fix(orders): count PDF pages with pdf-lib (reliable server-side parsing)#104
Merged
Conversation
Follow-up to #103. After switching page counting to pdfjs, valid PDFs were being rejected as invalid in production. Two root causes: 1. The pdfjs-dist *default* entry references browser-only globals (DOMMatrix) and throws 'ReferenceError: DOMMatrix is not defined' under Node. We already import the legacy build, but Next.js's standalone output-file tracing does not follow the dynamic subpath import, so the legacy build was missing from the deployed container. The import then threw and was swallowed as 'invalid PDF'. Fix: force the legacy build into the bundle via outputFileTracingIncludes. 2. countPdfPages swallowed *all* errors and returned 0, so a failure to load the parser (a server misconfiguration) was indistinguishable from a genuinely corrupt file. Fix: load the parser outside the try/catch and throw a distinct PdfParserUnavailableError so it surfaces as a 500 instead of telling the user their file is invalid; log genuine parse failures so real bad files can be told apart from parser regressions.
Replace the server-side pdfjs-based page counter with pdf-lib. pdfjs-dist is designed for the browser: its default build references DOM-only globals (DOMMatrix) and crashes under Node, and its legacy build was unreliable to trace into the Next.js standalone/container bundle — so valid PDFs were being rejected as invalid in production. pdf-lib is a dependency-free, pure-TypeScript PDF library that runs anywhere Node runs (no native addons, no DOM globals, no web worker, no bundler/file-tracing special-casing). It parses the document object graph and returns an authoritative page count via getPageCount(). - Accurate on real-world PDFs (annotations/incremental updates that made the original byte-scanner overcount 200 -> 467). - ignoreEncryption: true lets us still count pages of password/permission -protected PDFs instead of falsely rejecting them. - Invalid/corrupt input is caught and logged, returning 0 so callers reject it with a clear message. Also drops the now-unnecessary outputFileTracingIncludes workaround for the pdfjs legacy build. pdfjs-dist remains a dependency for the client-side PdfOrder preview only.
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.
Follow-up to #103. After that PR switched server-side page counting to pdfjs-dist, valid PDFs started being rejected as "Unable to read PDF / invalid PDF" in production.
Why pdfjs failed on the server
pdfjs-dist is built for the browser:
DOMMatrix) and throwsReferenceError: DOMMatrix is not definedunder Node.output: "standalone"container bundle (dynamic subpath import), so at runtime the import failed. The error was then swallowed and surfaced to users as "invalid PDF".Fix: use
pdf-libSwap the server-side counter to
pdf-lib— a dependency-free, pure-TypeScript PDF library that runs anywhere Node runs:getPageCount().ignoreEncryption: truelets us still count pages of password/permission-protected PDFs instead of falsely rejecting them.0so callers reject it with a clear message.Also removes the
outputFileTracingIncludespdfjs workaround (no longer needed).pdfjs-distremains a dependency for the client-sidePdfOrderpreview only.Changes
package.json/ lockfile — addpdf-lib.lib/pdf.ts— reimplementcountPdfPagesonpdf-lib.next.config.ts— drop the pdfjs legacy-build tracing workaround.Verification
pnpm typecheck✅,pnpm lint(biome) ✅{ r200: 200, r1: 1, rbad: 0 }— 200-page and 1-page docs count exactly; garbage input returns 0 (logged).Note: two commits on the branch — the first was the interim pdfjs standalone-tracing fix, the second replaces it with the pdf-lib approach. Can squash on merge.