From c2f2edbb71f244e696de7de823d9b6c2783a02ca Mon Sep 17 00:00:00 2001 From: Thomas Hauth Date: Fri, 26 Jun 2026 09:55:34 +0200 Subject: [PATCH] fix(core): Align pdfjs-dist versions for PDF document loading (#31732) --- package.json | 3 +- .../utils/n8n-binary-loader.real-pdf.test.ts | 86 +++++++++++++++++++ .../test/ReadPDF-encrypted.workflow.json | 2 +- .../nodes/ReadPdf/test/ReadPDF.workflow.json | 2 +- packages/nodes-base/package.json | 2 +- .../nodes-base/utils/__tests__/binary.test.ts | 2 +- ...@5.3.31.patch => pdfjs-dist@5.4.296.patch} | 8 +- pnpm-lock.yaml | 23 ++--- pnpm-workspace.yaml | 1 + 9 files changed, 105 insertions(+), 24 deletions(-) create mode 100644 packages/@n8n/ai-utilities/src/__tests__/utils/n8n-binary-loader.real-pdf.test.ts rename patches/{pdfjs-dist@5.3.31.patch => pdfjs-dist@5.4.296.patch} (80%) diff --git a/package.json b/package.json index eda1fba3301..b4f38e1c800 100644 --- a/package.json +++ b/package.json @@ -138,6 +138,7 @@ "date-fns-tz": "2.0.0", "form-data": "4.0.6", "pdf-parse": "catalog:", + "pdfjs-dist": "catalog:", "tmp": "0.2.7", "nodemailer": "8.0.10", "validator": "13.15.26", @@ -200,7 +201,7 @@ }, "patchedDependencies": { "bull@4.16.4": "patches/bull@4.16.4.patch", - "pdfjs-dist@5.3.31": "patches/pdfjs-dist@5.3.31.patch", + "pdfjs-dist@5.4.296": "patches/pdfjs-dist@5.4.296.patch", "pkce-challenge@5.0.0": "patches/pkce-challenge@5.0.0.patch", "@types/express-serve-static-core@5.0.6": "patches/@types__express-serve-static-core@5.0.6.patch", "@types/ws@8.18.1": "patches/@types__ws@8.18.1.patch", diff --git a/packages/@n8n/ai-utilities/src/__tests__/utils/n8n-binary-loader.real-pdf.test.ts b/packages/@n8n/ai-utilities/src/__tests__/utils/n8n-binary-loader.real-pdf.test.ts new file mode 100644 index 00000000000..83ff4c4a8bf --- /dev/null +++ b/packages/@n8n/ai-utilities/src/__tests__/utils/n8n-binary-loader.real-pdf.test.ts @@ -0,0 +1,86 @@ +import type { IBinaryData, IExecuteFunctions, INode, INodeExecutionData } from 'n8n-workflow'; +import { BINARY_ENCODING, LoggerProxy } from 'n8n-workflow'; +import { readFileSync } from 'node:fs'; +import { join } from 'node:path'; +import { pathToFileURL } from 'node:url'; +import { PDFParse } from 'pdf-parse'; + +import { N8nBinaryLoader } from 'src/utils/n8n-binary-loader'; + +LoggerProxy.init({ + debug: vi.fn(), + info: vi.fn(), + warn: vi.fn(), + error: vi.fn(), +}); + +describe('N8nBinaryLoader with real PDF data', () => { + it('loads a real PDF through the PDF document loader', async () => { + // Match the app runtime path where the PDF worker can resolve through + // nodes-base. This catches pdfjs-dist version drift between the pdf-parse + // API used here and the worker bundled by another package. + const originalWorker = PDFParse.setWorker(); + PDFParse.setWorker( + pathToFileURL( + join( + __dirname, + '../../../../../nodes-base/node_modules/pdfjs-dist/legacy/build/pdf.worker.mjs', + ), + ).href, + ); + const pdfBuffer = readFileSync( + join(__dirname, '../../../../../nodes-base/nodes/ReadPdf/test/sample.pdf'), + ); + const binaryData: IBinaryData = { + mimeType: 'application/pdf', + data: pdfBuffer.toString(BINARY_ENCODING), + fileName: 'sample.pdf', + }; + const node: INode = { + id: 'test-node', + name: 'Test Node', + type: 'n8n-nodes-base.testNode', + typeVersion: 1, + position: [0, 0], + parameters: {}, + }; + const item: INodeExecutionData = { + json: {}, + binary: { data: binaryData }, + }; + const context = { + getNode: vi.fn(() => node), + getNodeParameter: vi.fn((paramName: string, _itemIndex: number, defaultValue?: unknown) => { + switch (paramName) { + case 'binaryMode': + return 'singleFile'; + case 'loader': + return 'pdfLoader'; + case 'splitPages': + return false; + case 'options': + return {}; + default: + return defaultValue; + } + }), + helpers: { + assertBinaryData: vi.fn(() => binaryData), + }, + } as unknown as IExecuteFunctions; + + const loader = new N8nBinaryLoader(context, '', 'data'); + + try { + const documents = await loader.processItem(item, 0); + + expect(documents).toHaveLength(1); + expect(documents[0].pageContent).toContain('N8N'); + expect(documents[0].pageContent).toContain('Sample PDF'); + expect(documents[0].metadata.pdf).toMatchObject({ totalPages: 1 }); + expect(context.helpers.assertBinaryData).toHaveBeenCalledWith(0, 'data'); + } finally { + PDFParse.setWorker(originalWorker); + } + }); +}); diff --git a/packages/nodes-base/nodes/ReadPdf/test/ReadPDF-encrypted.workflow.json b/packages/nodes-base/nodes/ReadPdf/test/ReadPDF-encrypted.workflow.json index 918de4bdb7b..7cb312f8c41 100644 --- a/packages/nodes-base/nodes/ReadPdf/test/ReadPDF-encrypted.workflow.json +++ b/packages/nodes-base/nodes/ReadPdf/test/ReadPDF-encrypted.workflow.json @@ -57,7 +57,7 @@ "Title": "sample" }, "text": "N8N\nSample PDF\nLorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor\ninvidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et\njusto duo dolores et ea rebum.", - "version": "5.3.31" + "version": "5.4.296" } } ] diff --git a/packages/nodes-base/nodes/ReadPdf/test/ReadPDF.workflow.json b/packages/nodes-base/nodes/ReadPdf/test/ReadPDF.workflow.json index 31c033b6b44..74e8eb0f73e 100644 --- a/packages/nodes-base/nodes/ReadPdf/test/ReadPDF.workflow.json +++ b/packages/nodes-base/nodes/ReadPdf/test/ReadPDF.workflow.json @@ -54,7 +54,7 @@ "ModDate": "D:20230210122750Z" }, "text": "N8N\nSample PDF\nLorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor\ninvidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et\njusto duo dolores et ea rebum.", - "version": "5.3.31" + "version": "5.4.296" } } ] diff --git a/packages/nodes-base/package.json b/packages/nodes-base/package.json index f35af3e22ab..c818cb5e00b 100644 --- a/packages/nodes-base/package.json +++ b/packages/nodes-base/package.json @@ -974,7 +974,7 @@ "nodemailer": "catalog:", "oracledb": "catalog:", "otpauth": "9.1.1", - "pdfjs-dist": "5.3.31", + "pdfjs-dist": "catalog:", "pg": "catalog:", "pg-promise": "11.9.1", "promise-ftp": "1.3.5", diff --git a/packages/nodes-base/utils/__tests__/binary.test.ts b/packages/nodes-base/utils/__tests__/binary.test.ts index 081f356ce34..532ee1da8e4 100644 --- a/packages/nodes-base/utils/__tests__/binary.test.ts +++ b/packages/nodes-base/utils/__tests__/binary.test.ts @@ -19,7 +19,7 @@ vi.mock('xlsx', () => ({ vi.mock('pdfjs-dist/legacy/build/pdf.mjs', () => ({ getDocument: vi.fn(), - version: '5.3.31', + version: '5.4.296', })); describe('convertJsonToSpreadsheetBinary', () => { diff --git a/patches/pdfjs-dist@5.3.31.patch b/patches/pdfjs-dist@5.4.296.patch similarity index 80% rename from patches/pdfjs-dist@5.3.31.patch rename to patches/pdfjs-dist@5.4.296.patch index 99c1d86572b..8a8110080b8 100644 --- a/patches/pdfjs-dist@5.3.31.patch +++ b/patches/pdfjs-dist@5.4.296.patch @@ -1,8 +1,8 @@ diff --git a/legacy/build/pdf.mjs b/legacy/build/pdf.mjs -index 1a373ea986beef21076d30438235d180a0487c20..9d584f4fcc13f0b86e57160570c530e5ac794638 100644 +index d0c1864edb1d3a042468fd3f8ca98f9b52b67a1b..e26bc47c11e5ce612a7f6f4fead34e04473e68f1 100644 --- a/legacy/build/pdf.mjs +++ b/legacy/build/pdf.mjs -@@ -12060,9 +12060,9 @@ class DOMWasmFactory extends BaseWasmFactory { +@@ -14336,9 +14336,9 @@ class AnnotationEditor { if (isNodeJS) { let canvas; try { @@ -14,7 +14,7 @@ index 1a373ea986beef21076d30438235d180a0487c20..9d584f4fcc13f0b86e57160570c530e5 } catch (ex) { warn(`Cannot load "@napi-rs/canvas" package: "${ex}".`); } -@@ -12106,8 +12106,8 @@ async function node_utils_fetchData(url) { +@@ -14382,8 +14382,8 @@ async function node_utils_fetchData(url) { class NodeFilterFactory extends BaseFilterFactory {} class NodeCanvasFactory extends BaseCanvasFactory { _createCanvas(width, height) { @@ -24,4 +24,4 @@ index 1a373ea986beef21076d30438235d180a0487c20..9d584f4fcc13f0b86e57160570c530e5 + const canvas = _require("@napi-rs/canvas"); return canvas.createCanvas(width, height); } - } + } \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e7cd5713d05..2bf0d9f0ddc 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -683,6 +683,7 @@ overrides: date-fns-tz: 2.0.0 form-data: 4.0.6 pdf-parse: 2.4.5 + pdfjs-dist: 5.4.296 tmp: 0.2.7 nodemailer: 8.0.10 validator: 13.15.26 @@ -768,9 +769,9 @@ patchedDependencies: minifaker: hash: bc707e2c34a2464da2c9c93ead33e80fd9883a00434ef64907ddc45208a08b33 path: patches/minifaker.patch - pdfjs-dist@5.3.31: - hash: 421253c8e411cdaef58ba96d2bb44ae0784e1b3e446f5caca50710daa1fa5dcd - path: patches/pdfjs-dist@5.3.31.patch + pdfjs-dist@5.4.296: + hash: e652436fd7a04798432ecfcf33f92fbe6ebedbc248af535faca00b8181aa936f + path: patches/pdfjs-dist@5.4.296.patch pkce-challenge@5.0.0: hash: 651e785d0b7bbf5be9210e1e895c39a16dc3ce8a5a3843b4819565fb6e175b90 path: patches/pkce-challenge@5.0.0.patch @@ -5588,8 +5589,8 @@ importers: specifier: 9.1.1 version: 9.1.1 pdfjs-dist: - specifier: 5.3.31 - version: 5.3.31(patch_hash=421253c8e411cdaef58ba96d2bb44ae0784e1b3e446f5caca50710daa1fa5dcd) + specifier: 5.4.296 + version: 5.4.296(patch_hash=e652436fd7a04798432ecfcf33f92fbe6ebedbc248af535faca00b8181aa936f) pg: specifier: 'catalog:' version: 8.17.0 @@ -18721,10 +18722,6 @@ packages: engines: {node: '>=20.16.0 <21 || >=22.3.0'} hasBin: true - pdfjs-dist@5.3.31: - resolution: {integrity: sha512-EhPdIjNX0fcdwYQO+e3BAAJPXt+XI29TZWC7COhIXs/K0JHcUt1Gdz1ITpebTwVMFiLsukdUZ3u0oTO7jij+VA==} - engines: {node: '>=20.16.0 || >=22.3.0'} - pdfjs-dist@5.4.296: resolution: {integrity: sha512-DlOzet0HO7OEnmUmB6wWGJrrdvbyJKftI1bhMitK7O2N8W2gc757yyYBbINy9IDafXAV9wmKr9t7xsTaNKRG5Q==} engines: {node: '>=20.16.0 || >=22.3.0'} @@ -37787,13 +37784,9 @@ snapshots: pdf-parse@2.4.5: dependencies: '@napi-rs/canvas': 0.1.80 - pdfjs-dist: 5.4.296 + pdfjs-dist: 5.4.296(patch_hash=e652436fd7a04798432ecfcf33f92fbe6ebedbc248af535faca00b8181aa936f) - pdfjs-dist@5.3.31(patch_hash=421253c8e411cdaef58ba96d2bb44ae0784e1b3e446f5caca50710daa1fa5dcd): - optionalDependencies: - '@napi-rs/canvas': 0.1.80 - - pdfjs-dist@5.4.296: + pdfjs-dist@5.4.296(patch_hash=e652436fd7a04798432ecfcf33f92fbe6ebedbc248af535faca00b8181aa936f): optionalDependencies: '@napi-rs/canvas': 0.1.80 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 04749ad1b83..a9528479487 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -166,6 +166,7 @@ catalog: oxlint: ^1.61.0 oxlint-tsgolint: ^0.21.1 pdf-parse: 2.4.5 + pdfjs-dist: 5.4.296 pg: 8.17.0 picocolors: 1.0.1 playwright-core: 1.60.0