77 lines
2.6 KiB
TypeScript
77 lines
2.6 KiB
TypeScript
import type { Json } from "@/types/supabase";
|
|||
|
|
import { buildDocumentSavePayload, type DocumentSavePayload } from "@/lib/documents/save-contract";
|
||
|
|
|
||
|
|
export type PageBodyPersistedMeta = {
|
||
|
|
revision: number | null;
|
||
|
|
conflictDetectionKey: string | null;
|
||
|
|
};
|
||
|
|
|
||
|
|
export type PageBodyPersistedState = PageBodyPersistedMeta & {
|
||
|
|
workspaceId: string | null;
|
||
|
|
};
|
||
|
|
|
||
|
|
export type ApplyPageBodyCommandInput = {
|
||
|
|
documentId: string;
|
||
|
|
workspaceId: string | null;
|
||
|
|
revision: number | null;
|
||
|
|
conflictDetectionKey: string | null;
|
||
|
|
blocks: Json;
|
||
|
|
applyEditorSnapshot?: (blocks: Json) => void;
|
||
|
|
onPersistedMetaChange?: (meta: PageBodyPersistedMeta) => void;
|
||
|
|
fetchImpl?: typeof fetch;
|
||
|
|
persistPageBody?: (payload: DocumentSavePayload) => Promise<PageBodyPersistedMeta>;
|
||
|
|
};
|
||
|
|
|
||
|
|
async function persistPageBodyViaRoute(
|
||
|
|
payload: DocumentSavePayload,
|
||
|
|
fetchImpl: typeof fetch,
|
||
|
|
): Promise<PageBodyPersistedMeta> {
|
||
|
|
const response = await fetchImpl("/api/documents/save", {
|
||
|
|
method: "POST",
|
||
|
|
headers: { "Content-Type": "application/json" },
|
||
|
|
body: JSON.stringify(payload),
|
||
|
|
});
|
||
|
|
const body = (await response.json().catch(() => null)) as
|
||
|
|
| {
|
||
|
|
ok?: boolean;
|
||
|
|
revision?: number | null;
|
||
|
|
conflictDetectionKey?: string | null;
|
||
|
|
error?: string;
|
||
|
|
}
|
||
|
|
| null;
|
||
|
|
|
||
|
|
if (!response.ok) {
|
||
|
|
const message = body && typeof body.error === "string" && body.error.trim() ? body.error.trim() : "页面正文保存失败";
|
||
|
|
throw new Error(message);
|
||
|
|
}
|
||
|
|
|
||
|
|
return {
|
||
|
|
revision:
|
||
|
|
typeof body?.revision === "number" && Number.isInteger(body.revision) ? body.revision : payload.revision,
|
||
|
|
conflictDetectionKey:
|
||
|
|
typeof body?.conflictDetectionKey === "string" && body.conflictDetectionKey.trim()
|
||
|
|
? body.conflictDetectionKey.trim()
|
||
|
|
: payload.conflictDetectionKey,
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
export async function applyPageBodyCommand(input: ApplyPageBodyCommandInput): Promise<PageBodyPersistedMeta> {
|
||
|
|
const payload = buildDocumentSavePayload({
|
||
|
|
documentId: input.documentId,
|
||
|
|
workspaceId: input.workspaceId,
|
||
|
|
revision: input.revision,
|
||
|
|
conflictDetectionKey: input.conflictDetectionKey,
|
||
|
|
content: input.blocks,
|
||
|
|
editorDocument: undefined,
|
||
|
|
tiptapDocument: undefined,
|
||
|
|
blockCount: Array.isArray(input.blocks) ? input.blocks.length : null,
|
||
|
|
snapshotCapturedAt: new Date().toISOString(),
|
||
|
|
});
|
||
|
|
const persistedMeta = input.persistPageBody
|
||
|
|
? await input.persistPageBody(payload)
|
||
|
|
: await persistPageBodyViaRoute(payload, input.fetchImpl ?? fetch);
|
||
|
|
input.applyEditorSnapshot?.(input.blocks);
|
||
|
|
input.onPersistedMetaChange?.(persistedMeta);
|
||
|
|
return persistedMeta;
|
||
|
|
}
|