From c35351ec5eb38e76df61c5aa3c3ce52f3855f53b Mon Sep 17 00:00:00 2001 From: krflol Date: Thu, 15 Oct 2026 10:09:56 -0500 Subject: [PATCH] Update framework starters to Fullbleed 0.5.1 --- .github/workflows/browser-starter.yml | 4 +- .github/workflows/react-starter.yml | 4 +- .github/workflows/vue-starter.yml | 4 +- examples/browser/README.md | 4 +- examples/browser/package-lock.json | 8 +- examples/browser/package.json | 2 +- examples/nextjs/README.md | 4 +- examples/nextjs/package-lock.json | 8 +- examples/nextjs/package.json | 2 +- examples/react/README.md | 4 +- examples/react/package-lock.json | 8 +- examples/react/package.json | 2 +- examples/vue/README.md | 4 +- examples/vue/package-lock.json | 8 +- examples/vue/package.json | 2 +- tools/starter-engine-2.5.24.json | 133 +++ tools/starter_engine_fixes.py | 44 +- verification/starters-051.json | 1460 +++++++++++++++++++++++++ 18 files changed, 1668 insertions(+), 37 deletions(-) create mode 100644 tools/starter-engine-2.5.24.json create mode 100644 verification/starters-051.json diff --git a/.github/workflows/browser-starter.yml b/.github/workflows/browser-starter.yml index ddf6f3d..8471014 100644 --- a/.github/workflows/browser-starter.yml +++ b/.github/workflows/browser-starter.yml @@ -3,9 +3,9 @@ name: Browser starter on: push: branches: [main] - paths: ['examples/browser/**', 'tools/check-browser-starter.py', 'tools/browser-requirements.txt', 'tools/starter_standard_fonts.py', 'tools/starter_engine_fixes.py', 'tools/starter-engine-2.5.22.json', '.github/workflows/browser-starter.yml'] + paths: ['examples/browser/**', 'tools/check-browser-starter.py', 'tools/browser-requirements.txt', 'tools/starter_standard_fonts.py', 'tools/starter_engine_fixes.py', 'tools/starter-engine-2.5.22.json', 'tools/starter-engine-2.5.24.json', '.github/workflows/browser-starter.yml'] pull_request: - paths: ['examples/browser/**', 'tools/check-browser-starter.py', 'tools/browser-requirements.txt', 'tools/starter_standard_fonts.py', 'tools/starter_engine_fixes.py', 'tools/starter-engine-2.5.22.json', '.github/workflows/browser-starter.yml'] + paths: ['examples/browser/**', 'tools/check-browser-starter.py', 'tools/browser-requirements.txt', 'tools/starter_standard_fonts.py', 'tools/starter_engine_fixes.py', 'tools/starter-engine-2.5.22.json', 'tools/starter-engine-2.5.24.json', '.github/workflows/browser-starter.yml'] workflow_dispatch: permissions: diff --git a/.github/workflows/react-starter.yml b/.github/workflows/react-starter.yml index b227674..779ece1 100644 --- a/.github/workflows/react-starter.yml +++ b/.github/workflows/react-starter.yml @@ -3,9 +3,9 @@ name: React starter on: push: branches: [main] - paths: ['examples/react/**', 'tools/check-react-starter.py', 'tools/prepare-react-check.mjs', 'tools/browser-requirements.txt', 'tools/starter_standard_fonts.py', 'tools/starter_engine_fixes.py', 'tools/starter-engine-2.5.22.json', '.github/workflows/react-starter.yml'] + paths: ['examples/react/**', 'tools/check-react-starter.py', 'tools/prepare-react-check.mjs', 'tools/browser-requirements.txt', 'tools/starter_standard_fonts.py', 'tools/starter_engine_fixes.py', 'tools/starter-engine-2.5.22.json', 'tools/starter-engine-2.5.24.json', '.github/workflows/react-starter.yml'] pull_request: - paths: ['examples/react/**', 'tools/check-react-starter.py', 'tools/prepare-react-check.mjs', 'tools/browser-requirements.txt', 'tools/starter_standard_fonts.py', 'tools/starter_engine_fixes.py', 'tools/starter-engine-2.5.22.json', '.github/workflows/react-starter.yml'] + paths: ['examples/react/**', 'tools/check-react-starter.py', 'tools/prepare-react-check.mjs', 'tools/browser-requirements.txt', 'tools/starter_standard_fonts.py', 'tools/starter_engine_fixes.py', 'tools/starter-engine-2.5.22.json', 'tools/starter-engine-2.5.24.json', '.github/workflows/react-starter.yml'] workflow_dispatch: permissions: diff --git a/.github/workflows/vue-starter.yml b/.github/workflows/vue-starter.yml index 461f1b9..590a774 100644 --- a/.github/workflows/vue-starter.yml +++ b/.github/workflows/vue-starter.yml @@ -3,9 +3,9 @@ name: Vue starter on: push: branches: [main] - paths: ['examples/vue/**', 'tools/check-vue-starter.py', 'tools/prepare-vue-check.mjs', 'tools/browser-requirements.txt', 'tools/starter_standard_fonts.py', 'tools/starter_engine_fixes.py', 'tools/starter-engine-2.5.22.json', '.github/workflows/vue-starter.yml'] + paths: ['examples/vue/**', 'tools/check-vue-starter.py', 'tools/prepare-vue-check.mjs', 'tools/browser-requirements.txt', 'tools/starter_standard_fonts.py', 'tools/starter_engine_fixes.py', 'tools/starter-engine-2.5.22.json', 'tools/starter-engine-2.5.24.json', '.github/workflows/vue-starter.yml'] pull_request: - paths: ['examples/vue/**', 'tools/check-vue-starter.py', 'tools/prepare-vue-check.mjs', 'tools/browser-requirements.txt', 'tools/starter_standard_fonts.py', 'tools/starter_engine_fixes.py', 'tools/starter-engine-2.5.22.json', '.github/workflows/vue-starter.yml'] + paths: ['examples/vue/**', 'tools/check-vue-starter.py', 'tools/prepare-vue-check.mjs', 'tools/browser-requirements.txt', 'tools/starter_standard_fonts.py', 'tools/starter_engine_fixes.py', 'tools/starter-engine-2.5.22.json', 'tools/starter-engine-2.5.24.json', '.github/workflows/vue-starter.yml'] workflow_dispatch: permissions: diff --git a/examples/browser/README.md b/examples/browser/README.md index be7f054..8d2e956 100644 --- a/examples/browser/README.md +++ b/examples/browser/README.md @@ -63,8 +63,8 @@ explains CSP, custom assets, structured errors, and browser worker lifecycle lim ## Versions and verification -The lockfile pins Fullbleed npm 0.4.1 / engine 2.5.22 and Vite 8.3.2. -The browser SDK is covered by the [versioned release evidence](https://github.com/fullbleed-engine/fullbleed-node/releases/tag/v0.4.1). +The lockfile pins Fullbleed npm 0.5.1 / engine 2.5.24 and Vite 8.3.2. +The browser SDK is covered by the [versioned release evidence](https://github.com/fullbleed-engine/fullbleed-node/releases/tag/v0.5.1). The repository's starter check builds this app, serves it below `/nested/demo/`, downloads actual PDFs, checks their text and page size, exercises editing and cancellation, and captures desktop/mobile screenshots. Playwright WebKit is not diff --git a/examples/browser/package-lock.json b/examples/browser/package-lock.json index 0cbe9cf..07e6174 100644 --- a/examples/browser/package-lock.json +++ b/examples/browser/package-lock.json @@ -8,7 +8,7 @@ "name": "fullbleed-browser-starter", "version": "1.0.0", "dependencies": { - "fullbleed": "0.4.1" + "fullbleed": "0.5.1" }, "devDependencies": { "vite": "8.3.2" @@ -357,9 +357,9 @@ } }, "node_modules/fullbleed": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/fullbleed/-/fullbleed-0.4.1.tgz", - "integrity": "sha512-vP/U/gxv/5M0xGwg8itmh0HtMmwP8qpKdDTZRIDQpAnndjt/Yu4quoLvt1O/FJvmIEVF1ClsioCQnpu4FMmvLA==", + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/fullbleed/-/fullbleed-0.5.1.tgz", + "integrity": "sha512-NSrRDtxqMqm1/tZdEeJm1rSRSvLwL9xpX4emE0cV9wTYSIBuynoQwgV+WbC04/OXfCZpPau7vt5hS0zxYbZaMQ==", "license": "MIT", "dependencies": { "@bjorn3/browser_wasi_shim": "0.4.2" diff --git a/examples/browser/package.json b/examples/browser/package.json index e8aa230..33ac88f 100644 --- a/examples/browser/package.json +++ b/examples/browser/package.json @@ -10,6 +10,6 @@ "build": "npm run assets && vite build", "preview": "vite preview --host 127.0.0.1" }, - "dependencies": { "fullbleed": "0.4.1" }, + "dependencies": { "fullbleed": "0.5.1" }, "devDependencies": { "vite": "8.3.2" } } diff --git a/examples/nextjs/README.md b/examples/nextjs/README.md index b02b027..aa9cfa0 100644 --- a/examples/nextjs/README.md +++ b/examples/nextjs/README.md @@ -20,8 +20,8 @@ Open `http://127.0.0.1:3000` and select **Download sample PDF**. The route IDs return 404. Use `npm run dev` while editing the app. `PORT` changes the port; `FULLBLEED_HOST` changes the production server's loopback binding. -The lockfile pins Next.js 16.3.8, React 19.3.0 and Fullbleed Node 0.4.1 -(engine 2.5.22) from npm. The registry package is byte-identical to the +The lockfile pins Next.js 16.3.8, React 19.3.0 and Fullbleed Node 0.5.1 +(engine 2.5.24) from npm. The registry package is byte-identical to the verified GitHub release tarball. Installing this starter needs no Python, Rust, system fonts or browser renderer. diff --git a/examples/nextjs/package-lock.json b/examples/nextjs/package-lock.json index 664ecb8..0d80bfb 100644 --- a/examples/nextjs/package-lock.json +++ b/examples/nextjs/package-lock.json @@ -9,7 +9,7 @@ "version": "1.0.0", "license": "MIT", "dependencies": { - "fullbleed": "0.4.1", + "fullbleed": "0.5.1", "next": "16.3.8", "react": "19.3.0", "react-dom": "19.3.0" @@ -787,9 +787,9 @@ } }, "node_modules/fullbleed": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/fullbleed/-/fullbleed-0.4.1.tgz", - "integrity": "sha512-vP/U/gxv/5M0xGwg8itmh0HtMmwP8qpKdDTZRIDQpAnndjt/Yu4quoLvt1O/FJvmIEVF1ClsioCQnpu4FMmvLA==", + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/fullbleed/-/fullbleed-0.5.1.tgz", + "integrity": "sha512-NSrRDtxqMqm1/tZdEeJm1rSRSvLwL9xpX4emE0cV9wTYSIBuynoQwgV+WbC04/OXfCZpPau7vt5hS0zxYbZaMQ==", "license": "MIT", "dependencies": { "@bjorn3/browser_wasi_shim": "0.4.2" diff --git a/examples/nextjs/package.json b/examples/nextjs/package.json index 0ba3584..6bc226d 100644 --- a/examples/nextjs/package.json +++ b/examples/nextjs/package.json @@ -16,7 +16,7 @@ "verify": "node tools/verify.mjs" }, "dependencies": { - "fullbleed": "0.4.1", + "fullbleed": "0.5.1", "next": "16.3.8", "react": "19.3.0", "react-dom": "19.3.0" diff --git a/examples/react/README.md b/examples/react/README.md index 12a076e..1579ffc 100644 --- a/examples/react/README.md +++ b/examples/react/README.md @@ -35,7 +35,7 @@ renders supplied static HTML/CSS rather than capturing the React page. ## Reuse the hook Copy `src/usePdfPreview.ts` into your client application, install -`fullbleed@0.4.1`, and copy the runtime with +`fullbleed@0.5.1`, and copy the runtime with `npx fullbleed-browser-assets public/fullbleed`. Keep the document input stable with `useMemo` so ordinary component updates do not schedule another render: @@ -94,7 +94,7 @@ WebAssembly, and Web Crypto are required. ## Versions and verification -The lockfile pins Fullbleed 0.4.1 / engine 2.5.22, React 19.3.0, TypeScript 7.0.2, +The lockfile pins Fullbleed 0.5.1 / engine 2.5.24, React 19.3.0, TypeScript 7.0.2, and Vite 8.3.2. No Fullbleed engine or package release is needed for this example. The repository's `React starter` workflow builds the locked project and checks diff --git a/examples/react/package-lock.json b/examples/react/package-lock.json index 9da5803..e9ca8ab 100644 --- a/examples/react/package-lock.json +++ b/examples/react/package-lock.json @@ -8,7 +8,7 @@ "name": "fullbleed-react-starter", "version": "1.0.0", "dependencies": { - "fullbleed": "0.4.1", + "fullbleed": "0.5.1", "react": "19.3.0", "react-dom": "19.3.0" }, @@ -760,9 +760,9 @@ } }, "node_modules/fullbleed": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/fullbleed/-/fullbleed-0.4.1.tgz", - "integrity": "sha512-vP/U/gxv/5M0xGwg8itmh0HtMmwP8qpKdDTZRIDQpAnndjt/Yu4quoLvt1O/FJvmIEVF1ClsioCQnpu4FMmvLA==", + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/fullbleed/-/fullbleed-0.5.1.tgz", + "integrity": "sha512-NSrRDtxqMqm1/tZdEeJm1rSRSvLwL9xpX4emE0cV9wTYSIBuynoQwgV+WbC04/OXfCZpPau7vt5hS0zxYbZaMQ==", "license": "MIT", "dependencies": { "@bjorn3/browser_wasi_shim": "0.4.2" diff --git a/examples/react/package.json b/examples/react/package.json index 5aec8c9..2aef167 100644 --- a/examples/react/package.json +++ b/examples/react/package.json @@ -12,7 +12,7 @@ "preview": "vite preview --host 127.0.0.1" }, "dependencies": { - "fullbleed": "0.4.1", + "fullbleed": "0.5.1", "react": "19.3.0", "react-dom": "19.3.0" }, diff --git a/examples/vue/README.md b/examples/vue/README.md index 45e4711..537b8ba 100644 --- a/examples/vue/README.md +++ b/examples/vue/README.md @@ -38,7 +38,7 @@ Use [supported print CSS](https://docs.fullbleed.dev/css-coverage/). ## Reuse the composable Copy `src/usePdfPreview.ts` into your client application, install -`fullbleed@0.4.1`, and copy the runtime with +`fullbleed@0.5.1`, and copy the runtime with `npx fullbleed-browser-assets public/fullbleed`: ```vue @@ -106,7 +106,7 @@ WebAssembly, and Web Crypto are required. ## Versions and verification -The lockfile pins Fullbleed 0.4.1 / engine 2.5.22, Vue 3.5.43, TypeScript 6.0.3, +The lockfile pins Fullbleed 0.5.1 / engine 2.5.24, Vue 3.5.43, TypeScript 6.0.3, and Vite 8.3.2. TypeScript 6 is used because the pinned `vue-tsc` still needs TypeScript's JavaScript compiler entry; TypeScript 7 does not expose it. diff --git a/examples/vue/package-lock.json b/examples/vue/package-lock.json index 00ec786..80c00fe 100644 --- a/examples/vue/package-lock.json +++ b/examples/vue/package-lock.json @@ -9,7 +9,7 @@ "version": "1.0.0", "license": "MIT", "dependencies": { - "fullbleed": "0.4.1", + "fullbleed": "0.5.1", "vue": "3.5.43" }, "devDependencies": { @@ -605,9 +605,9 @@ } }, "node_modules/fullbleed": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/fullbleed/-/fullbleed-0.4.1.tgz", - "integrity": "sha512-vP/U/gxv/5M0xGwg8itmh0HtMmwP8qpKdDTZRIDQpAnndjt/Yu4quoLvt1O/FJvmIEVF1ClsioCQnpu4FMmvLA==", + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/fullbleed/-/fullbleed-0.5.1.tgz", + "integrity": "sha512-NSrRDtxqMqm1/tZdEeJm1rSRSvLwL9xpX4emE0cV9wTYSIBuynoQwgV+WbC04/OXfCZpPau7vt5hS0zxYbZaMQ==", "license": "MIT", "dependencies": { "@bjorn3/browser_wasi_shim": "0.4.2" diff --git a/examples/vue/package.json b/examples/vue/package.json index 512fec7..03033ab 100644 --- a/examples/vue/package.json +++ b/examples/vue/package.json @@ -15,7 +15,7 @@ "preview": "vite preview --host 127.0.0.1" }, "dependencies": { - "fullbleed": "0.4.1", + "fullbleed": "0.5.1", "vue": "3.5.43" }, "devDependencies": { diff --git a/tools/starter-engine-2.5.24.json b/tools/starter-engine-2.5.24.json new file mode 100644 index 0000000..a4fdfc4 --- /dev/null +++ b/tools/starter-engine-2.5.24.json @@ -0,0 +1,133 @@ +{ + "schema": "fullbleed.starter.engine-fixes.v1", + "upstreamRelease": "2.5.24", + "sources": [ + { + "path": "test/fixtures/hidden-text-2.5.24.json", + "sha256": "d33c73024b1886825af3bbd164aae6c1857232aabf86aa2129cd6e4ce37aa639", + "url": "https://github.com/fullbleed-engine/fullbleed-node/blob/v0.5.1/test/fixtures/hidden-text-2.5.24.json" + }, + { + "path": "test/fixtures/decoration-thickness.json", + "sha256": "61d464532afbdcafb5579cc8875d761eb69b771a835bcf8483f1bf732e5f8181", + "url": "https://github.com/fullbleed-engine/fullbleed-node/blob/v0.5.1/test/fixtures/decoration-thickness.json" + } + ], + "font": { + "file": "Inter-Variable.ttf", + "sha256": "29160a80ff49ddcab2c97711247e08b1fab27a484a329ce8b813d820dc559031", + "unitsPerEm": 2048, + "underlineThickness": 140 + }, + "cases": [ + { + "name": "visibility-script-blocks", + "family": "visibility", + "html": "

