Skip to content

Commit e8a4ea5

Browse files
authored
fix(pdf-server): detached-buffer on range re-request + stale e2e assertion (#561)
* fix(pdf-server): slice bytes before onDataRange to avoid detached buffer PDF.js transfers the ArrayBuffer to its worker via postMessage, detaching it in the main thread. When the same range is re-requested (common on iOS/WKWebView under memory pressure during scroll/zoom/navigate), the cached Uint8Array now wraps a detached buffer and onDataRange throws 'Buffer is already detached'. Fix: pass result.bytes.slice() so the rangeCache entry stays valid. * test(e2e): update pdf-annotations assertion for new display_pdf prompt text The 91880a6 prompt rewrite changed the interact-enabled result text from 'Displaying PDF (viewUUID: ...)' to 'PDF opened. viewUUID: ...'. The e2e test was still asserting the old string.
1 parent 6723c8f commit e8a4ea5

File tree

2 files changed

+7
-3
lines changed

2 files changed

+7
-3
lines changed

examples/pdf-server/src/mcp-app.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3875,7 +3875,11 @@ async function loadPdfProgressively(urlToLoad: string): Promise<{
38753875
requestDataRange(begin: number, end: number) {
38763876
fetchRange(urlToLoad, begin, end)
38773877
.then((result) => {
3878-
this.onDataRange(begin, result.bytes);
3878+
// PDF.js transfers the ArrayBuffer to its worker, detaching it.
3879+
// Pass a copy so the rangeCache entry stays valid for re-requests
3880+
// (iOS/WKWebView re-requests ranges under memory pressure and
3881+
// throws "Buffer is already detached" on the cached original).
3882+
this.onDataRange(begin, result.bytes.slice());
38793883
})
38803884
.catch((err: unknown) => {
38813885
log.error(`Error fetching range ${begin}-${end}:`, err);

tests/e2e/pdf-annotations.spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ async function extractViewUUID(page: Page): Promise<string> {
5050
const resultText = (await resultContent.textContent()) ?? "";
5151

5252
// Extract viewUUID from the JSON result
53-
// The text content includes: "Displaying PDF (viewUUID: <uuid>): ..."
53+
// The text content includes: "PDF opened. viewUUID: <uuid>"
5454
const match = resultText.match(/viewUUID["\s:]+([a-f0-9-]{36})/);
5555
if (!match) {
5656
throw new Error(
@@ -107,7 +107,7 @@ test.describe("PDF Server - Annotations", () => {
107107
// (interact action list lives in the tool description, not the runtime result).
108108
expect(resultText).toContain("viewUUID");
109109
expect(resultText).toContain("interactEnabled");
110-
expect(resultText).toContain("Displaying PDF");
110+
expect(resultText).toContain("PDF opened");
111111
});
112112

113113
test("interact tool is available in tool dropdown", async ({ page }) => {

0 commit comments

Comments
 (0)