From ba31be1f912f98e0e85049f16fe8a015eb5278c6 Mon Sep 17 00:00:00 2001 From: Olivier Chafik Date: Mon, 27 Apr 2026 15:32:53 +0100 Subject: [PATCH] perf(pdf-server): lazy form extraction via range transport + incremental viewer scans (#639) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * perf(pdf-server): lazy form extraction via range transport + incremental viewer scans Server: display_pdf now opens the document via PDFDataRangeTransport (disableAutoFetch) and only runs the per-page form/annotation walk when getFieldObjects() is non-empty, so form-free PDFs are probed with ~10-25% of bytes instead of a full download. The unused viewFieldInfo Map is removed. Viewer: getDocument sets disableAutoFetch/disableStream; baseline annotation scan and field-name mapping run lazily per rendered page instead of walking every page after load, so first paint no longer schedules a full-file pull. E2E: new range-counting HTTPS fixture (W-9 for forms, generated text+image PDF for no-forms) with stallAfterBytes control, and four regression tests asserting form fields are returned, <30% served on no-forms display_pdf, first page renders while later ranges are stalled, and overlap stays bounded. * fix(pdf-server): handle separated field/widget trees in extractFormSchema pdfjs getFieldObjects() returns the full field-tree array. For PDFs with a separated structure (pdf-lib, some authoring tools) the typed widget sits at fields[1+] behind a typeless container at fields[0]; the previous code only inspected fields[0] and skipped them all. Pick the first entry with a non-empty type instead. Makes the e2e forms.pdf fixture fully generated (no checked-in third-party asset on the hot path); fw9.pdf stays as a unit-test fixture for the hierarchical/XFA case. * fix(pdf-server): address range-transport hangs and lazy-scan tombstone loss PdfCacheRangeTransport: - abort() is a no-op stub on PDFDataRangeTransport (it's the hook pdfjs calls *on* the transport, not an upstream error channel). Expose a .failed promise that rejects on the first fetch error and race every pdfjs await against it in display_pdf, so transient network errors surface into the existing catch instead of hanging the tool call. - pdfjs coalesces adjacent missing chunks into one unbounded requestDataRange; readPdfRange clamps each call to MAX_CHUNK_BYTES. Loop and deliver in slices so every requested chunk is marked loaded. Viewer (mcp-app.ts): - The lazy per-page baseline scan left pdfBaselineAnnotations incomplete, so persistAnnotations and getAnnotatedPdfBytes silently dropped restoredRemovedIds tombstones for unvisited pages. Union those ids into the computed diff and removedRefs. Test fixture: release stalled handlers before resetStats/close so a failing stalled test doesn't hang afterAll; fail fast if started with NODE_ENV=production. NODE_TLS_REJECT_UNAUTHORIZED scope documented (full per-process scoping needs a validateUrl localhost allow, tracked separately). * test(pdf-server): bridge coverage gaps and switch fixture to gated loopback HTTP PdfCacheRangeTransport.deliver(): pdf.js's reader is keyed by the original begin and removed after one delivery, so accumulate slices and call onDataRange once with the full buffer (the previous multi-call approach threw inside pdfjs). Covered by a new integration test that drives getDocument()/getPage(1) on a >1MB PDF through a clamping in-memory readPdfRange. validateUrl: allow http://127.0.0.1|localhost|[::1] only when PDF_SERVER_ALLOW_LOOPBACK_HTTP is set, so a remote deploy can't be made to probe its own ports. Covered by env-on/off unit tests. Fixture switched to plain HTTP (no openssl, no NODE_TLS_REJECT_UNAUTHORIZED). Adds /error.pdf (500s after 50KB) and two e2e tests: page 2 renders after stall release (>512KB object path), and display_pdf returns gracefully on mid-load 500. Existing <30% test now samples stats before the iframe loads. New unit tests: display_pdf returns (not hangs) on mid-load fetch failure via in-memory MCP client; computeDiff/serializeDiff contract tests pinning the restoredRemovedIds tombstone-preservation behaviour. * test(pdf-server): e2e for restoredRemovedIds tombstone preservation through viewer Adds /with-native-annot.pdf fixture (2 pages, native /Text annot on page 2) and a Playwright test that drives delete on page 2 → iframe reload → interact add_annotations on page 1 (persist with page 2 unscanned) → assert localStorage diff still contains the removed id → page 2 still shows it gone. Covers the mcp-app.ts glue the unit tests can't reach. * refactor(pdf-server): simplify per round-2 review and fix false-pass test server.ts: extract probeFormFields() so display_pdf calls one helper instead of inlining 40 lines of transport/orFail plumbing; make extractFormSchema's fieldObjects param required (the optional branch only existed for a test helper). server.test.ts: the >1MB integration test now forces the image XObject fetch via getOperatorList() and asserts max requestDataRange span > MAX_CHUNK_BYTES, so it can't go vacuous. Dedupe makeRandomJpeg by importing from the fixture. mcp-app.ts: restore per-annotation try/catch isolation in the lazy baseline scan (a throw was skipping AnnotationLayer.render); only carry forward restoredRemovedIds while the baseline scan is incomplete so a stale id can't pin dirty=true once every page is scanned. tests: bump fixture JPEG to 1.1MB; consolidate 7 e2e tests to 4 (merge overlap into the byte-budget test, merge stall+page-2, drop the error-e2e duplicate of the unit integration test); delete run-fixture.mjs; drop /error.pdf and ERROR_AFTER_BYTES; rename tombstone test's describe and clarify page-2 covers the viewer transport. * fix(pdf-server): preserve partial probeFormFields results when extractFormFieldInfo throws * test(pdf-server): fix tombstone e2e — deleted native annotations become a cleared card, not removed from DOM * test(pdf-server): mark tombstone e2e as fixme — needs basic-host iframe-reload replay support * test(pdf-server): link tombstone fixme to tracking issue #642 --- examples/pdf-server/server.test.ts | 266 +++++++++++++++++ examples/pdf-server/server.ts | 192 +++++++++---- examples/pdf-server/src/mcp-app.ts | 171 +++++++---- .../pdf-server/src/pdf-annotations.test.ts | 86 ++++++ playwright.config.ts | 4 + tests/e2e/pdf-incremental-load.spec.ts | 271 ++++++++++++++++++ tests/helpers/assets/fw9.pdf | Bin 0 -> 140815 bytes tests/helpers/range-counting-server.ts | 249 ++++++++++++++++ 8 files changed, 1133 insertions(+), 106 deletions(-) create mode 100644 tests/e2e/pdf-incremental-load.spec.ts create mode 100644 tests/helpers/assets/fw9.pdf create mode 100644 tests/helpers/range-counting-server.ts diff --git a/examples/pdf-server/server.test.ts b/examples/pdf-server/server.test.ts index f63ae67..8a0790a 100644 --- a/examples/pdf-server/server.test.ts +++ b/examples/pdf-server/server.test.ts @@ -4,9 +4,15 @@ import os from "node:os"; import path from "node:path"; import { Client } from "@modelcontextprotocol/sdk/client/index.js"; import { InMemoryTransport } from "@modelcontextprotocol/sdk/inMemory.js"; +import { getDocument } from "pdfjs-dist/legacy/build/pdf.mjs"; +import { PDFDocument } from "pdf-lib"; +import { makeRandomJpeg } from "../../tests/helpers/range-counting-server"; import { createPdfCache, createServer, + extractFormSchema, + PdfCacheRangeTransport, + MAX_CHUNK_BYTES, validateUrl, isAncestorDir, allowedLocalFiles, @@ -289,6 +295,266 @@ describe("PDF Cache with Timeouts", () => { // through manual testing or E2E tests. }); +describe("PdfCacheRangeTransport", () => { + it("accumulates ranges larger than MAX_CHUNK_BYTES into one onDataRange call", async () => { + const big = MAX_CHUNK_BYTES * 2 + 100; + const reads: Array<[number, number]> = []; + const t = new PdfCacheRangeTransport("u", big, async (_u, off, n) => { + reads.push([off, n]); + return { + data: new Uint8Array(Math.min(n, MAX_CHUNK_BYTES)), + totalBytes: big, + }; + }); + const delivered: Array<[number, number]> = []; + t.addRangeListener((begin: number, chunk: Uint8Array) => + delivered.push([begin, chunk.length]), + ); + t.requestDataRange(0, big); + await new Promise((r) => setTimeout(r, 10)); + // pdf.js's reader is keyed by the original begin and removed after one + // delivery, so deliver() must call onDataRange exactly once with the + // accumulated buffer — multiple calls would throw inside pdfjs. + expect(delivered).toEqual([[0, big]]); + expect(reads).toEqual([ + [0, MAX_CHUNK_BYTES], + [MAX_CHUNK_BYTES, MAX_CHUNK_BYTES], + [MAX_CHUNK_BYTES * 2, 100], + ]); + }); + + it("rejects .failed when a range fetch errors instead of hanging", async () => { + const t = new PdfCacheRangeTransport("u", 1000, async () => { + throw new Error("network down"); + }); + t.requestDataRange(0, 100); + await expect( + Promise.race([ + t.failed, + new Promise((r) => setTimeout(() => r("timeout"), 200)), + ]), + ).rejects.toThrow("network down"); + }); + + it("rejects .failed on zero-length response (would otherwise spin)", async () => { + const t = new PdfCacheRangeTransport("u", 1000, async () => ({ + data: new Uint8Array(0), + totalBytes: 1000, + })); + t.requestDataRange(0, 100); + await expect(t.failed).rejects.toThrow(/empty range/); + }); + + it("getDocument resolves on a >1MB PDF when readPdfRange clamps to MAX_CHUNK_BYTES", async () => { + // pdfjs coalesces adjacent missing chunks into one requestDataRange that + // can exceed MAX_CHUNK_BYTES. deliver() must accumulate clamped reads and + // hand pdfjs a single onDataRange(begin, fullBuffer). This test fails if + // deliver() either truncates or calls onDataRange more than once per + // requestDataRange (pdf.mjs _onReceiveData matches by exact begin). + const d = await PDFDocument.create(); + const img = await d.embedJpg(makeRandomJpeg(1_100_000)); + const page = d.addPage([612, 792]); + page.drawImage(img, { x: 36, y: 36, width: 540, height: 720 }); + const bytes = await d.save(); + expect(bytes.length).toBeGreaterThan(2 * MAX_CHUNK_BYTES); + + const readClamped: PdfCache["readPdfRange"] = async (_u, off, n) => { + const len = Math.min(n, MAX_CHUNK_BYTES, bytes.length - off); + return { data: bytes.slice(off, off + len), totalBytes: bytes.length }; + }; + // Record the spans pdfjs actually requests so the test fails fast if it + // never asks for >MAX_CHUNK_BYTES (i.e. can't go vacuously green). + const spans: number[] = []; + class RecordingTransport extends PdfCacheRangeTransport { + override requestDataRange(begin: number, end: number): void { + spans.push(end - begin); + super.requestDataRange(begin, end); + } + } + const transport = new RecordingTransport( + "mem://big", + bytes.length, + readClamped, + ); + + const orHang = (p: Promise, what: string): Promise => + Promise.race([ + p, + transport.failed, + new Promise((_, rej) => + setTimeout(() => rej(new Error(`${what} hung`)), 5000), + ), + ]); + + const doc = await orHang( + getDocument({ + range: transport, + length: bytes.length, + disableAutoFetch: true, + disableStream: true, + rangeChunkSize: 64 * 1024, + }).promise, + "getDocument", + ); + const p1 = await orHang(doc.getPage(1), "getPage"); + // getPage() alone doesn't decode the image XObject; getOperatorList() does, + // which is what triggers the >512KB coalesced range request. + await orHang(p1.getOperatorList(), "getOperatorList"); + expect(Math.max(...spans)).toBeGreaterThan(MAX_CHUNK_BYTES); + doc.destroy(); + }); +}); + +describe("display_pdf transport-error handling", () => { + it("returns (does not hang) when range fetches fail mid-load", async () => { + // First fetch = the 1-byte size probe → 206 with Content-Range so + // display_pdf gets totalBytes. Every subsequent fetch (made by + // PdfCacheRangeTransport via readPdfRange) rejects, which must surface + // through transport.failed → orFail() → outer catch, not hang. + let calls = 0; + const mockFetch = spyOn(globalThis, "fetch").mockImplementation( + async () => { + if (calls++ === 0) { + return new Response(new Uint8Array(1), { + status: 206, + headers: { "Content-Range": "bytes 0-0/50000" }, + }); + } + throw new Error("network down"); + }, + ); + + const server = createServer(); + const client = new Client({ name: "t", version: "1" }); + const [ct, st] = InMemoryTransport.createLinkedPair(); + await Promise.all([server.connect(st), client.connect(ct)]); + + try { + const result = await Promise.race([ + client.callTool({ + name: "display_pdf", + arguments: { url: "https://arxiv.org/pdf/err-test" }, + }), + new Promise((_, rej) => + setTimeout( + () => rej(new Error("display_pdf hung on transport error")), + 3000, + ), + ), + ]); + expect(result.isError).toBeFalsy(); + const sc = result.structuredContent as { formFields?: unknown }; + expect(sc.formFields).toBeUndefined(); + expect(calls).toBeGreaterThan(1); + } finally { + mockFetch.mockRestore(); + await client.close(); + await server.close(); + } + }); +}); + +describe("extractFormSchema field-tree handling", () => { + async function schemaFor(bytes: Uint8Array) { + const doc = await getDocument({ data: bytes }).promise; + try { + const fo = (await doc.getFieldObjects()) as Parameters< + typeof extractFormSchema + >[1]; + return await extractFormSchema(doc, fo); + } finally { + doc.destroy(); + } + } + + it("handles pdf-lib separated field/widget structure", async () => { + const d = await PDFDocument.create(); + const form = d.getForm(); + d.addPage([612, 792]); + form + .createTextField("alpha") + .addToPage(d.getPage(0), { x: 50, y: 700, width: 200, height: 20 }); + form + .createCheckBox("agree") + .addToPage(d.getPage(0), { x: 50, y: 660, width: 20, height: 20 }); + form + .createDropdown("choice") + .addToPage(d.getPage(0), { x: 50, y: 620, width: 100, height: 20 }); + + const schema = await schemaFor(await d.save()); + expect(schema).not.toBeNull(); + expect(schema!.properties.alpha).toEqual({ + type: "string", + title: "alpha", + }); + expect(schema!.properties.agree).toEqual({ + type: "boolean", + title: "agree", + }); + expect(schema!.properties.choice.type).toBe("string"); + }); + + it("handles fields with multiple widgets across pages", async () => { + const d = await PDFDocument.create(); + const form = d.getForm(); + d.addPage([612, 792]); + d.addPage([612, 792]); + const tf = form.createTextField("shared"); + tf.addToPage(d.getPage(0), { x: 50, y: 700, width: 200, height: 20 }); + tf.addToPage(d.getPage(1), { x: 50, y: 700, width: 200, height: 20 }); + + const schema = await schemaFor(await d.save()); + expect(schema?.properties.shared).toEqual({ + type: "string", + title: "shared", + }); + }); + + it("skips container nodes and finds leaf fields (W-9 style)", async () => { + const bytes = fs.readFileSync( + path.join(__dirname, "../../tests/helpers/assets/fw9.pdf"), + ); + const doc = await getDocument({ data: new Uint8Array(bytes) }).promise; + try { + const fo = (await doc.getFieldObjects()) as Parameters< + typeof extractFormSchema + >[1]; + // Container nodes (no leaf type) should not crash extraction + expect(fo!["topmostSubform[0]"]).toBeDefined(); + // Schema is null for W-9 (mechanical names), but extraction must not throw + const schema = await extractFormSchema(doc, fo); + expect(schema).toBeNull(); + } finally { + doc.destroy(); + } + }); + + it("returns null when no AcroForm present", async () => { + const d = await PDFDocument.create(); + d.addPage([612, 792]); + const schema = await schemaFor(await d.save()); + expect(schema).toBeNull(); + }); +}); + +describe("validateUrl loopback HTTP allow (PDF_SERVER_ALLOW_LOOPBACK_HTTP)", () => { + it("rejects http://127.0.0.1 by default", () => { + expect(validateUrl("http://127.0.0.1:9999/x.pdf").valid).toBe(false); + }); + + it("accepts http://127.0.0.1 only when the env gate is set, and never non-loopback http", () => { + const prev = process.env.PDF_SERVER_ALLOW_LOOPBACK_HTTP; + process.env.PDF_SERVER_ALLOW_LOOPBACK_HTTP = "1"; + try { + expect(validateUrl("http://127.0.0.1:9999/x.pdf").valid).toBe(true); + expect(validateUrl("http://169.254.169.254/").valid).toBe(false); + } finally { + if (prev === undefined) delete process.env.PDF_SERVER_ALLOW_LOOPBACK_HTTP; + else process.env.PDF_SERVER_ALLOW_LOOPBACK_HTTP = prev; + } + }); +}); + describe("validateUrl with MCP roots (allowedLocalDirs)", () => { const savedFiles = new Set(allowedLocalFiles); const savedDirs = new Set(allowedLocalDirs); diff --git a/examples/pdf-server/server.ts b/examples/pdf-server/server.ts index 062b263..93dedfd 100644 --- a/examples/pdf-server/server.ts +++ b/examples/pdf-server/server.ts @@ -31,6 +31,7 @@ import { import "./pdfjs-polyfill.js"; import { getDocument, + PDFDataRangeTransport, VerbosityLevel, version as PDFJS_VERSION, } from "pdfjs-dist/legacy/build/pdf.mjs"; @@ -368,9 +369,6 @@ export const viewSourcePaths = new Map(); /** Valid form field names per viewer UUID (populated during display_pdf) */ const viewFieldNames = new Map>(); -/** Detailed form field info per viewer UUID (populated during display_pdf) */ -const viewFieldInfo = new Map(); - /** * Active fs.watch per view. Only created for local files when interact is * enabled (stdio). Watcher is re-established on `rename` events to survive @@ -387,7 +385,7 @@ const viewFileWatches = new Map(); /** * Per-view heartbeat. THIS is what the sweep iterates — not commandQueues. * - * Why not commandQueues: display_pdf populates viewFieldNames/viewFieldInfo/ + * Why not commandQueues: display_pdf populates viewFieldNames/ * viewFileWatches but never touches commandQueues (only enqueueCommand does, * and it's triply gated). And dequeueCommands deletes the entry on every poll, * so even when it exists the sweep's TTL window is ~200ms wide. Net effect: @@ -409,7 +407,6 @@ function pruneStaleQueues(): void { viewLastActivity.delete(uuid); commandQueues.delete(uuid); viewFieldNames.delete(uuid); - viewFieldInfo.delete(uuid); viewsPolled.delete(uuid); viewSourcePaths.delete(uuid); stopFileWatch(uuid); @@ -644,10 +641,19 @@ export function validateUrl(url: string): { // Remote URL - require HTTPS try { const parsed = new URL(url); - if (parsed.protocol !== "https:") { - return { valid: false, error: `Only HTTPS URLs are allowed: ${url}` }; + if (parsed.protocol === "https:") return { valid: true }; + // Loopback HTTP is opt-in (test fixtures, local dev). Off by default so a + // remotely-deployed server can't be made to probe its own internal ports. + if ( + process.env.PDF_SERVER_ALLOW_LOOPBACK_HTTP && + parsed.protocol === "http:" && + (parsed.hostname === "127.0.0.1" || + parsed.hostname === "localhost" || + parsed.hostname === "[::1]") + ) { + return { valid: true }; } - return { valid: true }; + return { valid: false, error: `Only HTTPS URLs are allowed: ${url}` }; } catch { return { valid: false, error: `Invalid URL: ${url}` }; } @@ -882,6 +888,61 @@ export function createPdfCache( }; } +/** + * pdf.js range transport backed by {@link PdfCache.readPdfRange}. Lets + * getDocument() fetch only the byte ranges it needs (xref, /AcroForm dict) + * instead of the whole file. With disableAutoFetch, a PDF without form + * fields is opened with ~5% of bytes fetched. + * + * pdf.js has no upstream error channel on PDFDataRangeTransport (its + * `abort()` is a no-op stub it calls *on* us, not the other way). Callers + * must `Promise.race` their pdf.js awaits against {@link failed}, which + * rejects on the first fetch error. + */ +export class PdfCacheRangeTransport extends PDFDataRangeTransport { + /** Rejects on the first range-fetch error; never resolves. */ + readonly failed: Promise; + private fail!: (e: unknown) => void; + + constructor( + private url: string, + length: number, + private readPdfRange: PdfCache["readPdfRange"], + ) { + super(length, null); + this.failed = new Promise((_, reject) => { + this.fail = reject; + }); + // Don't crash the process if no one is racing yet. + this.failed.catch(() => {}); + } + + override requestDataRange(begin: number, end: number): void { + void this.deliver(begin, end).catch((e) => this.fail(e)); + } + + /** + * pdf.js coalesces adjacent missing chunks into one unbounded request, but + * readPdfRange clamps each call to MAX_CHUNK_BYTES. Its reader is keyed by + * the original `begin` and removed after one delivery, so we must accumulate + * slices and call onDataRange exactly once with the full buffer. + */ + private async deliver(begin: number, end: number): Promise { + const buf = new Uint8Array(end - begin); + let off = 0; + while (off < buf.length) { + const want = Math.min(buf.length - off, MAX_CHUNK_BYTES); + const { data } = await this.readPdfRange(this.url, begin + off, want); + if (data.length === 0) { + throw new Error(`empty range at ${begin + off} for ${this.url}`); + } + buf.set(data.subarray(0, Math.min(data.length, buf.length - off)), off); + off += data.length; + } + this.onDataRange(begin, buf); + } +} + // ============================================================================= // MCP Roots // ============================================================================= @@ -957,6 +1018,60 @@ interface FormFieldInfo { options?: string[]; } +/** + * Open `url` via {@link PdfCacheRangeTransport} and return form metadata. + * Uses `disableAutoFetch` so PDFs without an AcroForm are probed with only + * the trailer/xref/catalog (~5-25% of bytes); PDFs with forms still walk + * every page via {@link extractFormFieldInfo} but those are typically small. + * All errors (including range-fetch failures surfaced via + * {@link PdfCacheRangeTransport.failed}) resolve to empty results. + */ +async function probeFormFields( + url: string, + totalBytes: number, + readPdfRange: PdfCache["readPdfRange"], +): Promise<{ + formSchema: Awaited>; + fieldInfo: FormFieldInfo[]; +}> { + // Assigned sequentially below so a throw in extractFormFieldInfo (no per-page + // guard, unlike extractFormSchema) doesn't discard an already-computed schema. + let formSchema: Awaited> = null; + let fieldInfo: FormFieldInfo[] = []; + try { + const transport = new PdfCacheRangeTransport(url, totalBytes, readPdfRange); + const orFail = (p: Promise): Promise => + Promise.race([p, transport.failed]); + const pdfDoc = await orFail( + getDocument({ + range: transport, + length: totalBytes, + disableAutoFetch: true, + disableStream: true, + rangeChunkSize: 64 * 1024, + standardFontDataUrl: STANDARD_FONT_DATA_URL, + StandardFontDataFactory: FetchStandardFontDataFactory, + verbosity: VerbosityLevel.ERRORS, + }).promise, + ); + try { + const fieldObjects = (await orFail(pdfDoc.getFieldObjects())) as Record< + string, + PdfJsFieldObject[] + > | null; + if (fieldObjects && Object.keys(fieldObjects).length > 0) { + formSchema = await orFail(extractFormSchema(pdfDoc, fieldObjects)); + fieldInfo = await orFail(extractFormFieldInfo(pdfDoc)); + } + } finally { + pdfDoc.destroy(); + } + } catch { + // Non-fatal — return whatever was assigned before the throw. + } + return { formSchema, fieldInfo }; +} + /** * Extract detailed form field info (name, type, page, bounding box, label) * from a PDF. Bounding boxes are converted to model coordinates (top-left origin). @@ -1020,27 +1135,25 @@ async function extractFormFieldInfo( return fields; } -async function extractFormSchema(pdfDoc: PDFDocumentProxy): Promise<{ +export async function extractFormSchema( + pdfDoc: PDFDocumentProxy, + fieldObjects: Record | null, +): Promise<{ type: "object"; properties: Record; required?: string[]; } | null> { - let fieldObjects: Record | null; - try { - fieldObjects = (await pdfDoc.getFieldObjects()) as Record< - string, - PdfJsFieldObject[] - > | null; - } catch { - return null; - } if (!fieldObjects || Object.keys(fieldObjects).length === 0) { return null; } const properties: Record = {}; for (const [name, fields] of Object.entries(fieldObjects)) { - const field = fields[0]; // first widget determines the type + // pdfjs returns the full field-tree array: for separated structures + // (pdf-lib) the typed widget is at [1+] behind a container at [0]; for + // merged/leaf entries (W-9, most authoring tools) it's at [0]. Pick the + // first entry that actually has a field type. + const field = fields.find((f) => f.type) ?? fields[0]; if (!field.editable) continue; switch (field.type) { @@ -1434,7 +1547,7 @@ Set \`elicit_form_inputs\` to true to prompt the user to fill form fields before const { totalBytes } = await readPdfRange(normalized, 0, 1); const uuid = randomUUID(); // Start the heartbeat now so the sweep can clean up viewFieldNames/ - // viewFieldInfo/viewFileWatches even if no interact calls ever happen. + // viewFileWatches even if no interact calls ever happen. if (!disableInteract) touchView(uuid); // Check writability (governs save button; see isWritablePath doc). @@ -1462,38 +1575,19 @@ Set \`elicit_form_inputs\` to true to prompt the user to fill form fields before } } - // Extract form field schema + detailed field info from a single - // download/parse pass. - let formSchema: Awaited> = null; - let fieldInfo: FormFieldInfo[] = []; - try { - const { data } = await readPdfRange(normalized, 0, totalBytes); - const pdfDoc = await getDocument({ - data, - standardFontDataUrl: STANDARD_FONT_DATA_URL, - StandardFontDataFactory: FetchStandardFontDataFactory, - verbosity: VerbosityLevel.ERRORS, - }).promise; - try { - formSchema = await extractFormSchema(pdfDoc); - fieldInfo = await extractFormFieldInfo(pdfDoc); - } finally { - pdfDoc.destroy(); - } - } catch { - // Non-fatal — PDF may not have form fields or may fail to parse - } + const { formSchema, fieldInfo } = await probeFormFields( + normalized, + totalBytes, + readPdfRange, + ); if (formSchema) { viewFieldNames.set(uuid, new Set(Object.keys(formSchema.properties))); } - if (fieldInfo.length > 0) { - viewFieldInfo.set(uuid, fieldInfo); - if (!viewFieldNames.has(uuid)) { - viewFieldNames.set( - uuid, - new Set(fieldInfo.map((f) => f.name).filter(Boolean)), - ); - } + if (fieldInfo.length > 0 && !viewFieldNames.has(uuid)) { + viewFieldNames.set( + uuid, + new Set(fieldInfo.map((f) => f.name).filter(Boolean)), + ); } // Elicit form field values if requested and client supports it diff --git a/examples/pdf-server/src/mcp-app.ts b/examples/pdf-server/src/mcp-app.ts index 500879a..a953e24 100644 --- a/examples/pdf-server/src/mcp-app.ts +++ b/examples/pdf-server/src/mcp-app.ts @@ -150,6 +150,11 @@ const imageCache = new Map(); /** Annotations imported from the PDF file (baseline for diff computation). */ let pdfBaselineAnnotations: PdfAnnotationDef[] = []; +/** Pages whose native annotations have already been imported into the baseline. */ +const baselineScannedPages = new Set(); +/** Native-annotation ids the user deleted (from restored localStorage diff) — + * the lazy per-page scan must NOT re-add these to annotationMap. */ +const restoredRemovedIds = new Set(); // Dirty flag — tracks unsaved local changes let isDirty = false; @@ -2679,52 +2684,60 @@ function annotationStorageKey(): string | null { } /** - * Import annotations from the loaded PDF to establish the baseline. - * These are the annotations that exist in the PDF file itself. + * Import one page's native annotations into the baseline. Called lazily from + * renderPage() so we don't walk every page (and pull most of the file via + * range requests) before the user sees anything. Idempotent per page. */ -async function loadBaselineAnnotations( - doc: pdfjsLib.PDFDocumentProxy, -): Promise { - pdfBaselineAnnotations = []; - for (let pageNum = 1; pageNum <= doc.numPages; pageNum++) { +function scanPageBaselineAnnotations( + pageNum: number, + annotations: unknown[], +): void { + if (baselineScannedPages.has(pageNum)) return; + baselineScannedPages.add(pageNum); + let imported = 0; + for (let i = 0; i < annotations.length; i++) { + // Isolate each annotation: a malformed one must not bubble up to the + // caller's form-layer try in renderPage() (which would skip + // AnnotationLayer.render and hide form widgets for the whole page). try { - const page = await doc.getPage(pageNum); - const annotations = await page.getAnnotations(); - for (let i = 0; i < annotations.length; i++) { - const ann = annotations[i]; - const def = importPdfjsAnnotation(ann, pageNum, i); - if (def) { - pdfBaselineAnnotations.push(def); - // Add to annotationMap if not already present (from localStorage restore) - if (!annotationMap.has(def.id)) { - annotationMap.set(def.id, { def, elements: [] }); - } - } else if (ann.annotationType !== 20) { - // Widget (type 20) is expected to be skipped; anything else we - // don't import will still be painted by page.render() onto the - // canvas as unselectable pixels. Log so we can diagnose - // "ghost annotations" (visible but not in panel, not clickable). - log.info( - `[WARN] Baseline: skipped PDF annotation on page ${pageNum}`, - `type=${ann.annotationType}`, - `subtype=${ann.subtype ?? "?"}`, - `name=${ann.name ?? "?"}`, - `rect=${ann.rect ? JSON.stringify(ann.rect) : "none"}`, - ); + const ann = annotations[i] as { + annotationType?: number; + subtype?: string; + name?: string; + rect?: number[]; + }; + const def = importPdfjsAnnotation(ann, pageNum, i); + if (def) { + pdfBaselineAnnotations.push(def); + imported++; + if (!annotationMap.has(def.id) && !restoredRemovedIds.has(def.id)) { + annotationMap.set(def.id, { def, elements: [] }); } + } else if (ann.annotationType !== 20) { + // Widget (type 20) is expected to be skipped; anything else we + // don't import will still be painted by page.render() onto the + // canvas as unselectable pixels. Log so we can diagnose + // "ghost annotations" (visible but not in panel, not clickable). + log.info( + `[WARN] Baseline: skipped PDF annotation on page ${pageNum}`, + `type=${ann.annotationType}`, + `subtype=${ann.subtype ?? "?"}`, + `name=${ann.name ?? "?"}`, + `rect=${ann.rect ? JSON.stringify(ann.rect) : "none"}`, + ); } } catch (err) { - // Log the error — a thrown import for one annotation silently - // drops the REST of that page's annotations too. - log.info( - `[WARN] Baseline: page ${pageNum} annotation import failed:`, - err, - ); + log.info(`Baseline: page ${pageNum} annotation import failed`, err); + } + } + if (imported > 0) { + try { + updateAnnotationsBadge(); + renderAnnotationPanel(); + } catch (err) { + log.info(`Baseline: page ${pageNum} panel update failed`, err); } } - log.info( - `Loaded ${pdfBaselineAnnotations.length} baseline annotations from PDF`, - ); } function persistAnnotations(): void { @@ -2740,6 +2753,20 @@ function persistAnnotations(): void { pdfBaselineFormValues, ); + // computeDiff only sees baseline ids from pages we've already scanned. + // Carry forward restored tombstones for unvisited pages so the first + // persist after restore doesn't drop them. Once every page is scanned the + // baseline is complete and computeDiff is authoritative on its own — + // dropping the carry-forward then also stops a stale id (no longer in the + // file) from pinning dirty=true forever. + if (baselineScannedPages.size < totalPages) { + for (const id of restoredRemovedIds) { + if (!annotationMap.has(id) && !diff.removed.includes(id)) { + diff.removed.push(id); + } + } + } + // Dirty tracks whether there are unsaved changes. Undoing back to baseline // yields an empty diff → clean again → save button disables. if (!isRestoring) setDirty(!isDiffEmpty(diff)); @@ -2765,11 +2792,11 @@ function restoreAnnotations(): void { const diff = deserializeDiff(raw); // Merge baseline + diff. The loop below is add-only, so we MUST also - // delete: loadBaselineAnnotations() runs between the two restore calls - // and re-seeds annotationMap with every baseline id — including the - // ones in diff.removed. Without this, the zombie survives the restore, - // and the next persistAnnotations() sees it in currentIds → computeDiff - // produces removed=[] → the deletion is permanently lost from storage. + // delete: the per-page baseline scan re-seeds annotationMap with every + // native id it encounters — including ones in diff.removed. Without the + // deletes here AND the restoredRemovedIds tombstones below, the zombie + // survives, and the next persistAnnotations() sees it in currentIds → + // computeDiff produces removed=[] → the deletion is permanently lost. const merged = mergeAnnotations(pdfBaselineAnnotations, diff); for (const def of merged) { if (!annotationMap.has(def.id)) { @@ -2778,6 +2805,9 @@ function restoreAnnotations(): void { } for (const id of diff.removed) { annotationMap.delete(id); + // Tombstone so the lazy per-page baseline scan (which runs AFTER this + // restore) doesn't resurrect it. + restoredRemovedIds.add(id); } // Restore form fields @@ -2869,6 +2899,14 @@ async function buildFieldNameMap( // getFieldObjects may fail on some PDFs } + // No AcroForm → nothing to map. Skip the per-page widget walk so form-free + // PDFs (the common large case) don't pull every page after first paint. + // getFieldObjects() itself only reads the catalog/AcroForm dict via range + // transport, so this gate is cheap. + if (!cachedFieldObjects || Object.keys(cachedFieldObjects).length === 0) { + return false; + } + // Scan every page's widget annotations to collect the CORRECT storage keys, // plus labels, pages, positions, AND fieldValue (what the widget renders // — which can differ from getFieldObjects().value if the PDF is internally @@ -3074,11 +3112,19 @@ async function getAnnotatedPdfBytes(): Promise { } // Baseline annotations the user deleted: strip their refs from /Annots so - // they don't reappear on reload. Ids without a recoverable ref (page-index - // fallback) can't be removed by-ref and are skipped. - const removedRefs = pdfBaselineAnnotations - .filter((a) => !annotationMap.has(a.id)) - .map((a) => parseAnnotationRef(a.id)) + // they don't reappear on reload. Include restored tombstones for pages we + // haven't scanned yet — those ids aren't in pdfBaselineAnnotations but the + // ref is still parseable from the id string. Ids without a recoverable ref + // (page-index fallback) can't be removed by-ref and are skipped. + const removedIds = new Set(); + for (const a of pdfBaselineAnnotations) { + if (!annotationMap.has(a.id)) removedIds.add(a.id); + } + for (const id of restoredRemovedIds) { + if (!annotationMap.has(id)) removedIds.add(id); + } + const removedRefs = [...removedIds] + .map(parseAnnotationRef) .filter((r): r is NonNullable => r !== null); // Only write fields that actually changed vs. what's already in the PDF. @@ -3362,6 +3408,9 @@ async function renderPage() { formLayerEl.style.setProperty("--total-scale-factor", `${scale}`); try { const annotations = await page.getAnnotations(); + // Lazy baseline import — piggyback on the annotations we just fetched + // for this page instead of walking all pages upfront. + scanPageBaselineAnnotations(pageToRender, annotations); if (annotations.length > 0) { const linkService = { getDestinationHash: () => "#", @@ -4406,6 +4455,8 @@ async function reloadPdf(): Promise { undoStack.length = 0; redoStack.length = 0; pdfBaselineAnnotations = []; + baselineScannedPages.clear(); + restoredRemovedIds.clear(); pdfBaselineFormValues.clear(); pageTextCache.clear(); pageTextItemsCache.clear(); @@ -4449,11 +4500,11 @@ async function reloadPdf(): Promise { log.info("PDF reloaded:", totalPages, "pages,", totalBytes, "bytes"); showViewer(); - // Render immediately — annotation/form scans below are O(numPages) and - // do NOT block the canvas. See same pattern in the initial-load path. + // Render immediately — baseline-annotation scan now happens per-page + // inside renderPage(); buildFieldNameMap below early-returns when no + // AcroForm is present. See same pattern in the initial-load path. await renderPage(); - await loadBaselineAnnotations(document); const seeded = await buildFieldNameMap(document); syncFormValuesToStorage(); if (seeded) await renderPage(); @@ -4509,6 +4560,11 @@ async function loadPdfProgressively(urlToLoad: string): Promise<{ const loadingTask = pdfjsLib.getDocument({ range: transport, standardFontDataUrl: STANDARD_FONT_DATA_URL, + // Only fetch ranges renderPage()/getFieldObjects() actually ask for. + // Without these pdfjs background-prefetches the whole file regardless of + // the per-page lazy scans below. + disableAutoFetch: true, + disableStream: true, }); try { @@ -4673,12 +4729,13 @@ app.ontoolresult = async (result: CallToolResult) => { scale = fitScale; log.info("Initial fit scale:", scale); } - await renderPage(); - - // Import annotations from the PDF to establish baseline - await loadBaselineAnnotations(document); - // Restore any persisted user diff + // Restore any persisted user diff BEFORE first render so the per-page + // baseline scan inside renderPage() can honour the removed-id tombstones + // and not resurrect annotations the user deleted last session. + // restoreAnnotations is sync (localStorage read) so first paint is not + // delayed. restoreAnnotations(); + await renderPage(); // Build field name → annotation ID mapping for form filling const seeded = await buildFieldNameMap(document); diff --git a/examples/pdf-server/src/pdf-annotations.test.ts b/examples/pdf-server/src/pdf-annotations.test.ts index 38ef27b..239777a 100644 --- a/examples/pdf-server/src/pdf-annotations.test.ts +++ b/examples/pdf-server/src/pdf-annotations.test.ts @@ -367,6 +367,92 @@ describe("computeDiff", () => { current.map((a) => a.id).sort(), ); }); + + // Backs the post-computeDiff union step in mcp-app.ts persistAnnotations / + // getAnnotatedPdfBytes: with the lazy per-page baseline scan, computeDiff + // alone cannot produce `removed` for natives on pages not yet visited, so + // callers must union restoredRemovedIds. These tests pin the contract those + // call sites depend on. + describe("partial baseline (lazy-scan tombstone preservation)", () => { + const tombstoned = "pdf-5-0"; + const userNote: PdfAnnotationDef = { + type: "note", + id: "u1", + page: 1, + x: 10, + y: 10, + content: "unrelated edit", + }; + + /** Mirrors the union loop in mcp-app.ts persistAnnotations. */ + function unionRestored( + diff: AnnotationDiff, + restored: Iterable, + currentIds: Set, + ): void { + for (const id of restored) { + if (!currentIds.has(id) && !diff.removed.includes(id)) { + diff.removed.push(id); + } + } + } + + it("computeDiff alone drops tombstones for unscanned pages; the union step preserves them", () => { + const baseline: PdfAnnotationDef[] = []; // page with the native not yet scanned + const current = [userNote]; + const diff = computeDiff(baseline, current, new Map()); + expect(diff.removed).toEqual([]); // proves the union step is load-bearing + + unionRestored(diff, [tombstoned], new Set(current.map((a) => a.id))); + + expect(diff.removed).toEqual([tombstoned]); + expect(isDiffEmpty(diff)).toBe(false); + expect(deserializeDiff(serializeDiff(diff)).removed).toEqual([ + tombstoned, + ]); + }); + + it("a tombstone the user re-added is excluded from the union", () => { + const reAdded: PdfAnnotationDef = { + type: "note", + id: tombstoned, + page: 3, + x: 0, + y: 0, + content: "back", + }; + const current = [userNote, reAdded]; + const diff = computeDiff([], current, new Map()); + unionRestored(diff, [tombstoned], new Set(current.map((a) => a.id))); + expect(diff.removed).toEqual([]); + }); + + it("union does not duplicate ids once the page is scanned and computeDiff produces them", () => { + const native: PdfAnnotationDef = { + type: "note", + id: tombstoned, + page: 3, + x: 0, + y: 0, + content: "native", + }; + const diff = computeDiff([native], [userNote], new Map()); + expect(diff.removed).toEqual([tombstoned]); + unionRestored(diff, [tombstoned], new Set([userNote.id])); + expect(diff.removed).toEqual([tombstoned]); + }); + + it("removedRefs from restored tombstones parse for buildAnnotatedPdfBytes; non-ref ids are skipped", () => { + const restored = new Set(["pdf-5-0", "pdf-12R", "pdf-2-idx-7"]); + const removedRefs = [...restored] + .map(parseAnnotationRef) + .filter((r): r is NonNullable => r !== null); + expect(removedRefs).toEqual([ + { objectNumber: 5, generationNumber: 0 }, + { objectNumber: 12, generationNumber: 0 }, + ]); + }); + }); }); // ============================================================================= diff --git a/playwright.config.ts b/playwright.config.ts index 6f6cb65..ecf1e13 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -47,6 +47,10 @@ export default defineConfig({ env: { ...process.env, EXAMPLE: process.env.EXAMPLE ?? "", + // Let pdf-server fetch from the http://127.0.0.1 range-counting fixture + // (validateUrl rejects loopback HTTP unless this is set). Scoped to this + // server's check only — does not touch Node's TLS verification. + PDF_SERVER_ALLOW_LOOPBACK_HTTP: "1", }, }, // Snapshot configuration diff --git a/tests/e2e/pdf-incremental-load.spec.ts b/tests/e2e/pdf-incremental-load.spec.ts new file mode 100644 index 0000000..52a99ee --- /dev/null +++ b/tests/e2e/pdf-incremental-load.spec.ts @@ -0,0 +1,271 @@ +import { test, expect, type Page } from "@playwright/test"; +import { + startRangeServer, + type RangeServer, +} from "../helpers/range-counting-server"; + +/** + * Regression guard for incremental PDF loading. + * + * Asserts that display_pdf does not pull the entire file before the viewer + * starts streaming, that form schema is still returned in the initial response, + * and that no byte range is fetched server-side more than once. + * + * The "noforms <30%" test is the load-bearing regression check: it fails on the + * pre-range-transport implementation (which downloads 100% during display_pdf + * for form analysis) and passes once form extraction uses range transport. + */ + +test.setTimeout(120_000); + +let rangeServer: RangeServer; + +test.beforeAll(async () => { + rangeServer = await startRangeServer(); +}); + +test.afterAll(async () => { + await rangeServer.close(); +}); + +test.beforeEach(() => { + rangeServer.resetStats(); +}); + +function getAppFrame(page: Page) { + return page.frameLocator("iframe").first().frameLocator("iframe").first(); +} + +async function waitForAppLoad(page: Page) { + const outerFrame = page.frameLocator("iframe").first(); + await expect(outerFrame.locator("iframe")).toBeVisible({ timeout: 30_000 }); +} + +/** + * Load basic-host, select PDF Server, call display_pdf with a custom URL. + * Resolves once the tool result panel appears (server-side display_pdf done); + * does NOT wait for the viewer iframe — call waitForAppLoad separately so + * byte-count assertions can isolate server-side fetches from viewer fetches. + */ +async function displayPdf(page: Page, url: string) { + await page.goto("/?theme=hide"); + await expect(page.locator("select").first()).toBeEnabled({ timeout: 30_000 }); + await page.locator("select").first().selectOption({ label: "PDF Server" }); + await page.locator("textarea").fill(JSON.stringify({ url })); + await page.click('button:has-text("Call Tool")'); + await expect(page.locator('text="📤 Tool Result"').first()).toBeVisible({ + timeout: 30_000, + }); +} + +/** Read and parse the most recent tool result's structuredContent. */ +async function readStructuredContent( + page: Page, +): Promise> { + const resultPanel = page.locator('text="📤 Tool Result"').first(); + await expect(resultPanel).toBeVisible({ timeout: 30_000 }); + await resultPanel.click(); + const pre = page.locator("pre").last(); + await expect(pre).toBeVisible({ timeout: 5_000 }); + const raw = (await pre.textContent()) ?? "{}"; + const parsed = JSON.parse(raw) as { structuredContent?: object }; + return (parsed.structuredContent ?? {}) as Record; +} + +async function waitForFirstPageRendered(page: Page) { + const canvas = getAppFrame(page).locator("canvas").first(); + await expect(canvas).toBeVisible({ timeout: 30_000 }); + await expect + .poll(async () => canvas.evaluate((c: HTMLCanvasElement) => c.width)) + .toBeGreaterThan(0); +} + +test.describe("PDF Server — incremental loading", () => { + test("display_pdf on a form PDF returns form fields in initial response", async ({ + page, + }) => { + await displayPdf(page, `${rangeServer.baseUrl}/forms.pdf`); + await waitForAppLoad(page); + const sc = await readStructuredContent(page); + const fields = sc.formFields as Array<{ name: string }> | undefined; + expect(fields?.map((f) => f.name).sort()).toEqual([ + "city", + "email", + "name", + "notes", + "phone", + ]); + }); + + test("display_pdf on a no-forms PDF stays under byte budget and bounded overlap", async ({ + page, + }) => { + const fileSize = rangeServer.fileSizes["/noforms.pdf"]; + await displayPdf(page, `${rangeServer.baseUrl}/noforms.pdf`); + + // Measure before the viewer iframe loads so the count reflects only the + // server-side display_pdf range fetches. + expect(rangeServer.stats().totalBytesServed).toBeLessThan(fileSize * 0.3); + + await waitForAppLoad(page); + const sc = await readStructuredContent(page); + expect(sc.formFields).toBeUndefined(); + + await waitForFirstPageRendered(page); + // Server-side display_pdf and the viewer each open the document + // independently, so the xref/trailer/catalog is fetched twice (≈25%). + // This guards against the pre-range-transport behavior where the server + // alone pulled 100% (then 200% with the double-parse), giving overlap >> + // file size once the viewer also loaded. + expect(rangeServer.stats().overlapBytes).toBeLessThan(fileSize * 0.5); + }); + + test("first page renders under stall, then page 2 renders the >512KB image after release", async ({ + page, + }) => { + const fileSize = rangeServer.fileSizes["/noforms.pdf"]; + // Allow ~40% through (header + trailer/xref + page-1 content) then stall. + // The 1.1MB image stream referenced only by pages 2+ is the bulk. + const budget = Math.floor(fileSize * 0.4); + await displayPdf( + page, + `${rangeServer.baseUrl}/noforms.pdf?stallAfterBytes=${budget}`, + ); + await waitForAppLoad(page); + await waitForFirstPageRendered(page); + expect(rangeServer.stats().totalBytesServed).toBeLessThan(fileSize); + + rangeServer.release(); + const app = getAppFrame(page); + await app.locator("#next-btn").click(); + await expect(app.locator("#page-input")).toHaveValue("2", { + timeout: 30_000, + }); + // Page 2 references the ~1.1MB embedded JPEG. Rendering it exercises the + // viewer's range transport on a >MAX_CHUNK_BYTES object after the stall + // is released. (The server-side PdfCacheRangeTransport accumulate-once + // path is covered by the unit test in server.test.ts; on noforms.pdf + // display_pdf bails at the empty getFieldObjects() check before touching + // the image stream, so this test does not exercise it.) + await waitForFirstPageRendered(page); + expect(rangeServer.stats().totalBytesServed).toBeGreaterThan( + fileSize * 0.9, + ); + }); +}); + +// Kept in this spec because the test needs an HTTP-served PDF and the +// range-counting fixture is the convenient place; it does not use any +// byte-accounting features. +test.describe("PDF Server — annotation tombstone preservation", () => { + // FIXME(https://github.com/modelcontextprotocol/ext-apps/issues/642): + // basic-host doesn't replay the cached tool result on inner-iframe reload, + // and a fresh display_pdf call gets a new toolId → new storage key, so the + // restore-from-localStorage path can't be reached. The fix itself is covered + // by the computeDiff/serializeDiff contract tests in + // src/pdf-annotations.test.ts. + test.fixme("deleted native annotation tombstone survives a persist before its page is scanned", async ({ + page, + }) => { + // Regression for the lazy baseline scan: restoredRemovedIds must be + // unioned into persistAnnotations() and getAnnotatedPdfBytes() so a + // delete on page 2 isn't silently dropped when an unrelated edit on + // page 1 triggers a persist before page 2 has been re-scanned. + + await displayPdf(page, `${rangeServer.baseUrl}/with-native-annot.pdf`); + await waitForAppLoad(page); + await waitForFirstPageRendered(page); + const sc = await readStructuredContent(page); + const viewUUID = sc.viewUUID as string; + expect(viewUUID).toBeTruthy(); + + const app = getAppFrame(page); + + // 1. Go to page 2, open the panel, delete the native annotation via UI. + await app.locator("#next-btn").click(); + await expect(app.locator("#page-input")).toHaveValue("2"); + await app.locator("#annotations-btn").click(); + const nativeCard = app.locator( + '.annotation-card[data-annotation-id^="pdf-"]', + ); + await expect(nativeCard).toBeVisible({ timeout: 10_000 }); + const nativeId = await nativeCard.getAttribute("data-annotation-id"); + expect(nativeId).toMatch(/^pdf-\d+R?$/); + await nativeCard.locator(".annotation-card-delete").click(); + // Deleting a native annotation re-renders the card as a crossed-out + // tombstone (annotation-panel.ts createRemovedAnnotationCard) with the + // same data-annotation-id — it doesn't disappear from the DOM. + await expect(nativeCard).toHaveClass(/annotation-card-cleared/); + + // 2. Back to page 1 so the post-reload viewer restores there (page 2 + // must stay unscanned until the very end). + await app.locator("#page-input").fill("1"); + await app.locator("#page-input").press("Enter"); + await expect(app.locator("#page-input")).toHaveValue("1"); + + // 3. Capture the annotation localStorage key and confirm the delete was + // persisted. + const storageKey = await app + .locator("body") + .evaluate( + () => + Object.keys(localStorage).find( + (k) => k.startsWith("pdf-annot:") || k.endsWith(":annotations"), + ) ?? null, + ); + expect(storageKey).toBeTruthy(); + const diffBefore = await app + .locator("body") + .evaluate((_, k) => localStorage.getItem(k), storageKey!); + expect(JSON.parse(diffBefore!).removed).toContain(nativeId); + + // 4. Reload the inner viewer iframe ONLY (basic-host keeps the same + // cached tool result → same viewUUID/toolId → same storage key). + // restoreAnnotations() now seeds restoredRemovedIds from localStorage + // while the lazy scan has only seen page 1. + await app.locator("body").evaluate(() => location.reload()); + await waitForFirstPageRendered(page); + await expect(app.locator("#page-input")).toHaveValue("1"); + + // 5. Trigger persistAnnotations() via an unrelated edit on page 1 — the + // bug scenario: page 2 has not been scanned yet. + const toolSelect = page.locator("select").nth(1); + await toolSelect.selectOption("interact"); + await page.locator("textarea").fill( + JSON.stringify({ + viewUUID, + action: "add_annotations", + annotations: [ + { + id: "probe-on-page-1", + type: "highlight", + page: 1, + rects: [{ x: 50, y: 700, width: 100, height: 12 }], + }, + ], + }), + ); + await page.click('button:has-text("Call Tool")'); + await expect( + app.locator('[data-annotation-id="probe-on-page-1"]'), + ).toHaveCount(1, { timeout: 10_000 }); + + // 6. Load-bearing assertion: the persisted diff still carries the + // tombstone. Pre-fix, computeDiff() over the page-1-only baseline + // yielded removed=[], overwriting it. + const diffAfter = await app + .locator("body") + .evaluate((_, k) => localStorage.getItem(k), storageKey!); + const removedAfter: string[] = JSON.parse(diffAfter!).removed; + expect(removedAfter).toContain(nativeId); + + // 7. Belt-and-suspenders: navigate to page 2 (lazy scan now sees the + // native annotation) and confirm the panel shows it as a cleared + // tombstone, not a live (resurrected) card. + await app.locator("#next-btn").click(); + await expect(app.locator("#page-input")).toHaveValue("2"); + await expect( + app.locator(`.annotation-card[data-annotation-id="${nativeId}"]`), + ).toHaveClass(/annotation-card-cleared/); + }); +}); diff --git a/tests/helpers/assets/fw9.pdf b/tests/helpers/assets/fw9.pdf new file mode 100644 index 0000000000000000000000000000000000000000..c5eb6467893181c1d481e0748893877b015d5db0 GIT binary patch literal 140815 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

yE%Wu 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 OTiEw}s+GC7E&l*P; + stats(): RangeServerStats; + resetStats(): void; + /** Resolve any requests currently stalled by ?stallAfterBytes=N. */ + release(): void; + close(): Promise; +} + +const LOREM = + "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod " + + "tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim " + + "veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea " + + "commodo consequat. "; + +async function buildNoFormsPdf(): Promise { + const doc = await PDFDocument.create(); + const font = await doc.embedFont(StandardFonts.Helvetica); + // Page 1 is text-only (small) so first paint needs minimal bytes. Pages 2+ + // each reference a large embedded JPEG so the bulk of the file is in image + // streams page 1 doesn't need. The stallAfterBytes test holds those back + // and asserts page 1 still renders. The image is >MAX_CHUNK_BYTES (512KB) + // so rendering page 2 also exercises the viewer's >512KB range path. + const big = await doc.embedJpg(makeRandomJpeg(1_100 * 1024)); + const page1 = doc.addPage([612, 792]); + for (let line = 0; line < 30; line++) { + page1.drawText(`1.${line + 1} ${LOREM}`, { + x: 36, + y: 760 - line * 22, + size: 10, + font, + }); + } + for (let p = 1; p < 20; p++) { + const page = doc.addPage([612, 792]); + page.drawImage(big, { x: 36, y: 200, width: 540, height: 540 }); + page.drawText(`Page ${p + 1}`, { x: 36, y: 760, size: 10, font }); + } + return doc.save(); +} + +/** Minimal valid JPEG with `len` bytes of incompressible scan data. */ +export function makeRandomJpeg(len: number): Uint8Array { + // SOI, APP0 (JFIF), SOF0 (baseline 8x8 1-component), DHT (minimal), + // SOS, , EOI. pdf-lib only needs to parse the headers + // to embed; the scan data is opaque. + const header = Uint8Array.from([ + 0xff, 0xd8, 0xff, 0xe0, 0x00, 0x10, 0x4a, 0x46, 0x49, 0x46, 0x00, 0x01, + 0x01, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0xff, 0xc0, 0x00, 0x0b, + 0x08, 0x00, 0x08, 0x00, 0x08, 0x01, 0x01, 0x11, 0x00, 0xff, 0xc4, 0x00, + 0x14, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xda, 0x00, 0x08, 0x01, + 0x01, 0x00, 0x00, 0x3f, 0x00, + ]); + const scan = new Uint8Array(len); + for (let i = 0; i < len; i++) scan[i] = (i * 1103515245 + 12345) & 0xff; + // Avoid 0xFF in scan data so we don't accidentally form a marker. + for (let i = 0; i < len; i++) if (scan[i] === 0xff) scan[i] = 0xfe; + const eoi = Uint8Array.from([0xff, 0xd9]); + const out = new Uint8Array(header.length + scan.length + eoi.length); + out.set(header, 0); + out.set(scan, header.length); + out.set(eoi, header.length + scan.length); + return out; +} + +/** + * Two pages, page 1 text-only, page 2 carries one native /Text (sticky-note) + * annotation. Used by the tombstone-preservation e2e: the viewer's lazy + * baseline scan must not have visited page 2 when persistAnnotations runs. + */ +async function buildWithNativeAnnotPdf(): Promise { + const doc = await PDFDocument.create(); + const font = await doc.embedFont(StandardFonts.Helvetica); + const page1 = doc.addPage([612, 792]); + page1.drawText("Page 1 — no native annotations here.", { + x: 36, + y: 740, + size: 12, + font, + }); + const page2 = doc.addPage([612, 792]); + page2.drawText("Page 2 — has one native /Text annot.", { + x: 36, + y: 740, + size: 12, + font, + }); + const annotRef = doc.context.register( + doc.context.obj({ + Type: "Annot", + Subtype: "Text", + Rect: [100, 700, 120, 720], + Contents: PDFString.of("native sticky note"), + Open: false, + Name: "Comment", + }), + ); + page2.node.set(PDFName.of("Annots"), doc.context.obj([annotRef])); + return doc.save(); +} + +async function buildFormsPdf(): Promise { + const doc = await PDFDocument.create(); + const form = doc.getForm(); + for (let p = 0; p < 2; p++) doc.addPage([612, 792]); + const [page1] = doc.getPages(); + const fields = ["name", "email", "phone", "city", "notes"]; + fields.forEach((name, i) => { + const f = form.createTextField(name); + f.addToPage(page1, { x: 100, y: 650 - i * 60, width: 300, height: 24 }); + }); + return doc.save(); +} + +export async function startRangeServer(): Promise { + if (process.env.NODE_ENV === "production") { + throw new Error( + "range-counting-server is a test fixture; refusing to start with NODE_ENV=production", + ); + } + const files: Record = { + "/noforms.pdf": await buildNoFormsPdf(), + "/forms.pdf": await buildFormsPdf(), + "/with-native-annot.pdf": await buildWithNativeAnnotPdf(), + }; + const fileSizes = Object.fromEntries( + Object.entries(files).map(([k, v]) => [k, v.length]), + ); + + // Per-path hit count per byte, for overlap accounting. + const hitCounts: Record = {}; + const initHits = () => { + for (const [k, v] of Object.entries(files)) { + hitCounts[k] = new Uint8Array(v.length); + } + }; + initHits(); + + let totalBytesServed = 0; + let releaseResolve: (() => void) | undefined; + let releasePromise = new Promise((r) => (releaseResolve = r)); + + const server = http.createServer(async (req, res) => { + const url = new URL(req.url ?? "/", "http://127.0.0.1"); + const body = files[url.pathname]; + if (!body) { + res.writeHead(404).end(); + return; + } + + const stallAfterBytes = url.searchParams.get("stallAfterBytes"); + const total = body.length; + const range = req.headers.range; + + let begin = 0; + let end = total; // exclusive + let status = 200; + if (range) { + const m = /^bytes=(\d+)-(\d*)$/.exec(range); + if (m) { + begin = parseInt(m[1], 10); + end = m[2] ? parseInt(m[2], 10) + 1 : total; + begin = Math.min(begin, total); + end = Math.min(end, total); + status = 206; + } + } + + // Stall once N bytes have already been served — lets pdfjs read the + // header/trailer/xref (scattered across the file) before blocking the + // bulk content streams. + if (stallAfterBytes !== null) { + if (totalBytesServed >= parseInt(stallAfterBytes, 10)) { + await releasePromise; + } + } + + const slice = body.subarray(begin, end); + totalBytesServed += slice.length; + const hits = hitCounts[url.pathname]; + for (let i = begin; i < end; i++) hits[i]++; + + const headers: Record = { + "Content-Type": "application/pdf", + "Accept-Ranges": "bytes", + "Content-Length": String(slice.length), + }; + if (status === 206) { + headers["Content-Range"] = `bytes ${begin}-${end - 1}/${total}`; + } + res.writeHead(status, headers); + res.end(slice); + }); + + await new Promise((resolve) => server.listen(0, resolve)); + const port = (server.address() as AddressInfo).port; + + return { + port, + baseUrl: `http://127.0.0.1:${port}`, + fileSizes, + stats() { + let overlapBytes = 0; + for (const hits of Object.values(hitCounts)) { + for (let i = 0; i < hits.length; i++) if (hits[i] > 1) overlapBytes++; + } + return { totalBytesServed, overlapBytes }; + }, + resetStats() { + totalBytesServed = 0; + initHits(); + // Unblock any handlers parked on the previous stall before re-arming, + // otherwise they hold sockets open forever and close() hangs. + releaseResolve?.(); + releasePromise = new Promise((r) => (releaseResolve = r)); + }, + release() { + releaseResolve?.(); + }, + close() { + releaseResolve?.(); + server.closeAllConnections?.(); + return new Promise((resolve) => server.close(() => resolve())); + }, + }; +}