fix(orders): count PDF pages by parsing the document, not scanning bytes#103
Merged
Conversation
The server-side page counter scanned raw PDF bytes for '/Type /Page' markers to price orders. That badly overcounts real-world PDFs: the marker also appears in annotations/form fields, object streams, orphaned objects left by incremental updates, and inside content streams. A recent 200-page upload was counted as 467. Replace the naive scan with a shared lib/pdf.ts helper that parses the document with pdfjs-dist (already a dependency, already used client-side by PdfOrder and configured for the Worker runtime via the canvas shim) and reads the authoritative numPages. Both /api/shop/orders and /api/admin/orders now use the shared helper; invalid/corrupt files still return 0 so callers reject them.
choden-dev
added a commit
that referenced
this pull request
Jul 20, 2026
…ng) (#104) * fix(orders): make server-side PDF parsing work in the standalone build 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. * fix(orders): count PDF pages with pdf-lib instead of pdfjs 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.
Problem
Server-side PDF page counting was inaccurate. A recent 200-page upload was counted as 467, inflating the order price (pricing is derived from the server-side page count, which never trusts the client).
Root cause
countPdfPagesscanned the raw PDF bytes for/Type /Pagemarkers. This overcounts real-world PDFs because that marker also appears in:The identical naive function was also duplicated in both
app/api/shop/orders/route.tsandapp/api/admin/orders/route.ts.Fix
lib/pdf.tsthat parses the document withpdfjs-distand returns the authoritativenumPages.pdfjs-distis already a dependency, already used client-side byPdfOrder, and already configured for the Cloudflare Worker runtime via thecanvasshim. We only parse structure here (no rendering).legacybuild and disables worker/eval/font-face for reliable server-side parsing.0on corrupt/encrypted/non-PDF input so callers keep rejecting invalid files.Verification
pnpm typecheck✅ andpnpm lint(biome) ✅0.