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
resolution is not part of the state reset identity. After this option changes, previously requested indexes remain in requested, so prefetch skips them and loadPage renders at the new resolution only through the promotion branch, which discards the returned image; pages therefore continues exposing the old-resolution URLs. Reset/re-render page state when the resolution changes.
This issue also appears on line 186 of the same file.
Destroy during render leaks the late-created object URL
src/utils/pdf.ts:320
destroy() can run while render() is awaiting canvas.toBlob(). In that case the new object URL is created after the revocation pass, and this block still resolves callers with it even though the handle is destroyed, leaking the URL and violating the destroy contract. Revoke a late URL and reject the request when destruction occurred before render completion.
This issue also appears on line 399 of the same file.
These render callbacks update the latest hook state unconditionally. When source or maxPages changes, cleanup destroys the old handle, but its pending promises can still resolve/reject afterward and write a revoked old URL or destruction error into the new document's state; the old catch can also mutate the new requested set. Scope requests to a document generation and ignore all then/catch/finally work once that generation is stale.
This issue also appears on line 222 of the same file.
Remove canceled requests from inFlight immediately
src/utils/pdf.ts:302
When the last caller aborts an active render, cancel() is invoked but this request remains in inFlight until the task rejection is processed. A new getPage call made immediately after abort() therefore attaches to the canceled request and is rejected too. Remove the canceled request from inFlight immediately, while ensuring its later settlement cannot delete a replacement request with the same key.
Derive page dimensions from a viewport
src/utils/pdf.ts:346
page.view is [xMin, yMin, xMax, yMax], so these values are coordinates rather than width and height. PDFs with a non-zero MediaBox/CropBox origin will be rendered at the wrong target resolution; derive the dimensions from a unit-scale viewport instead (which also accounts for rotation).
This issue also appears on line 364 of the same file.
Render iterator pages on demand
src/utils/pdf.ts:418
The first iterator step allocates promises and queues renders for the entire range. If a consumer reads one page and breaks, all remaining pages still render, defeating the on-demand behavior for large ranges (and later rejected promises can become unhandled). Request each page as the generator advances, or use a bounded prefetch window.
Test all HEIF MIME type mappings
src/utils/image.spec.ts:19
The implementation newly recognizes image/heic-sequence, but this parameterized test omits that MIME type, so a typo or regression in that specific mapping would go undetected. Include all four entries from HEIF_MIME_TYPES.
Resolution changes leave pages rendered at the old resolution
src/hooks/usePDFDocument.ts:179
When the resolution option changes, already requested indexes remain in requested and their existing URLs remain in pages, while only future pages use the new value. The result can therefore mix old- and new-resolution pages and the initial pages are never rerendered. Invalidate/reload page state when resolution changes, or explicitly make this option immutable for the hook instance.
This issue also appears on line 186 of the same file.
Pending renders resolve successfully after destruction
src/utils/pdf.ts:324
A render can finish just as destroy() runs. In that ordering this block skips caching but still resolves every pending caller with an image, contradicting the handle contract that pending calls reject after destruction (and potentially returning an already-revoked URL). Recheck destroyed after the awaited render and reject instead of settling successfully.
This issue also appears on line 364 of the same file.
Eager page renders can leak and trigger unhandled rejections
src/utils/pdf.ts:418
getPages eagerly creates a promise for every page but only awaits them one at a time. If one render rejects, the signal aborts, or the consumer stops iterating early, the remaining promises keep rendering and can reject without handlers, causing unhandledrejection events. Request each page inside the yield loop so iterator cancellation/error leaves no orphaned work.
PDFSource label shows an inconsistent function type
docs/docs/Utils/get-pdf-page-count.mdx:7
This label currently reads as though PDFSource itself has the displayed function type. Keep the API signature label consistent with the other utility pages.
Parameterized MIME test omits image/heic-sequence
src/utils/image.spec.ts:19
The production MIME set also adds image/heic-sequence, but the parameterized test omits that new branch. Include it so all newly supported MIME variants are covered.
Ignore render callbacks from stale document generations
src/hooks/usePDFDocument.ts:213
This only guards against a resolution change; callbacks from a render on the previous document can still update the new document when the source changes at the same resolution. Destroying the old handle rejects pending renders with a non-AbortError, so the old catch can leave a stale error on the new ready state, and its finally can remove a new render's loading marker. Tag renders with a document/source generation and ignore all then/catch/finally work once that generation is stale.
Copy PDF data before transferring it to the worker
src/utils/pdf.ts:165
pdf.js transfers DocumentInitParameters.data to its worker and takes ownership of the backing buffer. Passing these objects through directly therefore detaches caller-owned Uint8Array/ArrayBuffer values, so reusing the source (for example when this hook reopens after maxPages changes) can fail. Copy the bytes before passing them to pdf.js.
Remove cancelled requests from in-flight deduplication immediately
src/utils/pdf.ts:302
When the final caller aborts an actively rendering request, cancellation starts but the request remains in inFlight until the render task rejects. A new getPage for the same key during that interval attaches to the already-cancelled request and is rejected too. Remove the cancelled request from deduplication immediately, and make settle delete the map entry only when it still points to that request so it cannot remove a replacement request.
Calculate page dimensions from a unit-scale viewport
src/utils/pdf.ts:366
page.view contains coordinates [x1, y1, x2, y2], not [width, height]. PDFs whose page box does not start at (0, 0) therefore get the wrong scale and miss the requested pixel resolution. Derive the dimensions from a unit-scale viewport, which also accounts for page rotation and user units.
Correct breaking-change classification for zoom.max semantics
docs/docs/migration.md:16
This section documents that zoom.max has changed meaning for existing consumers, which is a behavioral breaking change, while the PR metadata explicitly marks the change as non-breaking. Either preserve the v1 semantics or classify/release this as a major change so consumers are not unexpectedly affected.
Validate prefetch and batch as non-negative integers
src/hooks/usePDFDocument.ts:136
prefetch and batch are unrestricted numbers, but the batching arithmetic requires non-negative/positive integers. For example, batch: 0 makes batchBounds return NaN bounds, while fractional values can enqueue fractional page indexes and produce render errors. Validate or normalize these public options before using them.
This issue also appears in the following locations of the same file:
line 153
line 184
Validate resolution before viewport calculation
src/utils/pdf.ts:211
Validate the public resolution value before computing a viewport. A value such as 0, a negative number, NaN, or Infinity currently reaches the scale calculation and creates a zero/invalid canvas instead of producing a defined API error.
Cancel in-progress PDF loading on source change or unmount
src/hooks/usePDFDocument.ts:227
handle is assigned only after openPDF resolves, so this cleanup cannot stop an in-progress URL download or parse. When the source changes or the component unmounts, the obsolete document keeps consuming network and shared-worker resources until opening finishes—the exact case that is costly for very large PDFs. Preserve and cancel pdf.js's loading task (for example via an AbortSignal accepted by openPDF) and trigger that cancellation here.
Abort stale renders when resolution changes
src/hooks/usePDFDocument.ts:255
Changing resolution only makes callbacks stale; these requests have no signal, so every old-resolution render remains queued. After a large loadRange, the obsolete queue is fully rendered before the new low-priority reloads, wasting CPU/memory and delaying updated pages. Associate an AbortController with each document/resolution generation, pass its signal here, and abort the previous generation before requeuing.
Non-integer range bounds are not normalized or rejected, so loadRange(0.5, 2) queues page indexes 0.5 and 1.5 and records render errors. Since this hook's invalid indexes are no-ops, reject non-integer bounds before entering the loop.
This issue also appears on line 324 of the same file.
Remove the unnecessary preposition in “accommodate for”
README.md:97
Remove the unnecessary preposition in “accommodate for.”
Invalidate render generation before destroying the handle
src/hooks/usePDFDocument.ts:246
The cleanup destroys the old handle without advancing requested.current. If the source is cleared or the component unmounts while a page is rendering, that render's rejection callback still sees stale() as false and can write a destruction error into the reset state (or update after unmount). Invalidate and abort the render generation before destroying the handle.
This issue also appears on line 349 of the same file.
Each page proxy is retained by pdf.js for the document lifetime, and normal display renders do not automatically release its operator-list/image resources. Since this queue already caches the encoded image, navigating through a large document otherwise retains both representations until destroy(), undermining the lazy-loading memory benefit. Call page.cleanup() in a finally path after rendering/encoding has finished (including cancellation/error paths).
Documented defaultZoom behavior is not implemented
docs/docs/customization.md:27
defaultZoom is never read by the viewer—the only runtime occurrences are its type/default declarations—so changing it does not set an initial zoom level. This newly documented behavior is therefore inaccurate; either initialize the fitted stage from options.zoom.defaultZoom (with coverage) or remove this claim.
Remove misleading comparison to unused defaultZoom
docs/docs/migration.md:16
The comparison to defaultZoom is misleading because defaultZoom is not consumed anywhere by the viewer at runtime; setting it currently has no effect. Either implement that option as a fitted-image-relative initial level or remove this comparison from the migration guidance.
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
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.
PR Details
Description
Make pages load lazily so that huge documents can be loaded
Screencast-quick.webm
Also fixes zoom to be dependent on image size
Related Issue
Motivation and Context
How Has This Been Tested
Types of changes
Checklist