You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Remove QuestPDF — its Community licence is pay-to-use above a revenue threshold #1230
MeshWeaver ships dual-licensed Apache-2.0 / MIT. QuestPDF (Directory.Packages.props, 2026.7.2) is dual-licensed: the Community tier is free only below a revenue threshold; above it a paid commercial licence is required. MarkdownExportExtensions.cs:60 accepts that Community licence programmatically at mesh-builder time, and MeshWeaver.Blazor pulls it transitively, so QuestPDF ships in every deployed portal image.
The user's decision (2026-08-11) is to dereference it — not to buy a licence and not to swap in another restrictively-licensed package. PDF rendering moves to the browser via the existing Pixel/HeadlessChromiumPdfRenderer.cs (Playwright, MIT).
Footprint (verified on main)
src/MeshWeaver.Markdown.Export/Pdf/PdfDocumentRenderer.cs — 368 lines, 100% of the QuestPDF rendering, the only file with using QuestPDF.
src/MeshWeaver.Markdown.Export/MeshWeaver.Markdown.Export.csproj:8 — the only PackageReference.
Tests using it: PdfHeaderLogoTests.cs, RendererOutputTests.cs.
ExportFidelity.cs, ExportFormat.cs, Branding/ExportTemplateResolver.cs mention it in comments only — no compile dependency.
Why it is not a one-line deletion
Fork point Templates/ExportPdf.csx:126: Pixel fidelity goes to Chromium (Deck only); ExportPdf.csx:193-196 warns and falls back to QuestPDF for every non-Deck node. Per PixelFaithfulExport.md:70 the Chromium path today has no cover page, no TOC, no running header/footer and no page-break rules — those exist only in PdfDocumentRenderer.cs. README.md:23 also states headless Chromium is deliberately not shipped in the portal image.
So the deletion must land with the document-export migration onto Chromium, otherwise it is a functional regression rather than a cleanup.
Done when
Markdown→PDF, cover page, TOC and running header/footer render through the browser path
PdfDocumentRenderer.cs, the licence line and the PackageReference are deleted
PdfHeaderLogoTests / RendererOutputTests assert the same behaviour against browser-rendered output (do not weaken them)
<PackageVersion Include="QuestPDF" …> removed from Directory.Packages.props
the questpdf entry is deleted from EXCEPTIONS in .github/scripts/check-licenses.py — the licence gate then enforces this permanently
Hard prerequisite: Chromium is not in the deployed image
Confirmed while auditing dependency licences (#1233): deploy/base-images/portal-ai/Dockerfile — the base of memex-portal-ai per main-cd.yml — does not include a browser, and that is a stated design choice rather than an oversight.
That changes this issue's shape:
The "let the browser render it" route cannot be the production PDF path until the base image gains Chromium. That is a deliberate deployment change with image-size, attack-surface and build-time consequences, and it deserves its own decision — it is not a side effect of a licence cleanup.
Removing QuestPDF before that lands would leave the portal with no PDF renderer at all. That would be strictly worse than the licence exposure it removes.
There is also no HTML→DOCX converter in the repo, so DOCX has no browser-based answer either — worth settling in the same decision.
#1234 fixed the real defect underneath this at its root: Ast/DocumentBuilder.cs built its own Markdig pipeline that omitted LayoutAreaMarkdownExtension, so @@(…) parsed as a paragraph and printed as raw source; the pixel path emitted the empty layout-area anchor, but its print document is file:// under default-src 'none' with --host-resolver-rules=MAP * ~NOTFOUND, so the browser could never fill it and printed blank. It also lifted the resolver/renderer/table-sizer/sanitizer out of Email/ into a format-neutral Html/.
This issue stays open and blocked on that chain. Meanwhile QuestPDF is carried as a dated, reasoned exception in EXCEPTIONS in .github/scripts/check-licenses.py (added by #1233), so the licence gate enforces everything else today while this stays visible instead of silently permanent. Closing this issue includes deleting that entry.
Activity
rbuergi commentedon Aug 11, 2026
Hard prerequisite: Chromium is not in the deployed image
Confirmed while auditing dependency licences (#1233):
deploy/base-images/portal-ai/Dockerfile— the base ofmemex-portal-aipermain-cd.yml— does not include a browser, and that is a stated design choice rather than an oversight.That changes this issue's shape:
Sequencing
#1234 fixed the real defect underneath this at its root:
Ast/DocumentBuilder.csbuilt its own Markdig pipeline that omittedLayoutAreaMarkdownExtension, so@@(…)parsed as a paragraph and printed as raw source; the pixel path emitted the empty layout-area anchor, but its print document isfile://underdefault-src 'none'with--host-resolver-rules=MAP * ~NOTFOUND, so the browser could never fill it and printed blank. It also lifted the resolver/renderer/table-sizer/sanitizer out ofEmail/into a format-neutralHtml/.This issue stays open and blocked on that chain. Meanwhile QuestPDF is carried as a dated, reasoned exception in
EXCEPTIONSin.github/scripts/check-licenses.py(added by #1233), so the licence gate enforces everything else today while this stays visible instead of silently permanent. Closing this issue includes deleting that entry.fix(ci): give the headless browser back its sandbox on the runner
docs(export): the portal-ai image ships the browser now
review: resolve the browser binary without walking the whole tree
fix(export): restore PDF contents page numbers by measuring the print