import { headers } from "next/headers"; import { notFound, redirect } from "next/navigation"; import { DocumentShell } from "@/components/editor/document-shell"; import type { PageFont, PageLayoutDensity, PageOptionsState, DocumentStats } from "@/types/page-options"; import { isConvexEnabled } from "@/lib/convex/enabled"; import { fetchDocumentMetaViaBridge } from "@/lib/documents/bridge-server"; import { getAuthedConvexClient } from "@/lib/convex/route"; import { buildDocumentBridgeContext, buildDocumentQueryEnvelope } from "@/lib/documents/bridge"; import { buildPageSubtreeProjection } from "@/lib/documents/page-subtree"; import { executeRustBridgeQueryTransport, resolveRustBridgeQueryPlan } from "@/lib/documents/rust-runtime"; interface DocumentPageProps { params: Promise<{ id: string }>; searchParams?: Promise>; } type DocumentMetaPayload = { id: string; workspace_id: string; title: string | null; updated_at: string | null; can_edit?: boolean | null; disable_download?: boolean | null; disable_copy?: boolean | null; wide_layout?: boolean | null; use_small_text?: boolean | null; show_heading_numbers?: boolean | null; show_toc?: boolean | null; show_structure?: boolean | null; protect_editing?: boolean | null; show_word_count?: boolean | null; collapse_backlinks?: boolean | null; page_font?: PageFont | null; layout_density?: PageLayoutDensity | null; hide_child_pages?: boolean | null; show_block_ref_count?: boolean | null; embed_default_block_id?: string | null; word_count?: number | null; character_count?: number | null; block_count?: number | null; todo_total?: number | null; todo_total_count?: number | null; todo_done?: number | null; todo_done_count?: number | null; }; type DocumentContentPayload = { content?: unknown; revision?: number | null; conflict_detection_key?: string | null; }; async function fetchDocumentContentOnServer(input: { documentId: string; workspaceId: string; }): Promise<{ content: unknown; revision: number | null; conflictDetectionKey: string | null; }> { try { const headerList = await headers(); const requestHeaders = new Headers(); [ "cookie", "authorization", "x-request-id", "x-trace-id", "x-session-id", "x-source-channel", "x-source-client", "user-agent", ].forEach((name) => { const value = headerList.get(name); if (value) { requestHeaders.set(name, value); } }); const request = new Request("http://mnote.local/documents/content", { method: "GET", headers: requestHeaders, }); const { client } = await getAuthedConvexClient(); const bridgeContext = await buildDocumentBridgeContext({ request, workspaceId: input.workspaceId, }); const envelope = buildDocumentQueryEnvelope({ name: "documents.content.get", payload: { documentId: input.documentId, workspaceId: input.workspaceId, }, }); const plan = await resolveRustBridgeQueryPlan({ context: bridgeContext, envelope, }); const result = await executeRustBridgeQueryTransport({ client, plan, }); return { content: result?.content ?? null, revision: typeof result?.revision === "number" && Number.isInteger(result.revision) ? result.revision : 0, conflictDetectionKey: typeof result?.conflict_detection_key === "string" && result.conflict_detection_key.trim() ? result.conflict_detection_key : `${input.documentId}:0`, }; } catch { return { content: null, revision: null, conflictDetectionKey: null, }; } } export default async function DocumentPage({ params, searchParams }: DocumentPageProps) { const { id } = await params; const resolvedSearch = (await searchParams) ?? {}; const openTableIdRaw = resolvedSearch?.openTableId; const openTableId = typeof openTableIdRaw === "string" ? openTableIdRaw : null; if (isConvexEnabled()) { const workspaceIdRaw = resolvedSearch?.workspaceId; const workspaceId = typeof workspaceIdRaw === "string" ? workspaceIdRaw : null; const result = await fetchDocumentMetaViaBridge({ documentId: id, workspaceId, }); const doc = result?.doc; if (!doc) { notFound(); } const readOnly = doc.can_edit === false; const disableDownload = Boolean(doc.disable_download); const disableCopy = Boolean(doc.disable_copy); const initialOptions: PageOptionsState = { wideLayout: doc.wide_layout ?? false, smallText: doc.use_small_text ?? false, showHeadingNumbers: doc.show_heading_numbers ?? true, showToc: doc.show_toc ?? false, showStructure: doc.show_structure ?? false, protectEditing: doc.protect_editing ?? false, showWordCount: doc.show_word_count ?? true, collapseBacklinks: doc.collapse_backlinks ?? false, pageFont: doc.page_font ?? "default", layoutDensity: doc.layout_density ?? "normal", hideChildPages: doc.hide_child_pages ?? false, showBlockRefCount: doc.show_block_ref_count ?? false, embedDefaultBlockId: doc.embed_default_block_id ?? null, }; const initialStats: DocumentStats = { wordCount: doc.word_count ?? 0, characterCount: doc.character_count ?? 0, blockCount: doc.block_count ?? 0, todoTotal: doc.todo_total ?? doc.todo_total_count ?? 0, todoDone: doc.todo_done ?? doc.todo_done_count ?? 0, }; const initialDocumentContent = await fetchDocumentContentOnServer({ documentId: doc.id, workspaceId: doc.workspace_id, }); const initialPageSubtree = buildPageSubtreeProjection({ documentId: doc.id, title: doc.title ?? "无标题", content: initialDocumentContent.content, }); return (
); } redirect("/auth"); }