Skip to content
File

Blob: src/worker/sites/project-page-json.ts

typescript44 lines
1import { getSchema, type JSONContent } from "@tiptap/core";
2import { yXmlFragmentToProseMirrorRootNode } from "@tiptap/y-tiptap";
3import * as Y from "yjs";
4 
5import { YJS_DOCUMENT_STORE } from "@/shared/constants";
6import {
7 collectEditorTextMetrics,
8 createHeadlessEditorExtensions,
9 type EditorTextMetrics,
10} from "@/shared/editor/schema";
11 
12export interface ProjectedPageJson {
13 content: JSONContent;
14 metrics: EditorTextMetrics;
15}
16 
17export async function projectPageJson(env: Pick<Env, "DocSync">, pageId: string): Promise<ProjectedPageJson | null> {
18 const stub = env.DocSync.getByName(pageId);
19 const snapshot = await stub.getSnapshotResponse(pageId);
20 if (snapshot.kind === "missing") return createEmptyPageJson();
21 
22 const bytes = new Uint8Array(await snapshot.response.arrayBuffer());
23 const ydoc = new Y.Doc();
24 try {
25 Y.applyUpdate(ydoc, bytes);
26 const fragment = ydoc.getXmlFragment(YJS_DOCUMENT_STORE);
27 const schema = getSchema(createHeadlessEditorExtensions());
28 const root = yXmlFragmentToProseMirrorRootNode(fragment, schema);
29 return {
30 content: root.toJSON() as JSONContent,
31 metrics: collectEditorTextMetrics(root),
32 };
33 } finally {
34 ydoc.destroy();
35 }
36}
37 
38function createEmptyPageJson(): ProjectedPageJson {
39 return {
40 content: { type: "doc", content: [] },
41 metrics: { words: 0, characters: 0 },
42 };
43}