[object Object]

← back to Exo

Fix pdf inputs on Safari (#1865)

2962ebee604ddd701178acc17ca582606a81c9cb · 2026-04-10 15:59:34 +0100 · ciaranbor

## Motivation

PDF attachments weren't working on Safari

## Changes

Create async readable stream if none exists

## Why It Works
pdfjs-dist requires an async readable stream internally

## Test Plan

### Manual Testing
pdf attachments now work on Safari, still work on Firefox

Files touched

Diff

commit 2962ebee604ddd701178acc17ca582606a81c9cb
Author: ciaranbor <81697641+ciaranbor@users.noreply.github.com>
Date:   Fri Apr 10 15:59:34 2026 +0100

    Fix pdf inputs on Safari (#1865)
    
    ## Motivation
    
    PDF attachments weren't working on Safari
    
    ## Changes
    
    Create async readable stream if none exists
    
    ## Why It Works
    pdfjs-dist requires an async readable stream internally
    
    ## Test Plan
    
    ### Manual Testing
    pdf attachments now work on Safari, still work on Firefox
---
 dashboard/src/lib/types/files.ts | 26 ++++++++++++++++++++++++++
 1 file changed, 26 insertions(+)

diff --git a/dashboard/src/lib/types/files.ts b/dashboard/src/lib/types/files.ts
index d2231d57..4e2b8641 100644
--- a/dashboard/src/lib/types/files.ts
+++ b/dashboard/src/lib/types/files.ts
@@ -5,6 +5,32 @@
 import { getDocument, GlobalWorkerOptions, version } from "pdfjs-dist";
 import type { DocumentInitParameters } from "pdfjs-dist/types/src/display/api";
 
+// Safari (through at least 18/26) does not implement
+// ReadableStream.prototype[Symbol.asyncIterator], which pdfjs-dist uses
+// internally in getTextContent(). Without this polyfill, `for await (const n
+// of stream)` throws "undefined is not a function" and PDF processing fails.
+if (
+  typeof ReadableStream !== "undefined" &&
+  !(ReadableStream.prototype as unknown as Record<symbol, unknown>)[
+    Symbol.asyncIterator
+  ]
+) {
+  (ReadableStream.prototype as unknown as Record<symbol, unknown>)[
+    Symbol.asyncIterator
+  ] = async function* (this: ReadableStream<unknown>) {
+    const reader = this.getReader();
+    try {
+      while (true) {
+        const { done, value } = await reader.read();
+        if (done) return;
+        yield value;
+      }
+    } finally {
+      reader.releaseLock();
+    }
+  };
+}
+
 GlobalWorkerOptions.workerSrc = `https://cdn.jsdelivr.net/npm/pdfjs-dist@${version}/build/pdf.worker.mjs`;
 
 const PDF_PAGE_SCALE = 2.0;

← abd75ae0 Truncate long logs with repr (#1854)  ·  back to Exo  ·  `just package` first builds dashboard (#1867) 93a980a6 →