diff --git a/examples/browser/README.md b/examples/browser/README.md index aed0cc2..711dd04 100644 --- a/examples/browser/README.md +++ b/examples/browser/README.md @@ -58,8 +58,8 @@ explains CSP, custom assets, structured errors, and browser worker lifecycle lim ## Versions and verification -The lockfile pins Fullbleed npm 0.3.0 / engine 2.5.8 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.3.0). +The lockfile pins Fullbleed npm 0.3.1 / engine 2.5.10 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.3.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 e279b7f..9861509 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.3.0" + "fullbleed": "0.3.1" }, "devDependencies": { "vite": "8.3.2" @@ -357,9 +357,9 @@ } }, "node_modules/fullbleed": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/fullbleed/-/fullbleed-0.3.0.tgz", - "integrity": "sha512-9HimnoHTEpgtGhqi9gF+IMSEW8g3GRK11yUkmL6OYD40D/RhWoIF7SqKuDs6nrHF7loWnhtNDWz3Hp/DNaBbMQ==", + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/fullbleed/-/fullbleed-0.3.1.tgz", + "integrity": "sha512-95CVTnYKduXD5KcEj9MLfzPsqofahZB2BsJ62Dfg0tOTlPFEHT8vx/T3f8xp4VQYkihOPQdMDiWQzYNHJkLpWA==", "license": "MIT", "dependencies": { "@bjorn3/browser_wasi_shim": "0.4.2" diff --git a/examples/browser/package.json b/examples/browser/package.json index 421a529..268bb13 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.3.0" }, + "dependencies": { "fullbleed": "0.3.1" }, "devDependencies": { "vite": "8.3.2" } } diff --git a/examples/browser/src/style.css b/examples/browser/src/style.css index 782b915..94ddfa0 100644 --- a/examples/browser/src/style.css +++ b/examples/browser/src/style.css @@ -1,5 +1,5 @@ /* Match the pinned renderer's URL so the page and worker can share the cached font. */ -@font-face{font-family:Inter;src:url('/fullbleed/fonts/Inter-Variable.ttf?v=0.3.0') format('truetype');font-weight:100 900;font-display:swap} +@font-face{font-family:Inter;src:url('/fullbleed/fonts/Inter-Variable.ttf?v=0.3.1') format('truetype');font-weight:100 900;font-display:swap} :root{font-family:Inter,sans-serif;color:#173b35;background:#f6f5ef;font-synthesis:none;font-size:15px;line-height:1.5} *{box-sizing:border-box}body{margin:0}button,input,select{font:inherit}button,a,input,select{touch-action:manipulation}a{color:inherit}a:focus-visible,button:focus-visible,input:focus-visible,select:focus-visible{outline:3px solid #d45d34;outline-offset:4px} .site-header{max-width:1440px;margin:auto;padding:22px 5vw;display:flex;align-items:center;gap:28px;border-bottom:1px solid #d8ded5}.wordmark{font-weight:850;font-size:29px;letter-spacing:-1.6px;text-decoration:none}.wordmark span{color:#d85330}.header-note{font-size:10px;letter-spacing:2px;font-weight:700;margin-left:8px}.docs-link{margin-left:auto;text-decoration:none;font-size:13px;font-weight:650}.docs-link span{margin-left:10px} diff --git a/examples/nextjs/README.md b/examples/nextjs/README.md index 5adac21..1e4e607 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.2.0 -(engine 2.5.8) 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.3.1 +(engine 2.5.10) 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 73e11af..3abb592 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.2.0", + "fullbleed": "0.3.1", "next": "16.3.8", "react": "19.3.0", "react-dom": "19.3.0" @@ -787,13 +787,16 @@ } }, "node_modules/fullbleed": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/fullbleed/-/fullbleed-0.2.0.tgz", - "integrity": "sha512-7khp008/oaJxMbroCQuv82ICOnJVQ1RUgYsOZWAqcW92qjKEAVzRK80UZDIJkNWcaMh1yDdTR8BJ5PAFc3QbnA==", + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/fullbleed/-/fullbleed-0.3.1.tgz", + "integrity": "sha512-95CVTnYKduXD5KcEj9MLfzPsqofahZB2BsJ62Dfg0tOTlPFEHT8vx/T3f8xp4VQYkihOPQdMDiWQzYNHJkLpWA==", "license": "MIT", "dependencies": { "@bjorn3/browser_wasi_shim": "0.4.2" }, + "bin": { + "fullbleed-browser-assets": "src/copy-browser-assets.cjs" + }, "engines": { "node": ">=22" } diff --git a/examples/nextjs/package.json b/examples/nextjs/package.json index 23ca97f..039412e 100644 --- a/examples/nextjs/package.json +++ b/examples/nextjs/package.json @@ -16,7 +16,7 @@ "verify": "node tools/verify.mjs" }, "dependencies": { - "fullbleed": "0.2.0", + "fullbleed": "0.3.1", "next": "16.3.8", "react": "19.3.0", "react-dom": "19.3.0" diff --git a/examples/nextjs/public/invoice.png b/examples/nextjs/public/invoice.png index 82d648f..5918b8c 100644 Binary files a/examples/nextjs/public/invoice.png and b/examples/nextjs/public/invoice.png differ diff --git a/examples/react/README.md b/examples/react/README.md index 6d9684e..8600205 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.3.0`, and copy the runtime with +`fullbleed@0.3.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.3.0 / engine 2.5.8, React 19.3.0, TypeScript 7.0.2, +The lockfile pins Fullbleed 0.3.1 / engine 2.5.10, 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 eb968fd..e44d28c 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.3.0", + "fullbleed": "0.3.1", "react": "19.3.0", "react-dom": "19.3.0" }, @@ -760,9 +760,9 @@ } }, "node_modules/fullbleed": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/fullbleed/-/fullbleed-0.3.0.tgz", - "integrity": "sha512-9HimnoHTEpgtGhqi9gF+IMSEW8g3GRK11yUkmL6OYD40D/RhWoIF7SqKuDs6nrHF7loWnhtNDWz3Hp/DNaBbMQ==", + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/fullbleed/-/fullbleed-0.3.1.tgz", + "integrity": "sha512-95CVTnYKduXD5KcEj9MLfzPsqofahZB2BsJ62Dfg0tOTlPFEHT8vx/T3f8xp4VQYkihOPQdMDiWQzYNHJkLpWA==", "license": "MIT", "dependencies": { "@bjorn3/browser_wasi_shim": "0.4.2" diff --git a/examples/react/package.json b/examples/react/package.json index 9c275d0..08ae981 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.3.0", + "fullbleed": "0.3.1", "react": "19.3.0", "react-dom": "19.3.0" }, diff --git a/examples/react/src/style.css b/examples/react/src/style.css index 50f3cfe..d98c5a6 100644 --- a/examples/react/src/style.css +++ b/examples/react/src/style.css @@ -1,5 +1,5 @@ /* Match the pinned renderer's URL so the page and worker can share the cached font. */ -@font-face{font-family:Inter;src:url('/fullbleed/fonts/Inter-Variable.ttf?v=0.3.0') format('truetype');font-weight:100 900;font-display:swap} +@font-face{font-family:Inter;src:url('/fullbleed/fonts/Inter-Variable.ttf?v=0.3.1') format('truetype');font-weight:100 900;font-display:swap} :root{font-family:Inter,sans-serif;color:#173b35;background:#f6f5ef;font-synthesis:none;font-size:15px;line-height:1.5} *{box-sizing:border-box}body{margin:0}button,input,select{font:inherit}button,a,input,select{touch-action:manipulation}a{color:inherit}a:focus-visible,button:focus-visible,input:focus-visible,select:focus-visible{outline:3px solid #d45d34;outline-offset:4px} .site-header{max-width:1440px;margin:auto;padding:22px 5vw;display:flex;align-items:center;gap:28px;border-bottom:1px solid #d8ded5}.wordmark{font-weight:850;font-size:29px;letter-spacing:-1.6px;text-decoration:none}.wordmark span{color:#d85330}.header-note{font-size:10px;letter-spacing:2px;font-weight:700;margin-left:8px}.docs-link{margin-left:auto;text-decoration:none;font-size:13px;font-weight:650}.docs-link span{margin-left:10px} diff --git a/verification/starters-031.json b/verification/starters-031.json new file mode 100644 index 0000000..d5e36b3 --- /dev/null +++ b/verification/starters-031.json @@ -0,0 +1,802 @@ +{ + "ok": true, + "checked_at": "2026-10-06T12:43:35.372965+00:00", + "package_version": "0.3.1", + "engine_version": "2.5.10", + "source_files": { + "examples/browser/.gitignore": "c023fec2bf12476cb47709e859f1fbb785aeb1e03281e52141e0bee1ee7dad72", + "examples/browser/LICENSE": "36a2115938f6e68cf0d87eccff7a6a3e57c17017e909cbd640d51aff1fa0c5a9", + "examples/browser/README.md": "886bb0ea403780834262b4432a4b866671098fb1f7074524007bc37dccab4a1d", + "examples/browser/index.html": "79baecb0b24716e78799893fc0076d88b2c026354f9f31acdf799c8f305c954b", + "examples/browser/package-lock.json": "16e4f019872bd1cd5f2a743769f3ec958f9aa78901b6f2f3fd2816e613369346", + "examples/browser/package.json": "36df50538f36f3dc9086e03d0777183c5b2bce508801f0d7c00ef21e23806f6d", + "examples/browser/public/favicon.svg": "3eed6dcf1013e48bc64886fed4cf815c609ed06b404742bdacdc44c1df8d3118", + "examples/browser/src/invoice.css": "0b310ce0f2964fd6b9b68e4afafa9307b4ff8c6b2f1fc753367dc755620ce427", + "examples/browser/src/invoice.html": "1f065ad6694021649e61b3f666cba6dc01aacdcbd8e80e97425b383e60d7d2fe", + "examples/browser/src/main.js": "10312b7064b0b2c19d97194b3953f639cc1f6842c35acf85f5e9543fa9c1d27f", + "examples/browser/src/report.css": "519591ae75c239ec602324f008dd99108ebeae0b9306df7215fa5f0442905473", + "examples/browser/src/report.html": "46b0e975d43914c8b4492218feae09ea0ad684091a9f9ee3b18f66a87202e521", + "examples/browser/src/style.css": "5005045f66a84a038a0f7a0f7e15b8b5e9eac2489f9717d4a581fec5075bf6f4", + "examples/browser/vite.config.js": "ec725922705a3c5ba2df191a564c54c0cac6e8997ecd3d00b8a42c647bec8e74", + "examples/nextjs/.gitignore": "b4abc38d76926640e3f2cbe3bf25c8f5aec6cc43dd978c48d3ad5cc20d964f66", + "examples/nextjs/LICENSE": "36a2115938f6e68cf0d87eccff7a6a3e57c17017e909cbd640d51aff1fa0c5a9", + "examples/nextjs/README.md": "0b47cb42317df65f497447bb1084c888194886f82e5223960ed2ecaa55b22273", + "examples/nextjs/app/api/invoices/[id]/route.js": "d6348ce64b44feac7010e21fb0f55723e0858c7867222ae831c45d3440a3b052", + "examples/nextjs/app/globals.css": "02e0b545a14eaf15e6d3d8fc8c0e8c0f1c5ce5c1b8dc461b4343d330f291233e", + "examples/nextjs/app/layout.js": "2df89bff0d2f002b432b3fdb73fd64edf59c57641d9ea6df3f0051cf2329cf27", + "examples/nextjs/app/page.js": "24c7996f8172992f925cdb1e47455d0095397d0832f747c90ecb409f2a1d460c", + "examples/nextjs/lib/invoice.mjs": "fd87dd082fa19659ec572d97255c1902e1e728e43ebbc3e0ade9891fa7736cf2", + "examples/nextjs/next.config.mjs": "e93613419f5aaa6264f0405e5afbb6f5eea4c956e42e7ebf30a6c85a4d9d89b3", + "examples/nextjs/package-lock.json": "57dfea0b9c49f604477b28c88847764bda16c006383df852269bdd2b712daf43", + "examples/nextjs/package.json": "7e52578d679fa9422b15cf5a69fa065d7b6c68d076362ddfc4e885134dfd5766", + "examples/nextjs/public/invoice.png": "72420749ccc3deaa8025daf7baffcdf79be716b6e8e93ed605effebed01e86c7", + "examples/nextjs/templates/invoice.css": "cda22b39ab1f7a1eeac7cd76d162b05cd3568c2430c099123ba30a2fbd58a296", + "examples/nextjs/templates/invoice.html": "d9a5b1950ddab61f08628b0fcc773cb36f05d9401bb3d87273bca02452b1835e", + "examples/nextjs/tools/copy-public.mjs": "25005e2612d90ed5127f268144c45bcd259ceb1e68c832723549e57a06b8d3dd", + "examples/nextjs/tools/render-preview.mjs": "0e5f1c0e49e2ec35a77eec460d735a1228ae82a30b86a7eb687af4056c23522b", + "examples/nextjs/tools/start.mjs": "4c185a0801ca4f89a30a0c1e75710f1c22c84463d29477900162b05a8bc52eab", + "examples/nextjs/tools/verify.mjs": "54623914ff28a47ea63a553d063ac50a206df0424270dacb3f3a99054982a888", + "examples/react/.gitignore": "25d896ffa2be7ed008ad87c3956a0a88f54167d04a7cef5cf774d6989d3b5a7b", + "examples/react/LICENSE": "36a2115938f6e68cf0d87eccff7a6a3e57c17017e909cbd640d51aff1fa0c5a9", + "examples/react/README.md": "098a1ce15c586d7b3d3a5a459ac107230a2cbae3422f55916040a79a027e009f", + "examples/react/index.html": "cadf48a3476088b2efbe9012bb4b2d21fa24f1dd3e99f974f444c88fbf1ee165", + "examples/react/package-lock.json": "e38b0d8775b14bc62ad99cb4b5f518fbf5c797ab208e5cf184d5e4c39a0f0e72", + "examples/react/package.json": "14cb9c05cccdc589f09f8281fdd7b92345aba5e15e0ffbbfa93230deef94861f", + "examples/react/public/favicon.svg": "3eed6dcf1013e48bc64886fed4cf815c609ed06b404742bdacdc44c1df8d3118", + "examples/react/src/App.tsx": "5dbcd45d570a3e4d69f12237d252e30afe71f52cb8411c3ffe094dc72f559b9f", + "examples/react/src/invoice.css": "0b310ce0f2964fd6b9b68e4afafa9307b4ff8c6b2f1fc753367dc755620ce427", + "examples/react/src/invoice.html": "1f065ad6694021649e61b3f666cba6dc01aacdcbd8e80e97425b383e60d7d2fe", + "examples/react/src/main.tsx": "f8f523ef5fc0b1e4095830466e0caa648c01f7b42036694b800c25d43d5e2c84", + "examples/react/src/report.css": "519591ae75c239ec602324f008dd99108ebeae0b9306df7215fa5f0442905473", + "examples/react/src/report.html": "46b0e975d43914c8b4492218feae09ea0ad684091a9f9ee3b18f66a87202e521", + "examples/react/src/style.css": "940621b782b9e39fc48f5a257c119763e11cedd158fb570a82f483ea20aa9951", + "examples/react/src/usePdfPreview.ts": "587e8702bd32f42abe2720f9d29dcc68e6d75aba8cb3ceacbdfcf2b583f378cc", + "examples/react/tsconfig.json": "382c3c4a68901c016c3038c9653f1adaf145738c68de40a34821181ead2d7289", + "examples/react/vite.config.js": "4b74d0189e7f58a4c75d168367e9b8a53000555dd3de594c497f70fb5e02fff0" + }, + "browsers": [ + { + "starter": "browser", + "browser_engine": "chrome", + "browser": "154.0.8037.98", + "playwright": "1.63.0", + "pypdf": "6.19.0", + "checks": [ + "runtime resolves beneath a nested deployment path", + "bundled UI font loads", + "invoice: download has the expected pages and text", + "1440px: no horizontal overflow", + "390px: no horizontal overflow", + "320px: no horizontal overflow", + "color-only: download has the expected pages and text", + "changing only ink color changes the rendered PDF", + "changed inputs clear the previous preview", + "customized: download has the expected pages and text", + "customized bytes differ from the default invoice", + "edited: download has the expected pages and text", + "edited print CSS changes the PDF page size", + "document script does not run on the page", + "report: download has the expected pages and text", + "multi-page preview displays all report pages", + "each design preserves its template edits", + "reset restores only the selected template", + "invalid input displays an error without a stale download", + "cancellation restores controls without a stale download", + "recovered: download has the expected pages and text", + "no document uploads or cross-origin runtime requests", + "no uncaught page errors" + ], + "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": "0b02622b41ec3c796ad1cae117c90d4a47c7792a3941b984165e896a467b0ae2" + }, + { + "name": "report", + "filename": "community-report.pdf", + "pages": 3, + "sha256": "139df89824e6a73c13ff62f1237bb8eb9f71e790dcbd051b1bb713ed2bc47802" + }, + { + "name": "recovered", + "filename": "invoice-TEST-2042.pdf", + "pages": 1, + "sha256": "31ff314b44a6f13534cc383e0cf24929f0695c1dd3d84769dedf8828c6486a93" + } + ], + "page_errors": [], + "csp": "default-src 'none'; script-src 'self' 'wasm-unsafe-eval'; worker-src 'self'; connect-src 'self'; img-src 'self' blob:; font-src 'self'; style-src 'self'; object-src 'none'; base-uri 'none'" + }, + { + "starter": "browser", + "browser_engine": "firefox", + "browser": "155.0", + "playwright": "1.63.0", + "pypdf": "6.19.0", + "checks": [ + "runtime resolves beneath a nested deployment path", + "bundled UI font loads", + "invoice: download has the expected pages and text", + "1440px: no horizontal overflow", + "390px: no horizontal overflow", + "320px: no horizontal overflow", + "color-only: download has the expected pages and text", + "changing only ink color changes the rendered PDF", + "changed inputs clear the previous preview", + "customized: download has the expected pages and text", + "customized bytes differ from the default invoice", + "edited: download has the expected pages and text", + "edited print CSS changes the PDF page size", + "document script does not run on the page", + "report: download has the expected pages and text", + "multi-page preview displays all report pages", + "each design preserves its template edits", + "reset restores only the selected template", + "invalid input displays an error without a stale download", + "cancellation restores controls without a stale download", + "recovered: download has the expected pages and text", + "no document uploads or cross-origin runtime requests", + "no uncaught page errors" + ], + "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": "0b02622b41ec3c796ad1cae117c90d4a47c7792a3941b984165e896a467b0ae2" + }, + { + "name": "report", + "filename": "community-report.pdf", + "pages": 3, + "sha256": "139df89824e6a73c13ff62f1237bb8eb9f71e790dcbd051b1bb713ed2bc47802" + }, + { + "name": "recovered", + "filename": "invoice-TEST-2042.pdf", + "pages": 1, + "sha256": "31ff314b44a6f13534cc383e0cf24929f0695c1dd3d84769dedf8828c6486a93" + } + ], + "page_errors": [], + "csp": "default-src 'none'; script-src 'self' 'wasm-unsafe-eval'; worker-src 'self'; connect-src 'self'; img-src 'self' blob:; font-src 'self'; style-src 'self'; object-src 'none'; base-uri 'none'" + }, + { + "starter": "browser", + "browser_engine": "webkit", + "browser": "26.6", + "playwright": "1.63.0", + "pypdf": "6.19.0", + "checks": [ + "runtime resolves beneath a nested deployment path", + "bundled UI font loads", + "invoice: download has the expected pages and text", + "1440px: no horizontal overflow", + "390px: no horizontal overflow", + "320px: no horizontal overflow", + "color-only: download has the expected pages and text", + "changing only ink color changes the rendered PDF", + "changed inputs clear the previous preview", + "customized: download has the expected pages and text", + "customized bytes differ from the default invoice", + "edited: download has the expected pages and text", + "edited print CSS changes the PDF page size", + "document script does not run on the page", + "report: download has the expected pages and text", + "multi-page preview displays all report pages", + "each design preserves its template edits", + "reset restores only the selected template", + "invalid input displays an error without a stale download", + "cancellation restores controls without a stale download", + "recovered: download has the expected pages and text", + "no document uploads or cross-origin runtime requests", + "no uncaught page errors" + ], + "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": "0b02622b41ec3c796ad1cae117c90d4a47c7792a3941b984165e896a467b0ae2" + }, + { + "name": "report", + "filename": "community-report.pdf", + "pages": 3, + "sha256": "139df89824e6a73c13ff62f1237bb8eb9f71e790dcbd051b1bb713ed2bc47802" + }, + { + "name": "recovered", + "filename": "invoice-TEST-2042.pdf", + "pages": 1, + "sha256": "31ff314b44a6f13534cc383e0cf24929f0695c1dd3d84769dedf8828c6486a93" + } + ], + "page_errors": [], + "csp": "default-src 'none'; script-src 'self' 'wasm-unsafe-eval'; worker-src 'self'; connect-src 'self'; img-src 'self' blob:; font-src 'self'; style-src 'self'; object-src 'none'; base-uri 'none'" + }, + { + "starter": "react", + "browser_engine": "chrome", + "browser": "154.0.8037.98", + "react_mode": "production", + "playwright": "1.63.0", + "pypdf": "6.19.0", + "checks": [ + "invoice: real PDF has expected pages and text", + "invoice matches the installed Node package", + "initial automatic render starts one worker", + "settled render terminates its worker", + "runtime resolves beneath a nested deployment path", + "bundled interface font loads", + "1440px: no horizontal overflow", + "390px: no horizontal overflow", + "320px: no horizontal overflow", + "on-demand mode does not schedule a render after edits", + "manual: real PDF has expected pages and text", + "automatic rendering can be re-enabled", + "edits immediately hide the old preview and release its URLs", + "latest-input: real PDF has expected pages and text", + "superseded render cannot overwrite the latest input", + "a burst of edits is debounced into one new worker", + "replacement does not overlap active worker handles", + "only current PDF and preview URLs remain", + "edited-template: real PDF has expected pages and text", + "edited print CSS changes the page size", + "document scripts are not executed in the app", + "report: real PDF has expected pages and text", + "report matches the installed Node package", + "all report pages have previews", + "each design preserves its template edits", + "invalid input cannot leave an old download", + "cancel removes the worker and stale download", + "recovered: real PDF has expected pages and text", + "unmount releases ready PDF and preview URLs", + "unmount aborts a pending worker", + "remounted: real PDF has expected pages and text", + "remount starts from clean state and recovers", + "all created URLs and workers are released at final unmount", + "no uploads or cross-origin document requests", + "no uncaught page errors" + ], + "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": "62915a0cdcb14fa64e8a636077b94b252c8eb63ed893b65440046fc0b1456a88" + }, + { + "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" + } + ], + "lifecycle": { + "started": 12, + "terminated": 12, + "peak": 1, + "created": 20, + "revoked": 20, + "live": 0, + "urls": 0 + }, + "page_errors": [], + "csp": "default-src 'none'; script-src 'self' 'wasm-unsafe-eval'; worker-src 'self'; connect-src 'self'; img-src 'self' blob:; font-src 'self'; style-src 'self'; object-src 'none'; base-uri 'none'" + }, + { + "starter": "react", + "browser_engine": "firefox", + "browser": "155.0", + "react_mode": "production", + "playwright": "1.63.0", + "pypdf": "6.19.0", + "checks": [ + "invoice: real PDF has expected pages and text", + "invoice matches the installed Node package", + "initial automatic render starts one worker", + "settled render terminates its worker", + "runtime resolves beneath a nested deployment path", + "bundled interface font loads", + "1440px: no horizontal overflow", + "390px: no horizontal overflow", + "320px: no horizontal overflow", + "on-demand mode does not schedule a render after edits", + "manual: real PDF has expected pages and text", + "automatic rendering can be re-enabled", + "edits immediately hide the old preview and release its URLs", + "latest-input: real PDF has expected pages and text", + "superseded render cannot overwrite the latest input", + "a burst of edits is debounced into one new worker", + "replacement does not overlap active worker handles", + "only current PDF and preview URLs remain", + "edited-template: real PDF has expected pages and text", + "edited print CSS changes the page size", + "document scripts are not executed in the app", + "report: real PDF has expected pages and text", + "report matches the installed Node package", + "all report pages have previews", + "each design preserves its template edits", + "invalid input cannot leave an old download", + "cancel removes the worker and stale download", + "recovered: real PDF has expected pages and text", + "unmount releases ready PDF and preview URLs", + "unmount aborts a pending worker", + "remounted: real PDF has expected pages and text", + "remount starts from clean state and recovers", + "all created URLs and workers are released at final unmount", + "no uploads or cross-origin document requests", + "no uncaught page errors" + ], + "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": "62915a0cdcb14fa64e8a636077b94b252c8eb63ed893b65440046fc0b1456a88" + }, + { + "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" + } + ], + "lifecycle": { + "started": 12, + "terminated": 12, + "peak": 1, + "created": 20, + "revoked": 20, + "live": 0, + "urls": 0 + }, + "page_errors": [], + "csp": "default-src 'none'; script-src 'self' 'wasm-unsafe-eval'; worker-src 'self'; connect-src 'self'; img-src 'self' blob:; font-src 'self'; style-src 'self'; object-src 'none'; base-uri 'none'" + }, + { + "starter": "react", + "browser_engine": "webkit", + "browser": "26.6", + "react_mode": "production", + "playwright": "1.63.0", + "pypdf": "6.19.0", + "checks": [ + "invoice: real PDF has expected pages and text", + "invoice matches the installed Node package", + "initial automatic render starts one worker", + "settled render terminates its worker", + "runtime resolves beneath a nested deployment path", + "bundled interface font loads", + "1440px: no horizontal overflow", + "390px: no horizontal overflow", + "320px: no horizontal overflow", + "on-demand mode does not schedule a render after edits", + "manual: real PDF has expected pages and text", + "automatic rendering can be re-enabled", + "edits immediately hide the old preview and release its URLs", + "latest-input: real PDF has expected pages and text", + "superseded render cannot overwrite the latest input", + "a burst of edits is debounced into one new worker", + "replacement does not overlap active worker handles", + "only current PDF and preview URLs remain", + "edited-template: real PDF has expected pages and text", + "edited print CSS changes the page size", + "document scripts are not executed in the app", + "report: real PDF has expected pages and text", + "report matches the installed Node package", + "all report pages have previews", + "each design preserves its template edits", + "invalid input cannot leave an old download", + "cancel removes the worker and stale download", + "recovered: real PDF has expected pages and text", + "unmount releases ready PDF and preview URLs", + "unmount aborts a pending worker", + "remounted: real PDF has expected pages and text", + "remount starts from clean state and recovers", + "all created URLs and workers are released at final unmount", + "no uploads or cross-origin document requests", + "no uncaught page errors" + ], + "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": "62915a0cdcb14fa64e8a636077b94b252c8eb63ed893b65440046fc0b1456a88" + }, + { + "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" + } + ], + "lifecycle": { + "started": 12, + "terminated": 12, + "peak": 1, + "created": 20, + "revoked": 20, + "live": 0, + "urls": 0 + }, + "page_errors": [], + "csp": "default-src 'none'; script-src 'self' 'wasm-unsafe-eval'; worker-src 'self'; connect-src 'self'; img-src 'self' blob:; font-src 'self'; style-src 'self'; object-src 'none'; base-uri 'none'" + }, + { + "starter": "react", + "browser_engine": "chrome", + "browser": "154.0.8037.98", + "react_mode": "development StrictMode", + "playwright": "1.63.0", + "pypdf": "6.19.0", + "checks": [ + "invoice: real PDF has expected pages and text", + "invoice matches the installed Node package", + "initial automatic render starts one worker", + "settled render terminates its worker", + "runtime resolves beneath a nested deployment path", + "bundled interface font loads", + "1440px: no horizontal overflow", + "390px: no horizontal overflow", + "320px: no horizontal overflow", + "on-demand mode does not schedule a render after edits", + "manual: real PDF has expected pages and text", + "automatic rendering can be re-enabled", + "edits immediately hide the old preview and release its URLs", + "latest-input: real PDF has expected pages and text", + "superseded render cannot overwrite the latest input", + "a burst of edits is debounced into one new worker", + "replacement does not overlap active worker handles", + "only current PDF and preview URLs remain", + "edited-template: real PDF has expected pages and text", + "edited print CSS changes the page size", + "document scripts are not executed in the app", + "report: real PDF has expected pages and text", + "report matches the installed Node package", + "all report pages have previews", + "each design preserves its template edits", + "invalid input cannot leave an old download", + "cancel removes the worker and stale download", + "recovered: real PDF has expected pages and text", + "unmount releases ready PDF and preview URLs", + "unmount aborts a pending worker", + "remounted: real PDF has expected pages and text", + "remount starts from clean state and recovers", + "all created URLs and workers are released at final unmount", + "no uploads or cross-origin document requests", + "no uncaught page errors" + ], + "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": "62915a0cdcb14fa64e8a636077b94b252c8eb63ed893b65440046fc0b1456a88" + }, + { + "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" + } + ], + "lifecycle": { + "started": 12, + "terminated": 12, + "peak": 1, + "created": 20, + "revoked": 20, + "live": 0, + "urls": 0 + }, + "page_errors": [], + "csp": "default-src 'none'; script-src 'self' 'wasm-unsafe-eval'; worker-src 'self'; connect-src 'self'; img-src 'self' blob:; font-src 'self'; style-src 'self'; object-src 'none'; base-uri 'none'" + } + ], + "reviewed_layout": "test/fixtures/inline-layout-2.5.10.json", + "nextjs": { + "checkedAt": "2026-10-06T12:41:39.477Z", + "node": "v26.10.0", + "platform": "win32", + "next": "16.3.8", + "nodePackage": "0.3.1", + "engineVersion": "2.5.10", + "isolation": "process", + "packageLockSha256": "57dfea0b9c49f604477b28c88847764bda16c006383df852269bdd2b712daf43", + "base": "http://127.0.0.1:44208", + "standaloneFolder": "C:\\Users\\keena\\AppData\\Local\\Temp\\fullbleed-nextjs-jVN2EO", + "pages": 1, + "pdfSha256": "3078d155f30536f5ad721f7be3c241cd78661ae41249131fc0fd65f37f23e408", + "burst": [ + 200, + 503, + 503, + 503, + 503, + 503, + 503, + 503, + 503, + 503, + 503, + 503 + ], + "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 + } + ], + "scope": "Real next build standalone server with released Fullbleed npm package and fictional data; HTTP recovery after deliberate child failure. No hosted platform or application-authentication claim." + }, + "nextjs_browser": { + "ok": true, + "checked_at": "2026-10-06T12:42:59.420658+00:00", + "browser": "154.0.8037.98", + "checks": [ + { + "width": 1440, + "keyboard": false, + "pdf_sha256": "3078d155f30536f5ad721f7be3c241cd78661ae41249131fc0fd65f37f23e408", + "page_errors": [] + }, + { + "width": 390, + "keyboard": true, + "pdf_sha256": "3078d155f30536f5ad721f7be3c241cd78661ae41249131fc0fd65f37f23e408", + "page_errors": [] + }, + { + "width": 320, + "keyboard": false, + "pdf_sha256": "3078d155f30536f5ad721f7be3c241cd78661ae41249131fc0fd65f37f23e408", + "page_errors": [] + } + ], + "scope": "Owned anonymous Chrome; production Next.js standalone server; real downloads and responsive layouts." + }, + "scope": "Published npm package, locked starter builds, real browser downloads and isolated Next.js HTTP checks. Invoice/report match the retained core 2.5.10 layout. Synthetic data; no hosting-provider or standards conformance claim." +}