Skip to content
File

Blob: src/worker/queues/page-projection.ts

typescript50 lines
1import { eq } from "drizzle-orm";
2 
3import { createSessionDb } from "@/worker/db/d1/client";
4import { pages } from "@/worker/db/d1/schema";
5import { createLogger } from "@/worker/lib/logger";
6import { writeSiteR2 } from "@/worker/sites/cache";
7import type { TasksQueueResult } from "./messages";
8 
9const log = createLogger("page-projection");
10 
11export async function handlePageProjection(pageId: string, env: Env): Promise<TasksQueueResult> {
12 const { db } = createSessionDb(env.DB, "first-primary");
13 const page = await db
14 .select({ workspace_id: pages.workspace_id, kind: pages.kind, updated_at: pages.updated_at })
15 .from(pages)
16 .where(eq(pages.id, pageId))
17 .get();
18 
19 if (!page) {
20 log.info("sites_projection_retry", { pageId, reason: "page_not_yet_visible" });
21 return { kind: "retry", delaySeconds: 2 };
22 }
23 if (page.kind !== "doc") {
24 log.info("sites_projection_skipped", { pageId, workspaceId: page.workspace_id, kind: page.kind });
25 return { kind: "ok" };
26 }
27 
28 // ADR: keep Tiptap/y-tiptap projection out of Worker startup.
29 const { projectPageJson } = await import("@/worker/sites/project-page-json");
30 const projected = await projectPageJson(env, pageId);
31 if (!projected) {
32 log.info("sites_projection_skipped", { pageId, workspaceId: page.workspace_id, reason: "snapshot_missing" });
33 return { kind: "ok" };
34 }
35 
36 await writeSiteR2(env, page.workspace_id, pageId, {
37 content: projected.content,
38 metrics: projected.metrics,
39 updatedAt: page.updated_at,
40 });
41 log.info("sites_projected", {
42 pageId,
43 workspaceId: page.workspace_id,
44 updatedAt: page.updated_at,
45 words: projected.metrics.words,
46 characters: projected.metrics.characters,
47 });
48 return { kind: "ok" };
49}