@@ -15,12 +15,12 @@ import {
1515} from '@react-pdf/renderer'
1616import type { JSONContent } from '@tiptap/core'
1717import sharp from 'sharp'
18- import { parseServerMarkdownToDoc } from '@/lib/collab-doc/server-markdown'
1918import {
2019 type EmbeddedFileRef ,
2120 extractEmbeddedFileRef ,
2221} from '@/lib/uploads/utils/embedded-image-ref'
2322import { splitFrontmatter } from '@/app/workspace/[workspaceId]/files/components/file-viewer/rich-markdown-editor/markdown-fidelity'
23+ import { parseMarkdownToDoc } from '@/app/workspace/[workspaceId]/files/components/file-viewer/rich-markdown-editor/markdown-parse'
2424
2525type PdfImage = { data : Buffer ; format : 'png' }
2626type ResolvedPdfImageRef = Exclude < EmbeddedFileRef , null >
@@ -41,6 +41,23 @@ interface PdfFont {
4141
4242const require = createRequire ( import . meta. url )
4343
44+ /**
45+ * Ensure a DOM exists for the TipTap Markdown parser used by this PDF-only server module. The
46+ * renderer is loaded lazily by the PDF export branch, so this setup never affects ordinary exports.
47+ * Re-check both globals on every call to avoid accepting the partial `document` exposed by Next.
48+ */
49+ function ensureDomForMarkdownPdf ( ) : void {
50+ if ( typeof window !== 'undefined' && typeof document !== 'undefined' ) return
51+ const { JSDOM } = require ( 'jsdom' ) as typeof import ( 'jsdom' )
52+ const { window : jsdomWindow } = new JSDOM ( '<!doctype html><html><body></body></html>' )
53+ // double-cast-allowed: assigning the jsdom shims onto the global needs an
54+ // index-signature view of `globalThis`, whose declared type has none.
55+ const globals = globalThis as unknown as Record < string , unknown >
56+ globals . window = jsdomWindow
57+ globals . document = jsdomWindow . document
58+ globals . navigator ??= jsdomWindow . navigator
59+ }
60+
4461function resolveBrandFont ( filename : string ) : string {
4562 const candidates = [
4663 join ( process . cwd ( ) , 'public' , 'brand' , 'fonts' , filename ) ,
@@ -678,7 +695,8 @@ export async function renderMarkdownPdf({
678695} : MarkdownPdfInput ) : Promise < Buffer > {
679696 const normalizedImages = await normalizeImages ( images )
680697 const { body } = splitFrontmatter ( markdown )
681- const document = parseServerMarkdownToDoc ( body )
698+ ensureDomForMarkdownPdf ( )
699+ const document = parseMarkdownToDoc ( body )
682700 assertDocumentWithinLimits ( document )
683701 return renderToBuffer (
684702 < MarkdownDocument document = { document } title = { title } images = { normalizedImages } />
0 commit comments