Document AAA

Before

After

", + "css": "@page {size:500px 300px;margin:20px}\nhtml,body {margin:0;padding:0;color:black;background:white}\nbody {font-family:Helvetica;font-size:16px;line-height:24px}\nh1 {font-size:18px;line-height:26px;margin:0 0 12px}\np,pre {margin:0} table {border-collapse:collapse} td {padding:0}\n.flex {display:flex;gap:12px} .grid {display:grid;grid-template-columns:1fr 1fr}\n.contents {display:contents} .decorated {color:#173b6b}\n", + "pages": 1, + "previewDpi": 96, + "expected": { + "text": "Document AAA Before After", + "pdfSha256": "941b22bd5f30bf0f3a46faa6d749ee865eb785dfa623089f3dad0fe7d14a61f7" + } + }, + { + "name": "visibility-style-blocks", + "family": "visibility", + "html": "

Document AAA

Before

After

", + "css": "@page {size:500px 300px;margin:20px}\nhtml,body {margin:0;padding:0;color:black;background:white}\nbody {font-family:Helvetica;font-size:16px;line-height:24px}\nh1 {font-size:18px;line-height:26px;margin:0 0 12px}\np,pre {margin:0} table {border-collapse:collapse} td {padding:0}\n.flex {display:flex;gap:12px} .grid {display:grid;grid-template-columns:1fr 1fr}\n.contents {display:contents} .decorated {color:#173b6b}\n", + "pages": 1, + "previewDpi": 96, + "expected": { + "text": "Document AAA Before After", + "pdfSha256": "941b22bd5f30bf0f3a46faa6d749ee865eb785dfa623089f3dad0fe7d14a61f7" + } + }, + { + "name": "visibility-hidden-span-paragraph", + "family": "visibility", + "html": "

Document AAA

Before HIDDEN_SENTINEL
LEAK
After

", + "css": "@page {size:500px 300px;margin:20px}\nhtml,body {margin:0;padding:0;color:black;background:white}\nbody {font-family:Helvetica;font-size:16px;line-height:24px}\nh1 {font-size:18px;line-height:26px;margin:0 0 12px}\np,pre {margin:0} table {border-collapse:collapse} td {padding:0}\n.flex {display:flex;gap:12px} .grid {display:grid;grid-template-columns:1fr 1fr}\n.contents {display:contents} .decorated {color:#173b6b}\n", + "pages": 1, + "previewDpi": 96, + "expected": { + "text": "Document AAA Before After", + "pdfSha256": "17cd57e1c75e11561e6a2328aed0ec906a2e6994397cdde064ab56bc14c90f2e" + } + }, + { + "name": "visibility-script-revert", + "family": "visibility", + "html": "

Document AAA

Before

After

", + "css": "@page {size:500px 300px;margin:20px}\nhtml,body {margin:0;padding:0;color:black;background:white}\nbody {font-family:Helvetica;font-size:16px;line-height:24px}\nh1 {font-size:18px;line-height:26px;margin:0 0 12px}\np,pre {margin:0} table {border-collapse:collapse} td {padding:0}\n.flex {display:flex;gap:12px} .grid {display:grid;grid-template-columns:1fr 1fr}\n.contents {display:contents} .decorated {color:#173b6b}\n.probe {display:block;display:revert}", + "pages": 1, + "previewDpi": 96, + "expected": { + "text": "Document AAA Before After", + "pdfSha256": "941b22bd5f30bf0f3a46faa6d749ee865eb785dfa623089f3dad0fe7d14a61f7" + } + }, + { + "name": "visibility-script-inline-paragraph", + "family": "visibility", + "html": "

Document AAA

Before After

", + "css": "@page {size:500px 300px;margin:20px}\nhtml,body {margin:0;padding:0;color:black;background:white}\nbody {font-family:Helvetica;font-size:16px;line-height:24px}\nh1 {font-size:18px;line-height:26px;margin:0 0 12px}\np,pre {margin:0} table {border-collapse:collapse} td {padding:0}\n.flex {display:flex;gap:12px} .grid {display:grid;grid-template-columns:1fr 1fr}\n.contents {display:contents} .decorated {color:#173b6b}\n.probe {display:inline}", + "pages": 1, + "previewDpi": 96, + "expected": { + "text": "Document AAA Before SOURCE_SENTINEL After", + "pdfSha256": "0ff638f747481f71797696ff4b0c191b4505ca6bb9bf13fb073822d0c59f2947" + } + }, + { + "name": "decoration-inter-40-underline-font", + "family": "decoration", + "html": "

Invoice AAA HHH

", + "css": "@page {size:480px 140px;margin:0}\nhtml,body {margin:0;padding:0;color:black;background:white}\np {position:absolute;left:24px;top:30px;margin:0;line-height:64px;text-decoration-color:#d00000;text-decoration-skip-ink:none;text-underline-offset:8px}\np {font-family:Inter;font-size:40px;text-decoration-line:underline;text-decoration-thickness:from-font}", + "pages": 1, + "previewDpi": 96, + "expected": { + "variant": "font", + "fontSizePx": 40, + "lines": "underline", + "widthPt": 2.051, + "strokes": 1, + "text": "Invoice AAA HHH" + } + }, + { + "name": "decoration-inter-40-underline-length", + "family": "decoration", + "html": "

Invoice AAA HHH

", + "css": "@page {size:480px 140px;margin:0}\nhtml,body {margin:0;padding:0;color:black;background:white}\np {position:absolute;left:24px;top:30px;margin:0;line-height:64px;text-decoration-color:#d00000;text-decoration-skip-ink:none;text-underline-offset:8px}\np {font-family:Inter;font-size:40px;text-decoration-line:underline;text-decoration-thickness:2.051pt}", + "pages": 1, + "previewDpi": 96, + "expected": { + "variant": "length", + "fontSizePx": 40, + "lines": "underline", + "widthPt": 2.051, + "strokes": 1, + "text": "Invoice AAA HHH" + } + }, + { + "name": "decoration-inter-40-underline-auto", + "family": "decoration", + "html": "

Invoice AAA HHH

", + "css": "@page {size:480px 140px;margin:0}\nhtml,body {margin:0;padding:0;color:black;background:white}\np {position:absolute;left:24px;top:30px;margin:0;line-height:64px;text-decoration-color:#d00000;text-decoration-skip-ink:none;text-underline-offset:8px}\np {font-family:Inter;font-size:40px;text-decoration-line:underline;text-decoration-thickness:auto}", + "pages": 1, + "previewDpi": 96, + "expected": { + "variant": "auto", + "fontSizePx": 40, + "lines": "underline", + "widthPt": 3.0, + "strokes": 1, + "text": "Invoice AAA HHH" + } + } + ], + "scope": "Five released visibility fixtures and three underline-thickness variants through real editors and downloads; no universal CSS parity claim." +} diff --git a/tools/starter_engine_fixes.py b/tools/starter_engine_fixes.py index f4da1cd..3bbacad 100644 --- a/tools/starter_engine_fixes.py +++ b/tools/starter_engine_fixes.py @@ -13,10 +13,37 @@ from PIL import Image from playwright.sync_api import expect from pypdf import PdfReader +from pypdf.generic import ContentStream import pypdfium2 as pdfium FIXTURES = Path(__file__).with_name('starter-engine-2.5.22.json') +CURRENT_FIXTURES = Path(__file__).with_name('starter-engine-2.5.24.json') + + +def decoration_widths(page, reader): + """Read the red decoration strokes, including nested form objects.""" + widths = [] + def visit(stream, resources, width=1.0, color=None, depth=0): + assert depth < 12 + stack = [] + for args, op in ContentStream(stream, reader).operations: + if op == b'q': + stack.append((width, color)) + elif op == b'Q': + width, color = stack.pop() + elif op == b'w': + width = float(args[0]) + elif op == b'RG': + color = tuple(map(float, args)) + elif op in (b'S', b's') and color and color[0] > .7 and color[1:] == (0., 0.): + widths.append(width) + elif op == b'Do': + obj = resources['/XObject'][args[0]].get_object() + if obj.get('/Subtype') == '/Form': + visit(obj, obj.get('/Resources', resources), width, color, depth + 1) + visit(page.get_contents(), page['/Resources']) + return widths def inspect_outputs(case, pdf_path, preview_path, out, check): @@ -32,8 +59,17 @@ def inspect_outputs(case, pdf_path, preview_path, out, check): check(name + ': sibling counter resets produce the required labels', labels == expected['labels']) record['labels'] = labels if 'text' in expected: - check(name + ': decorated initial preserves the paragraph text', + check(name + ': downloaded text matches the expected visible content', re.sub(r'\s+', '', text) == re.sub(r'\s+', '', expected['text'])) + if 'pdfSha256' in expected: + check(name + ': PDF matches the released source/control fixture', + hashlib.sha256(pdf_path.read_bytes()).hexdigest() == expected['pdfSha256']) + if case['family'] == 'decoration': + widths = decoration_widths(reader.pages[0], reader) + check(name + ': decoration stroke count matches', len(widths) == expected['strokes']) + check(name + ': decoration uses the released font or CSS width', + all(abs(width - expected['widthPt']) <= .002 for width in widths)) + record['strokeWidthsPt'] = widths if 'probes' in expected: document = pdfium.PdfDocument(pdf_path) try: @@ -71,6 +107,7 @@ def verify_engine_fixes(page, out, check, ready, *, manual=False, preview_selector='#preview img', edit_sources=None): """Paste focused cases, inspect actual downloads, then restore the editor.""" fixtures = json.loads(FIXTURES.read_text(encoding='utf-8')) + current = json.loads(CURRENT_FIXTURES.read_text(encoding='utf-8')) evidence = out / 'engine-fixes' evidence.mkdir(exist_ok=False) original_html = page.locator(html_selector).input_value() @@ -82,7 +119,7 @@ def edit(html, css): page.locator(html_selector).fill(html) page.locator(css_selector).fill(css) records = [] - for case in fixtures['cases']: + for case in [*fixtures['cases'], *current['cases']]: name = case['name'] (evidence / (name + '.html')).write_text(case['html'], encoding='utf-8', newline='\n') (evidence / (name + '.css')).write_text(case['css'], encoding='utf-8', newline='\n') @@ -113,7 +150,8 @@ def edit(html, css): page.locator(render_selector).click() ready() result = {'ok': True, 'fixturesSha256': hashlib.sha256(FIXTURES.read_bytes()).hexdigest(), + 'additionalFixturesSha256': hashlib.sha256(CURRENT_FIXTURES.read_bytes()).hexdigest(), 'readers': {package: version(package) for package in ['pypdf', 'pypdfium2', 'pillow']}, - 'scope': fixtures['scope'], 'cases': records} + 'scope': fixtures['scope'] + ' ' + current['scope'], 'cases': records} (evidence / 'verification.json').write_text(json.dumps(result, indent=2) + '\n', encoding='utf-8', newline='\n') return result diff --git a/verification/starters-051.json b/verification/starters-051.json new file mode 100644 index 0000000..f843aa2 --- /dev/null +++ b/verification/starters-051.json @@ -0,0 +1,1460 @@ +{ + "ok": true, + "checkedAt": "2026-10-15T15:09:56.646201+00:00", + "package": "0.5.1", + "engine": "2.5.24", + "localBrowser": { + "browser": { + "browser": "155.0.8059.40", + "checks": 79, + "documents": [ + { + "name": "invoice", + "filename": "invoice-NS-1042.pdf", + "pages": 1, + "sha256": "3078d155f30536f5ad721f7be3c241cd78661ae41249131fc0fd65f37f23e408" + }, + { + "name": "color-only", + "filename": "invoice-NS-1042.pdf", + "pages": 1, + "sha256": "a2b69ba41f7ad4c9bcbd38d803a46e70f0b9ccacd90ffbab5b0f7d87ffca5e4b" + }, + { + "name": "customized", + "filename": "invoice-TEST-2042.pdf", + "pages": 1, + "sha256": "31ff314b44a6f13534cc383e0cf24929f0695c1dd3d84769dedf8828c6486a93" + }, + { + "name": "edited", + "filename": "invoice-TEST-2042.pdf", + "pages": 1, + "sha256": "fecff59c1bfd6b59de2f0fb56965a5668023b3b88e64b5c6c30f95875592c4b2" + }, + { + "name": "report", + "filename": "community-report.pdf", + "pages": 3, + "sha256": "139df89824e6a73c13ff62f1237bb8eb9f71e790dcbd051b1bb713ed2bc47802" + }, + { + "name": "recovered", + "filename": "invoice-TEST-2042.pdf", + "pages": 1, + "sha256": "31ff314b44a6f13534cc383e0cf24929f0695c1dd3d84769dedf8828c6486a93" + } + ], + "engineCases": [ + { + "name": "engine-counter-sibling-reset", + "pages": 1, + "text": "Record Ada\nAlpha\nCNT1.1ENDOne\nCNT1.2ENDTwo\nBeta\nCNT2.1ENDThree", + "probes": [], + "labels": [ + "1.1", + "1.2", + "2.1" + ], + "pdfSha256": "3a353c203c5ae356f20a19e7c585229dc9e6dea3225f4a1a7960c5d943154675", + "previewSha256": "ce37f3e85fcdcdff6731873d8f3ad5d453d82fb4ddd6e7f57188c6d5d6cb9280", + "suggestedFilename": "invoice-TEST-2042.pdf" + }, + { + "name": "engine-overflow-nested-clips", + "pages": 1, + "text": "", + "probes": [ + { + "source": "downloaded PDF", + "values": [ + { + "x": 60, + "y": 60, + "expected": [ + 255, + 0, + 0 + ], + "actual": [ + 255, + 0, + 0 + ] + }, + { + "x": 100, + "y": 60, + "expected": [ + 0, + 255, + 0 + ], + "actual": [ + 0, + 255, + 0 + ] + }, + { + "x": 60, + "y": 90, + "expected": [ + 255, + 255, + 255 + ], + "actual": [ + 255, + 255, + 255 + ] + } + ] + }, + { + "source": "displayed preview", + "values": [ + { + "x": 60, + "y": 60, + "expected": [ + 255, + 0, + 0 + ], + "actual": [ + 255, + 0, + 0 + ] + }, + { + "x": 100, + "y": 60, + "expected": [ + 0, + 255, + 0 + ], + "actual": [ + 0, + 255, + 0 + ] + }, + { + "x": 60, + "y": 90, + "expected": [ + 255, + 255, + 255 + ], + "actual": [ + 255, + 255, + 255 + ] + } + ] + } + ], + "pdfSha256": "3cc5f42eb90c4fe0942088f47e5f342e4f3d820b0ccf985cdf92fb0985e6ce7a", + "previewSha256": "21fe48aa84247cec012b40c7e28c64b139824e6a2e2c5a7603b44898148f93c7", + "suggestedFilename": "invoice-TEST-2042.pdf" + }, + { + "name": "engine-border-center-zero-top-falls-back-bottom-svg", + "pages": 1, + "text": "", + "probes": [ + { + "source": "downloaded PDF", + "values": [ + { + "x": 35, + "y": 35, + "expected": [ + 128, + 0, + 180 + ], + "actual": [ + 128, + 0, + 180 + ] + }, + { + "x": 45, + "y": 35, + "expected": [ + 0, + 180, + 0 + ], + "actual": [ + 0, + 180, + 0 + ] + }, + { + "x": 55, + "y": 35, + "expected": [ + 128, + 0, + 180 + ], + "actual": [ + 128, + 0, + 180 + ] + }, + { + "x": 65, + "y": 35, + "expected": [ + 0, + 180, + 0 + ], + "actual": [ + 0, + 180, + 0 + ] + } + ] + }, + { + "source": "displayed preview", + "values": [ + { + "x": 35, + "y": 35, + "expected": [ + 128, + 0, + 180 + ], + "actual": [ + 128, + 0, + 180 + ] + }, + { + "x": 45, + "y": 35, + "expected": [ + 0, + 180, + 0 + ], + "actual": [ + 0, + 180, + 0 + ] + }, + { + "x": 55, + "y": 35, + "expected": [ + 128, + 0, + 180 + ], + "actual": [ + 128, + 0, + 180 + ] + }, + { + "x": 65, + "y": 35, + "expected": [ + 0, + 180, + 0 + ], + "actual": [ + 0, + 180, + 0 + ] + } + ] + } + ], + "pdfSha256": "8e335b31a03779f8cc7cb64b0fa599fcf70345fdc6091605f899b5b3f1f732b5", + "previewSha256": "3880a460b4e3888d863bc47594f29674d8bda496273e604fccac03b74f95524d", + "suggestedFilename": "invoice-TEST-2042.pdf" + }, + { + "name": "engine-first-letter-decorated-left", + "pages": 1, + "text": "D\nrop cap leads this short\nparagraph while the\nremaining text wraps\nbeside the enlarged initial\nletter.", + "probes": [ + { + "source": "downloaded PDF", + "values": [ + { + "x": 28, + "y": 27, + "expected": [ + 224, + 64, + 32 + ], + "actual": [ + 224, + 64, + 32 + ] + }, + { + "x": 32, + "y": 31, + "expected": [ + 255, + 224, + 128 + ], + "actual": [ + 255, + 224, + 128 + ] + } + ] + }, + { + "source": "displayed preview", + "values": [ + { + "x": 28, + "y": 27, + "expected": [ + 224, + 64, + 32 + ], + "actual": [ + 224, + 64, + 32 + ] + }, + { + "x": 32, + "y": 31, + "expected": [ + 255, + 224, + 128 + ], + "actual": [ + 255, + 224, + 128 + ] + } + ] + } + ], + "pdfSha256": "9c527d1432bd5cdb07147442551ffcd5f509aab5928c0745861d4a351ec75ec8", + "previewSha256": "33a7c7d8115e558d246179aefe292c64c2e29b5bab80312afc1d6820262490fc", + "suggestedFilename": "invoice-TEST-2042.pdf" + }, + { + "name": "visibility-script-blocks", + "pages": 1, + "text": "Document AAA\nBefore\nAfter", + "probes": [], + "pdfSha256": "941b22bd5f30bf0f3a46faa6d749ee865eb785dfa623089f3dad0fe7d14a61f7", + "previewSha256": "fc257aa698b0ae28303656ea66ac3efd25542c0d9626f07b19a64b3f8f28920b", + "suggestedFilename": "invoice-TEST-2042.pdf" + }, + { + "name": "visibility-style-blocks", + "pages": 1, + "text": "Document AAA\nBefore\nAfter", + "probes": [], + "pdfSha256": "941b22bd5f30bf0f3a46faa6d749ee865eb785dfa623089f3dad0fe7d14a61f7", + "previewSha256": "fc257aa698b0ae28303656ea66ac3efd25542c0d9626f07b19a64b3f8f28920b", + "suggestedFilename": "invoice-TEST-2042.pdf" + }, + { + "name": "visibility-hidden-span-paragraph", + "pages": 1, + "text": "Document AAA\nBefore After", + "probes": [], + "pdfSha256": "17cd57e1c75e11561e6a2328aed0ec906a2e6994397cdde064ab56bc14c90f2e", + "previewSha256": "8651823d0af4cd652ab6c35598d260b467d74a8b7256cf3e66f49356e904401c", + "suggestedFilename": "invoice-TEST-2042.pdf" + }, + { + "name": "visibility-script-revert", + "pages": 1, + "text": "Document AAA\nBefore\nAfter", + "probes": [], + "pdfSha256": "941b22bd5f30bf0f3a46faa6d749ee865eb785dfa623089f3dad0fe7d14a61f7", + "previewSha256": "fc257aa698b0ae28303656ea66ac3efd25542c0d9626f07b19a64b3f8f28920b", + "suggestedFilename": "invoice-TEST-2042.pdf" + }, + { + "name": "visibility-script-inline-paragraph", + "pages": 1, + "text": "Document AAA\nBefore SOURCE_SENTINEL After", + "probes": [], + "pdfSha256": "0ff638f747481f71797696ff4b0c191b4505ca6bb9bf13fb073822d0c59f2947", + "previewSha256": "44483eea283bae46fdd816f2784cef751d5ab48bd01f34043366fb9ccedea8ac", + "suggestedFilename": "invoice-TEST-2042.pdf" + }, + { + "name": "decoration-inter-40-underline-font", + "pages": 1, + "text": "Invoice AAA HHH", + "probes": [], + "strokeWidthsPt": [ + 2.051 + ], + "pdfSha256": "8c431024572d470f85ce6b82cec990ad7b34d3aed8e77760d5ee378a1bf1f25c", + "previewSha256": "4195165f1f347b30610440c5419b8c0e3a6c7a52c86142e54a47bf5ddba1ac1a", + "suggestedFilename": "invoice-TEST-2042.pdf" + }, + { + "name": "decoration-inter-40-underline-length", + "pages": 1, + "text": "Invoice AAA HHH", + "probes": [], + "strokeWidthsPt": [ + 2.051 + ], + "pdfSha256": "8c431024572d470f85ce6b82cec990ad7b34d3aed8e77760d5ee378a1bf1f25c", + "previewSha256": "4195165f1f347b30610440c5419b8c0e3a6c7a52c86142e54a47bf5ddba1ac1a", + "suggestedFilename": "invoice-TEST-2042.pdf" + }, + { + "name": "decoration-inter-40-underline-auto", + "pages": 1, + "text": "Invoice AAA HHH", + "probes": [], + "strokeWidthsPt": [ + 3.0 + ], + "pdfSha256": "bdf2de5e5f1a102aa2b81a931eb35517cba323136742572fae95eb134f5b13bd", + "previewSha256": "903ba24e63b532b16d8e8571ae634bfbc6455c36b4618d5447f1b928bca43ee1", + "suggestedFilename": "invoice-TEST-2042.pdf" + } + ] + }, + "react": { + "browser": "155.0.8059.40", + "checks": 82, + "documents": [ + { + "name": "invoice", + "pages": 1, + "filename": "invoice-NS-1042.pdf", + "sha256": "3078d155f30536f5ad721f7be3c241cd78661ae41249131fc0fd65f37f23e408" + }, + { + "name": "manual", + "pages": 1, + "filename": "invoice-NS-1042.pdf", + "sha256": "1df9b1852ad96e07d00520d190140044f528b14047df6e30432e91a512be8883" + }, + { + "name": "latest-input", + "pages": 1, + "filename": "invoice-REACT-2042.pdf", + "sha256": "fccdad8d56abef7206e5efefc716af2c44c717c0e1c3619827c6d27931ed76be" + }, + { + "name": "edited-template", + "pages": 1, + "filename": "invoice-REACT-2042.pdf", + "sha256": "c1fe667a39ac3eaae3292c3a1fab1c466999e798a5ab0a4616b73689acc79880" + }, + { + "name": "report", + "pages": 3, + "filename": "community-report.pdf", + "sha256": "139df89824e6a73c13ff62f1237bb8eb9f71e790dcbd051b1bb713ed2bc47802" + }, + { + "name": "recovered", + "pages": 1, + "filename": "invoice-REACT-2042.pdf", + "sha256": "fccdad8d56abef7206e5efefc716af2c44c717c0e1c3619827c6d27931ed76be" + }, + { + "name": "remounted", + "pages": 1, + "filename": "invoice-NS-1042.pdf", + "sha256": "3078d155f30536f5ad721f7be3c241cd78661ae41249131fc0fd65f37f23e408" + } + ], + "engineCases": [ + { + "name": "engine-counter-sibling-reset", + "pages": 1, + "text": "Record Ada\nAlpha\nCNT1.1ENDOne\nCNT1.2ENDTwo\nBeta\nCNT2.1ENDThree", + "probes": [], + "labels": [ + "1.1", + "1.2", + "2.1" + ], + "pdfSha256": "3a353c203c5ae356f20a19e7c585229dc9e6dea3225f4a1a7960c5d943154675", + "previewSha256": "ce37f3e85fcdcdff6731873d8f3ad5d453d82fb4ddd6e7f57188c6d5d6cb9280", + "suggestedFilename": "invoice-REACT-2042.pdf" + }, + { + "name": "engine-overflow-nested-clips", + "pages": 1, + "text": "", + "probes": [ + { + "source": "downloaded PDF", + "values": [ + { + "x": 60, + "y": 60, + "expected": [ + 255, + 0, + 0 + ], + "actual": [ + 255, + 0, + 0 + ] + }, + { + "x": 100, + "y": 60, + "expected": [ + 0, + 255, + 0 + ], + "actual": [ + 0, + 255, + 0 + ] + }, + { + "x": 60, + "y": 90, + "expected": [ + 255, + 255, + 255 + ], + "actual": [ + 255, + 255, + 255 + ] + } + ] + }, + { + "source": "displayed preview", + "values": [ + { + "x": 60, + "y": 60, + "expected": [ + 255, + 0, + 0 + ], + "actual": [ + 255, + 0, + 0 + ] + }, + { + "x": 100, + "y": 60, + "expected": [ + 0, + 255, + 0 + ], + "actual": [ + 0, + 255, + 0 + ] + }, + { + "x": 60, + "y": 90, + "expected": [ + 255, + 255, + 255 + ], + "actual": [ + 255, + 255, + 255 + ] + } + ] + } + ], + "pdfSha256": "3cc5f42eb90c4fe0942088f47e5f342e4f3d820b0ccf985cdf92fb0985e6ce7a", + "previewSha256": "21fe48aa84247cec012b40c7e28c64b139824e6a2e2c5a7603b44898148f93c7", + "suggestedFilename": "invoice-REACT-2042.pdf" + }, + { + "name": "engine-border-center-zero-top-falls-back-bottom-svg", + "pages": 1, + "text": "", + "probes": [ + { + "source": "downloaded PDF", + "values": [ + { + "x": 35, + "y": 35, + "expected": [ + 128, + 0, + 180 + ], + "actual": [ + 128, + 0, + 180 + ] + }, + { + "x": 45, + "y": 35, + "expected": [ + 0, + 180, + 0 + ], + "actual": [ + 0, + 180, + 0 + ] + }, + { + "x": 55, + "y": 35, + "expected": [ + 128, + 0, + 180 + ], + "actual": [ + 128, + 0, + 180 + ] + }, + { + "x": 65, + "y": 35, + "expected": [ + 0, + 180, + 0 + ], + "actual": [ + 0, + 180, + 0 + ] + } + ] + }, + { + "source": "displayed preview", + "values": [ + { + "x": 35, + "y": 35, + "expected": [ + 128, + 0, + 180 + ], + "actual": [ + 128, + 0, + 180 + ] + }, + { + "x": 45, + "y": 35, + "expected": [ + 0, + 180, + 0 + ], + "actual": [ + 0, + 180, + 0 + ] + }, + { + "x": 55, + "y": 35, + "expected": [ + 128, + 0, + 180 + ], + "actual": [ + 128, + 0, + 180 + ] + }, + { + "x": 65, + "y": 35, + "expected": [ + 0, + 180, + 0 + ], + "actual": [ + 0, + 180, + 0 + ] + } + ] + } + ], + "pdfSha256": "8e335b31a03779f8cc7cb64b0fa599fcf70345fdc6091605f899b5b3f1f732b5", + "previewSha256": "3880a460b4e3888d863bc47594f29674d8bda496273e604fccac03b74f95524d", + "suggestedFilename": "invoice-REACT-2042.pdf" + }, + { + "name": "engine-first-letter-decorated-left", + "pages": 1, + "text": "D\nrop cap leads this short\nparagraph while the\nremaining text wraps\nbeside the enlarged initial\nletter.", + "probes": [ + { + "source": "downloaded PDF", + "values": [ + { + "x": 28, + "y": 27, + "expected": [ + 224, + 64, + 32 + ], + "actual": [ + 224, + 64, + 32 + ] + }, + { + "x": 32, + "y": 31, + "expected": [ + 255, + 224, + 128 + ], + "actual": [ + 255, + 224, + 128 + ] + } + ] + }, + { + "source": "displayed preview", + "values": [ + { + "x": 28, + "y": 27, + "expected": [ + 224, + 64, + 32 + ], + "actual": [ + 224, + 64, + 32 + ] + }, + { + "x": 32, + "y": 31, + "expected": [ + 255, + 224, + 128 + ], + "actual": [ + 255, + 224, + 128 + ] + } + ] + } + ], + "pdfSha256": "9c527d1432bd5cdb07147442551ffcd5f509aab5928c0745861d4a351ec75ec8", + "previewSha256": "33a7c7d8115e558d246179aefe292c64c2e29b5bab80312afc1d6820262490fc", + "suggestedFilename": "invoice-REACT-2042.pdf" + }, + { + "name": "visibility-script-blocks", + "pages": 1, + "text": "Document AAA\nBefore\nAfter", + "probes": [], + "pdfSha256": "941b22bd5f30bf0f3a46faa6d749ee865eb785dfa623089f3dad0fe7d14a61f7", + "previewSha256": "fc257aa698b0ae28303656ea66ac3efd25542c0d9626f07b19a64b3f8f28920b", + "suggestedFilename": "invoice-REACT-2042.pdf" + }, + { + "name": "visibility-style-blocks", + "pages": 1, + "text": "Document AAA\nBefore\nAfter", + "probes": [], + "pdfSha256": "941b22bd5f30bf0f3a46faa6d749ee865eb785dfa623089f3dad0fe7d14a61f7", + "previewSha256": "fc257aa698b0ae28303656ea66ac3efd25542c0d9626f07b19a64b3f8f28920b", + "suggestedFilename": "invoice-REACT-2042.pdf" + }, + { + "name": "visibility-hidden-span-paragraph", + "pages": 1, + "text": "Document AAA\nBefore After", + "probes": [], + "pdfSha256": "17cd57e1c75e11561e6a2328aed0ec906a2e6994397cdde064ab56bc14c90f2e", + "previewSha256": "8651823d0af4cd652ab6c35598d260b467d74a8b7256cf3e66f49356e904401c", + "suggestedFilename": "invoice-REACT-2042.pdf" + }, + { + "name": "visibility-script-revert", + "pages": 1, + "text": "Document AAA\nBefore\nAfter", + "probes": [], + "pdfSha256": "941b22bd5f30bf0f3a46faa6d749ee865eb785dfa623089f3dad0fe7d14a61f7", + "previewSha256": "fc257aa698b0ae28303656ea66ac3efd25542c0d9626f07b19a64b3f8f28920b", + "suggestedFilename": "invoice-REACT-2042.pdf" + }, + { + "name": "visibility-script-inline-paragraph", + "pages": 1, + "text": "Document AAA\nBefore SOURCE_SENTINEL After", + "probes": [], + "pdfSha256": "0ff638f747481f71797696ff4b0c191b4505ca6bb9bf13fb073822d0c59f2947", + "previewSha256": "44483eea283bae46fdd816f2784cef751d5ab48bd01f34043366fb9ccedea8ac", + "suggestedFilename": "invoice-REACT-2042.pdf" + }, + { + "name": "decoration-inter-40-underline-font", + "pages": 1, + "text": "Invoice AAA HHH", + "probes": [], + "strokeWidthsPt": [ + 2.051 + ], + "pdfSha256": "8c431024572d470f85ce6b82cec990ad7b34d3aed8e77760d5ee378a1bf1f25c", + "previewSha256": "4195165f1f347b30610440c5419b8c0e3a6c7a52c86142e54a47bf5ddba1ac1a", + "suggestedFilename": "invoice-REACT-2042.pdf" + }, + { + "name": "decoration-inter-40-underline-length", + "pages": 1, + "text": "Invoice AAA HHH", + "probes": [], + "strokeWidthsPt": [ + 2.051 + ], + "pdfSha256": "8c431024572d470f85ce6b82cec990ad7b34d3aed8e77760d5ee378a1bf1f25c", + "previewSha256": "4195165f1f347b30610440c5419b8c0e3a6c7a52c86142e54a47bf5ddba1ac1a", + "suggestedFilename": "invoice-REACT-2042.pdf" + }, + { + "name": "decoration-inter-40-underline-auto", + "pages": 1, + "text": "Invoice AAA HHH", + "probes": [], + "strokeWidthsPt": [ + 3.0 + ], + "pdfSha256": "bdf2de5e5f1a102aa2b81a931eb35517cba323136742572fae95eb134f5b13bd", + "previewSha256": "903ba24e63b532b16d8e8571ae634bfbc6455c36b4618d5447f1b928bca43ee1", + "suggestedFilename": "invoice-REACT-2042.pdf" + } + ] + }, + "vue": { + "browser": "155.0.8059.40", + "checks": 87, + "documents": [ + { + "name": "invoice", + "pages": 1, + "filename": "invoice-NS-1042.pdf", + "sha256": "3078d155f30536f5ad721f7be3c241cd78661ae41249131fc0fd65f37f23e408" + }, + { + "name": "manual", + "pages": 1, + "filename": "invoice-NS-1042.pdf", + "sha256": "1df9b1852ad96e07d00520d190140044f528b14047df6e30432e91a512be8883" + }, + { + "name": "latest-input", + "pages": 1, + "filename": "invoice-VUE-2042.pdf", + "sha256": "f63a42a366b08f4f054cca5594dbcd22510455ddfe2e9129623facfb8371e8ee" + }, + { + "name": "edited-template", + "pages": 1, + "filename": "invoice-VUE-2042.pdf", + "sha256": "071d2bd98b7b90b52aa5b60e74ce0934ef54d3c6032c222d7237786dc12fc953" + }, + { + "name": "report", + "pages": 3, + "filename": "community-report.pdf", + "sha256": "139df89824e6a73c13ff62f1237bb8eb9f71e790dcbd051b1bb713ed2bc47802" + }, + { + "name": "outage-recovery", + "pages": 1, + "filename": "invoice-VUE-2042.pdf", + "sha256": "f63a42a366b08f4f054cca5594dbcd22510455ddfe2e9129623facfb8371e8ee" + }, + { + "name": "recovered", + "pages": 1, + "filename": "invoice-VUE-2042.pdf", + "sha256": "f63a42a366b08f4f054cca5594dbcd22510455ddfe2e9129623facfb8371e8ee" + }, + { + "name": "remounted", + "pages": 1, + "filename": "invoice-NS-1042.pdf", + "sha256": "3078d155f30536f5ad721f7be3c241cd78661ae41249131fc0fd65f37f23e408" + } + ], + "engineCases": [ + { + "name": "engine-counter-sibling-reset", + "pages": 1, + "text": "Record Ada\nAlpha\nCNT1.1ENDOne\nCNT1.2ENDTwo\nBeta\nCNT2.1ENDThree", + "probes": [], + "labels": [ + "1.1", + "1.2", + "2.1" + ], + "pdfSha256": "3a353c203c5ae356f20a19e7c585229dc9e6dea3225f4a1a7960c5d943154675", + "previewSha256": "ce37f3e85fcdcdff6731873d8f3ad5d453d82fb4ddd6e7f57188c6d5d6cb9280", + "suggestedFilename": "invoice-VUE-2042.pdf" + }, + { + "name": "engine-overflow-nested-clips", + "pages": 1, + "text": "", + "probes": [ + { + "source": "downloaded PDF", + "values": [ + { + "x": 60, + "y": 60, + "expected": [ + 255, + 0, + 0 + ], + "actual": [ + 255, + 0, + 0 + ] + }, + { + "x": 100, + "y": 60, + "expected": [ + 0, + 255, + 0 + ], + "actual": [ + 0, + 255, + 0 + ] + }, + { + "x": 60, + "y": 90, + "expected": [ + 255, + 255, + 255 + ], + "actual": [ + 255, + 255, + 255 + ] + } + ] + }, + { + "source": "displayed preview", + "values": [ + { + "x": 60, + "y": 60, + "expected": [ + 255, + 0, + 0 + ], + "actual": [ + 255, + 0, + 0 + ] + }, + { + "x": 100, + "y": 60, + "expected": [ + 0, + 255, + 0 + ], + "actual": [ + 0, + 255, + 0 + ] + }, + { + "x": 60, + "y": 90, + "expected": [ + 255, + 255, + 255 + ], + "actual": [ + 255, + 255, + 255 + ] + } + ] + } + ], + "pdfSha256": "3cc5f42eb90c4fe0942088f47e5f342e4f3d820b0ccf985cdf92fb0985e6ce7a", + "previewSha256": "21fe48aa84247cec012b40c7e28c64b139824e6a2e2c5a7603b44898148f93c7", + "suggestedFilename": "invoice-VUE-2042.pdf" + }, + { + "name": "engine-border-center-zero-top-falls-back-bottom-svg", + "pages": 1, + "text": "", + "probes": [ + { + "source": "downloaded PDF", + "values": [ + { + "x": 35, + "y": 35, + "expected": [ + 128, + 0, + 180 + ], + "actual": [ + 128, + 0, + 180 + ] + }, + { + "x": 45, + "y": 35, + "expected": [ + 0, + 180, + 0 + ], + "actual": [ + 0, + 180, + 0 + ] + }, + { + "x": 55, + "y": 35, + "expected": [ + 128, + 0, + 180 + ], + "actual": [ + 128, + 0, + 180 + ] + }, + { + "x": 65, + "y": 35, + "expected": [ + 0, + 180, + 0 + ], + "actual": [ + 0, + 180, + 0 + ] + } + ] + }, + { + "source": "displayed preview", + "values": [ + { + "x": 35, + "y": 35, + "expected": [ + 128, + 0, + 180 + ], + "actual": [ + 128, + 0, + 180 + ] + }, + { + "x": 45, + "y": 35, + "expected": [ + 0, + 180, + 0 + ], + "actual": [ + 0, + 180, + 0 + ] + }, + { + "x": 55, + "y": 35, + "expected": [ + 128, + 0, + 180 + ], + "actual": [ + 128, + 0, + 180 + ] + }, + { + "x": 65, + "y": 35, + "expected": [ + 0, + 180, + 0 + ], + "actual": [ + 0, + 180, + 0 + ] + } + ] + } + ], + "pdfSha256": "8e335b31a03779f8cc7cb64b0fa599fcf70345fdc6091605f899b5b3f1f732b5", + "previewSha256": "3880a460b4e3888d863bc47594f29674d8bda496273e604fccac03b74f95524d", + "suggestedFilename": "invoice-VUE-2042.pdf" + }, + { + "name": "engine-first-letter-decorated-left", + "pages": 1, + "text": "D\nrop cap leads this short\nparagraph while the\nremaining text wraps\nbeside the enlarged initial\nletter.", + "probes": [ + { + "source": "downloaded PDF", + "values": [ + { + "x": 28, + "y": 27, + "expected": [ + 224, + 64, + 32 + ], + "actual": [ + 224, + 64, + 32 + ] + }, + { + "x": 32, + "y": 31, + "expected": [ + 255, + 224, + 128 + ], + "actual": [ + 255, + 224, + 128 + ] + } + ] + }, + { + "source": "displayed preview", + "values": [ + { + "x": 28, + "y": 27, + "expected": [ + 224, + 64, + 32 + ], + "actual": [ + 224, + 64, + 32 + ] + }, + { + "x": 32, + "y": 31, + "expected": [ + 255, + 224, + 128 + ], + "actual": [ + 255, + 224, + 128 + ] + } + ] + } + ], + "pdfSha256": "9c527d1432bd5cdb07147442551ffcd5f509aab5928c0745861d4a351ec75ec8", + "previewSha256": "33a7c7d8115e558d246179aefe292c64c2e29b5bab80312afc1d6820262490fc", + "suggestedFilename": "invoice-VUE-2042.pdf" + }, + { + "name": "visibility-script-blocks", + "pages": 1, + "text": "Document AAA\nBefore\nAfter", + "probes": [], + "pdfSha256": "941b22bd5f30bf0f3a46faa6d749ee865eb785dfa623089f3dad0fe7d14a61f7", + "previewSha256": "fc257aa698b0ae28303656ea66ac3efd25542c0d9626f07b19a64b3f8f28920b", + "suggestedFilename": "invoice-VUE-2042.pdf" + }, + { + "name": "visibility-style-blocks", + "pages": 1, + "text": "Document AAA\nBefore\nAfter", + "probes": [], + "pdfSha256": "941b22bd5f30bf0f3a46faa6d749ee865eb785dfa623089f3dad0fe7d14a61f7", + "previewSha256": "fc257aa698b0ae28303656ea66ac3efd25542c0d9626f07b19a64b3f8f28920b", + "suggestedFilename": "invoice-VUE-2042.pdf" + }, + { + "name": "visibility-hidden-span-paragraph", + "pages": 1, + "text": "Document AAA\nBefore After", + "probes": [], + "pdfSha256": "17cd57e1c75e11561e6a2328aed0ec906a2e6994397cdde064ab56bc14c90f2e", + "previewSha256": "8651823d0af4cd652ab6c35598d260b467d74a8b7256cf3e66f49356e904401c", + "suggestedFilename": "invoice-VUE-2042.pdf" + }, + { + "name": "visibility-script-revert", + "pages": 1, + "text": "Document AAA\nBefore\nAfter", + "probes": [], + "pdfSha256": "941b22bd5f30bf0f3a46faa6d749ee865eb785dfa623089f3dad0fe7d14a61f7", + "previewSha256": "fc257aa698b0ae28303656ea66ac3efd25542c0d9626f07b19a64b3f8f28920b", + "suggestedFilename": "invoice-VUE-2042.pdf" + }, + { + "name": "visibility-script-inline-paragraph", + "pages": 1, + "text": "Document AAA\nBefore SOURCE_SENTINEL After", + "probes": [], + "pdfSha256": "0ff638f747481f71797696ff4b0c191b4505ca6bb9bf13fb073822d0c59f2947", + "previewSha256": "44483eea283bae46fdd816f2784cef751d5ab48bd01f34043366fb9ccedea8ac", + "suggestedFilename": "invoice-VUE-2042.pdf" + }, + { + "name": "decoration-inter-40-underline-font", + "pages": 1, + "text": "Invoice AAA HHH", + "probes": [], + "strokeWidthsPt": [ + 2.051 + ], + "pdfSha256": "8c431024572d470f85ce6b82cec990ad7b34d3aed8e77760d5ee378a1bf1f25c", + "previewSha256": "4195165f1f347b30610440c5419b8c0e3a6c7a52c86142e54a47bf5ddba1ac1a", + "suggestedFilename": "invoice-VUE-2042.pdf" + }, + { + "name": "decoration-inter-40-underline-length", + "pages": 1, + "text": "Invoice AAA HHH", + "probes": [], + "strokeWidthsPt": [ + 2.051 + ], + "pdfSha256": "8c431024572d470f85ce6b82cec990ad7b34d3aed8e77760d5ee378a1bf1f25c", + "previewSha256": "4195165f1f347b30610440c5419b8c0e3a6c7a52c86142e54a47bf5ddba1ac1a", + "suggestedFilename": "invoice-VUE-2042.pdf" + }, + { + "name": "decoration-inter-40-underline-auto", + "pages": 1, + "text": "Invoice AAA HHH", + "probes": [], + "strokeWidthsPt": [ + 3.0 + ], + "pdfSha256": "bdf2de5e5f1a102aa2b81a931eb35517cba323136742572fae95eb134f5b13bd", + "previewSha256": "903ba24e63b532b16d8e8571ae634bfbc6455c36b4618d5447f1b928bca43ee1", + "suggestedFilename": "invoice-VUE-2042.pdf" + } + ] + } + }, + "nextjs": { + "node": "v22.23.3", + "platform": "win32", + "next": "16.3.8", + "isolation": "process", + "packageLockSha256": "a48102d9affaa7d6f424b69835ea837737848abcfd321c8f5f12db88ad63de94", + "pages": 1, + "pdfSha256": "3078d155f30536f5ad721f7be3c241cd78661ae41249131fc0fd65f37f23e408", + "checks": [ + { + "name": "standalone artifact is isolated from the source application", + "passed": true + }, + { + "name": "standalone tracing retains the verified engine and all bundled fonts", + "passed": true + }, + { + "name": "isolated production server starts on loopback", + "passed": true + }, + { + "name": "app exposes the sample download without a prefetched render", + "passed": true + }, + { + "name": "standalone server includes the actual PDF preview asset", + "passed": true + }, + { + "name": "production route returns complete private PDF bytes with a useful filename", + "passed": true + }, + { + "name": "unknown invoice IDs return a private JSON error", + "passed": true + }, + { + "name": "unsupported writes are rejected by the route", + "passed": true + }, + { + "name": "a concurrent burst receives explicit capacity errors instead of an unbounded queue", + "passed": true + }, + { + "name": "normal PDF downloads recover after a capacity burst", + "passed": true + }, + { + "name": "a real missing-glyph failure returns a generic non-PDF error", + "passed": true + }, + { + "name": "a valid document renders after an engine failure", + "passed": true + }, + { + "name": "the route enforces its page cap against a real multipage document", + "passed": true + }, + { + "name": "a valid document renders after the page limit rejects a job", + "passed": true + }, + { + "name": "a failed render child returns an HTTP error while the production server stays alive", + "passed": true + }, + { + "name": "the production server returns a valid PDF after a render-process failure", + "passed": true + }, + { + "name": "client JavaScript excludes the server PDF engine and worker", + "passed": true + } + ] + }, + "fixturesSha256": "0ec4c2e4c137ed5519b3a0d55b74d95653826e6423cc5af3f7e41ca5b99cac8e", + "scope": "Fresh published-package installations, Chrome editor/PDF downloads, and isolated Next.js production HTTP checks. Firefox, WebKit and React StrictMode are CI gates; no hosted-provider, authentication, universal CSS or conformance claim." +}