2026-04-15 03:06:29 +08:00
|
|
|
import type { Json } from "@/types/supabase";
|
2026-04-21 06:26:35 +08:00
|
|
|
import {
|
|
|
|
|
editorBlockDocumentFromContent,
|
|
|
|
|
editorBlockDocumentFromTiptapDoc,
|
|
|
|
|
legacyBlocksFromEditorBlockDocument,
|
|
|
|
|
normalizeEditorBlockDocument,
|
|
|
|
|
type EditorBlockDocument,
|
|
|
|
|
type TiptapDoc,
|
|
|
|
|
} from "@/lib/documents/tiptap-content-converter";
|
2026-04-15 03:06:29 +08:00
|
|
|
|
|
|
|
|
export type DocumentSavePayload = {
|
|
|
|
|
documentId: string;
|
|
|
|
|
workspaceId: string | null;
|
|
|
|
|
revision: number | null;
|
2026-04-21 06:26:35 +08:00
|
|
|
editorDocument: EditorBlockDocument;
|
2026-04-15 03:06:29 +08:00
|
|
|
content: Json;
|
2026-04-21 06:26:35 +08:00
|
|
|
tiptapDocument: TiptapDoc | null;
|
2026-04-15 03:06:29 +08:00
|
|
|
conflictDetectionKey: string | null;
|
|
|
|
|
snapshotCapturedAt: string | null;
|
|
|
|
|
blockCount: number | null;
|
|
|
|
|
};
|
|
|
|
|
|
2026-04-21 06:26:35 +08:00
|
|
|
type BuildDocumentSavePayloadInput = {
|
2026-04-15 03:06:29 +08:00
|
|
|
documentId: string;
|
|
|
|
|
workspaceId?: string | null;
|
|
|
|
|
revision?: number | null;
|
2026-04-21 06:26:35 +08:00
|
|
|
editorDocument?: unknown;
|
|
|
|
|
content?: Json;
|
|
|
|
|
tiptapDocument?: unknown;
|
2026-04-15 03:06:29 +08:00
|
|
|
conflictDetectionKey?: string | null;
|
|
|
|
|
snapshotCapturedAt?: string | null;
|
|
|
|
|
blockCount?: number | null;
|
2026-04-21 06:26:35 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
function resolveEditorDocument(
|
|
|
|
|
input: BuildDocumentSavePayloadInput,
|
|
|
|
|
normalizedDocumentId: string,
|
|
|
|
|
): EditorBlockDocument {
|
|
|
|
|
if (input.editorDocument != null) {
|
|
|
|
|
return normalizeEditorBlockDocument(input.editorDocument, normalizedDocumentId);
|
|
|
|
|
}
|
|
|
|
|
if (typeof input.content !== "undefined") {
|
|
|
|
|
return normalizeEditorBlockDocument(
|
|
|
|
|
editorBlockDocumentFromContent(input.content),
|
|
|
|
|
normalizedDocumentId,
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
if (input.tiptapDocument != null) {
|
|
|
|
|
return normalizeEditorBlockDocument(
|
|
|
|
|
editorBlockDocumentFromTiptapDoc(input.tiptapDocument, normalizedDocumentId),
|
|
|
|
|
normalizedDocumentId,
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
return normalizeEditorBlockDocument(
|
|
|
|
|
{
|
|
|
|
|
documentId: normalizedDocumentId,
|
|
|
|
|
rootBlockIds: [],
|
|
|
|
|
blocks: [],
|
|
|
|
|
},
|
|
|
|
|
normalizedDocumentId,
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function buildDocumentSavePayload(
|
|
|
|
|
input: BuildDocumentSavePayloadInput,
|
|
|
|
|
): DocumentSavePayload {
|
|
|
|
|
const documentId = input.documentId.trim();
|
|
|
|
|
const editorDocument = resolveEditorDocument(input, documentId);
|
|
|
|
|
const shouldDeriveLegacyContent =
|
|
|
|
|
input.editorDocument != null ||
|
|
|
|
|
input.tiptapDocument != null ||
|
|
|
|
|
typeof input.content === "undefined";
|
|
|
|
|
const content: Json = shouldDeriveLegacyContent
|
|
|
|
|
? (legacyBlocksFromEditorBlockDocument(editorDocument) as Json)
|
|
|
|
|
: (input.content as Json);
|
2026-04-15 03:06:29 +08:00
|
|
|
const revision =
|
|
|
|
|
typeof input.revision === "number" && Number.isInteger(input.revision) && input.revision >= 0
|
|
|
|
|
? input.revision
|
|
|
|
|
: null;
|
|
|
|
|
const conflictDetectionKey =
|
|
|
|
|
typeof input.conflictDetectionKey === "string" && input.conflictDetectionKey.trim()
|
|
|
|
|
? input.conflictDetectionKey.trim()
|
|
|
|
|
: null;
|
|
|
|
|
const snapshotCapturedAt =
|
|
|
|
|
typeof input.snapshotCapturedAt === "string" && input.snapshotCapturedAt.trim()
|
|
|
|
|
? input.snapshotCapturedAt.trim()
|
|
|
|
|
: null;
|
|
|
|
|
const blockCount =
|
|
|
|
|
typeof input.blockCount === "number" && Number.isInteger(input.blockCount) && input.blockCount >= 0
|
|
|
|
|
? input.blockCount
|
|
|
|
|
: null;
|
2026-04-21 06:26:35 +08:00
|
|
|
const tiptapDocument =
|
|
|
|
|
input.tiptapDocument && typeof input.tiptapDocument === "object"
|
|
|
|
|
? (input.tiptapDocument as TiptapDoc)
|
|
|
|
|
: null;
|
2026-04-15 03:06:29 +08:00
|
|
|
|
|
|
|
|
return {
|
2026-04-21 06:26:35 +08:00
|
|
|
documentId,
|
2026-04-15 03:06:29 +08:00
|
|
|
workspaceId: input.workspaceId?.trim() || null,
|
|
|
|
|
revision,
|
2026-04-21 06:26:35 +08:00
|
|
|
editorDocument,
|
|
|
|
|
content,
|
|
|
|
|
tiptapDocument,
|
2026-04-15 03:06:29 +08:00
|
|
|
conflictDetectionKey,
|
|
|
|
|
snapshotCapturedAt,
|
|
|
|
|
blockCount,
|
|
|
|
|
};
|
|
|
|
|
}
|