deps: replace abandoned pdf-lib with the maintained @cantoo/pdf-lib fork (#5672) - #5811
Merged
Conversation
…ork (#5672) PortOS generates PDFs on four user-facing export paths — comic issue, trade volume, prose print interior, and the legacy archive bundle. All four sat on `pdf-lib@1.17.1`, which has had no npm publish since 2022-05-12: the pinned version and the latest published version are the same release. It is not deprecated and `npm audit` has always been clean, but it parses and serializes a hostile binary format, so the day a PDF advisory lands there is no upstream release to take. Doing the migration now makes it a planned change instead of an emergency one. `@cantoo/pdf-lib` is a same-license (MIT) fork of the same project, actively published, and it preserves the `PDFDocument` / `rgb` / `StandardFonts` public API this codebase uses. The swap is therefore four import lines, one manifest line, and the lockfile — no export changes its layout, fonts, page geometry, or output. Two boundary tests cover the one class of regression a same-API fork can introduce, which no import-level change would surface: the prose export now asserts its real bytes (a `Uint8Array` starting `%PDF-` and ending `%%EOF`, above an empty-document floor), and the comic export asserts that embedded image XObjects scale with the rendered page count, so a silently dropped `drawImage` payload fails instead of emitting blank pages. Note for future dependency sweeps, recorded in docs/DEPS.md: one of the four import sites lives in a file `file(1)` classifies as `data`, so plain `grep -r` skips it silently. A repo-wide dependency sweep must use `grep -ra`. Closes #5672 Claude-Session: https://claude.ai/code/session_01GMxEz43s3YCLaVZV9KmVwE
….md (#5672) The migration note claimed +6 packages net and said `@pdf-lib/standard-fonts`, `@pdf-lib/upng` and `tslib` left with the old package. Measured against the regenerated lockfile the real delta is 380 -> 385 (+5), and all three of those packages stay: the fork depends on the first two, and `tslib` is pulled by other dependencies. Claude-Session: https://claude.ai/code/session_01GMxEz43s3YCLaVZV9KmVwE
atomantic
force-pushed
the
claim/issue-5672
branch
from
September 2, 2026 05:39
e8082ae to
ded1c3d
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
PortOS generates PDFs on four user-facing export paths — comic issue, trade volume, prose print interior, and the legacy archive bundle. All four sat on
pdf-lib@1.17.1, which has had no npm publish since 2022-05-12: the pinned version and the latest published version are the same release. It is not deprecated andnpm audithas always been clean, but it parses and serializes a hostile binary format, so the day a PDF advisory lands there is no upstream release to take. Doing the migration now makes it a planned change instead of an emergency one.@cantoo/pdf-libis a same-license (MIT) fork of the same project, actively published, and it preserves thePDFDocument/rgb/StandardFontspublic API this codebase uses. The swap is four import lines, one manifest line, and the lockfile — no export changes its layout, fonts, page geometry, or output.What changed
server/package.json—pdf-lib@^1.17.1→@cantoo/pdf-lib@2.9.1(exact pin, matching the manifest's dominant convention).server/services/pipeline/volumePdf.js,comicPdf.js,proseExport.js, andserver/services/legacyExport.js. Prose comments naming the package were updated alongside them so a future dependency sweep greps clean.server/package-lock.jsonregenerated. Lockfile goes 380 → 385 packages (+5 net);npm auditreports 0 vulnerabilities.docs/DEPS.md— thepdf-librow becomes an@cantoo/pdf-libTier 2 KEEP row plus apdf-lib | — | REPLACEDrow, with a Detailed Findings subsection recording the API surface, the transitive delta, and a re-audit trigger (revisit if the fork itself goes >12 months without a publish, or on any CVE).Two things worth flagging
The issue scoped three import sites; there are four.
server/services/legacyExport.jscontains a byte sequence that makesfile(1)classify it asdata, so plaingrep -rsilently skips it. It surfaced only as anERR_MODULE_NOT_FOUNDin the suite. That caveat is now recorded indocs/DEPS.md— a repo-wide dependency sweep must usegrep -ra.Two boundary tests, not import-level ones. A same-API fork can only regress below the helper layer, so both new tests assert real output bytes:
proseExport.test.js—buildProsePdfreturns aUint8Arraystarting%PDF-and ending%%EOF, above an empty-document floor. Catches a fork whosesave()returns a different container type, which would break every streaming caller while passing every existing helper test.comicPdf.test.js— embedded image XObjects scale with the rendered page count (ratio, not a hard-coded count, since an RGBA PNG carries its alpha as a separate SMask object). Catches a silently droppeddrawImagepayload, which would otherwise emit a structurally valid PDF of blank pages.No unit tests were added for the layout helpers — they are deterministic and already exercised through these callers (AGENTS.md Test Strategy).
Test plan
cd server && npm test— 1834 files / 37283 tests pass.cd server && npm audit— 0 vulnerabilities.grep -ra "pdf-lib" server scripts docs --include='*.js' --include='*.md'returns only@cantoo/pdf-libmatches and the DEPS.md history prose.grep -c '"node_modules/pdf-lib"' server/package-lock.json→ 0.codexreview round — one finding (an inaccurate transitive-dependency count in the DEPS.md prose), verified against the regenerated lockfile and fixed in a follow-up commit.Closes #5672
https://claude.ai/code/session_01GMxEz43s3YCLaVZV9KmVwE