Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified docs/assets/nextjs/project.zip
Binary file not shown.
6 changes: 3 additions & 3 deletions docs/assets/nextjs/source.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
{
"sourceRepository": "https://github.com/fullbleed-engine/fullbleed-node",
"sourceCommit": "fe0fa10499428841ba3c0eac8571b5fc31b00fdc",
"sourceCommit": "4f574b5e11d3a680a50c561bf9ea071de29d0cb8",
"files": 18,
"assets": [
{
"file": "project.zip",
"sha256": "9a211e5553f81508c54c87ab52d02f498f17f0e2703eff088cfd440867969564",
"bytes": 104399
"sha256": "d6586c7b3d5f465fa08ac292b02c634b2ad649f0722616c47b5bc26cf751e157",
"bytes": 105014
},
{
"file": "invoice.pdf",
Expand Down
119 changes: 88 additions & 31 deletions docs/assets/nextjs/verification.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
{
"checkedAt": "2026-10-05T23:55:42.874759+00:00",
"checkedAt": "2026-10-06T01:06:26.050552+00:00",
"sourceRepository": "https://github.com/fullbleed-engine/fullbleed-node",
"sourceCommit": "fe0fa10499428841ba3c0eac8571b5fc31b00fdc",
"mergedCommit": "39062ed78bde8cca2bb73842e6c04b0dc6531a71",
"pullRequest": "https://github.com/fullbleed-engine/fullbleed-node/pull/15",
"ciRun": "https://github.com/fullbleed-engine/fullbleed-node/actions/runs/37279997939",
"sourceCommit": "4f574b5e11d3a680a50c561bf9ea071de29d0cb8",
"pullRequest": "https://github.com/fullbleed-engine/fullbleed-node/pull/17",
"ciRun": "https://github.com/fullbleed-engine/fullbleed-node/actions/runs/37397228563",
"standaloneChecks": [
{
"name": "standalone artifact is isolated from the source application",
Expand Down Expand Up @@ -62,21 +61,29 @@
"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
}
],
"ciResults": [
{
"artifact": "nextjs-ubuntu-latest-22",
"checkedAt": "2026-10-05T07:50:52.448Z",
"checkedAt": "2026-10-06T01:04:06.668Z",
"node": "v22.23.3",
"platform": "linux",
"next": "16.3.8",
"nodePackage": "0.1.5",
"nodePackage": "0.2.0",
"engineVersion": "2.5.8",
"packageLockSha256": "eb0b1ff6cf424cebf8464f44b38192a175465bcb77626a7645a18c85f3f0ce40",
"isolation": "process",
"packageLockSha256": "ceda9f7f9099fa91ab5a98d6ce8fd0ba4d2db761b46a19b412688f8db045c179",
"pages": 1,
"pdfSha256": "9d93174ed961bb2ef577f5f38d2836763b414edc53365f1a9c61e2b50d40f054",
"burst": [
Expand All @@ -93,17 +100,18 @@
503,
503
],
"checksPassed": 15
"artifact": "nextjs-ubuntu-latest-22",
"checksPassed": 17
},
{
"artifact": "nextjs-ubuntu-latest-24",
"checkedAt": "2026-10-05T07:50:44.440Z",
"checkedAt": "2026-10-06T01:04:06.836Z",
"node": "v24.21.0",
"platform": "linux",
"next": "16.3.8",
"nodePackage": "0.1.5",
"nodePackage": "0.2.0",
"engineVersion": "2.5.8",
"packageLockSha256": "eb0b1ff6cf424cebf8464f44b38192a175465bcb77626a7645a18c85f3f0ce40",
"isolation": "process",
"packageLockSha256": "ceda9f7f9099fa91ab5a98d6ce8fd0ba4d2db761b46a19b412688f8db045c179",
"pages": 1,
"pdfSha256": "9d93174ed961bb2ef577f5f38d2836763b414edc53365f1a9c61e2b50d40f054",
"burst": [
Expand All @@ -120,17 +128,18 @@
503,
503
],
"checksPassed": 15
"artifact": "nextjs-ubuntu-latest-24",
"checksPassed": 17
},
{
"artifact": "nextjs-windows-latest-24",
"checkedAt": "2026-10-05T07:51:41.715Z",
"checkedAt": "2026-10-06T01:04:28.012Z",
"node": "v24.21.0",
"platform": "win32",
"next": "16.3.8",
"nodePackage": "0.1.5",
"nodePackage": "0.2.0",
"engineVersion": "2.5.8",
"packageLockSha256": "eb0b1ff6cf424cebf8464f44b38192a175465bcb77626a7645a18c85f3f0ce40",
"isolation": "process",
"packageLockSha256": "ceda9f7f9099fa91ab5a98d6ce8fd0ba4d2db761b46a19b412688f8db045c179",
"pages": 1,
"pdfSha256": "9d93174ed961bb2ef577f5f38d2836763b414edc53365f1a9c61e2b50d40f054",
"burst": [
Expand All @@ -147,25 +156,22 @@
503,
503
],
"checksPassed": 15
"artifact": "nextjs-windows-latest-24",
"checksPassed": 17
}
],
"packageChecks": {
"run": "https://github.com/fullbleed-engine/fullbleed-node/actions/runs/37279997930",
"jobsPassed": 10,
"conclusion": "success"
},
"downloadVerification": {
"downloadedStarter": {
"ok": true,
"checkedAt": "2026-10-05T07:51:53.410802+00:00",
"sourceCommit": "fe0fa10499428841ba3c0eac8571b5fc31b00fdc",
"checkedAt": "2026-10-06T01:05:03.951160+00:00",
"sourceCommit": "4f574b5e11d3a680a50c561bf9ea071de29d0cb8",
"downloadFiles": 18,
"projectZipSha256": "9a211e5553f81508c54c87ab52d02f498f17f0e2703eff088cfd440867969564",
"projectZipSha256": "d6586c7b3d5f465fa08ac292b02c634b2ad649f0722616c47b5bc26cf751e157",
"node": "v22.23.3",
"platform": "win32",
"next": "16.3.8",
"nodePackage": "0.1.5",
"nodePackage": "0.2.0",
"engineVersion": "2.5.8",
"isolation": "process",
"commands": [
{
"name": "install",
Expand Down Expand Up @@ -243,12 +249,63 @@
"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": "Fresh public ZIP installation, production build, isolated standalone HTTP server, and exact sample-asset comparison. No application authentication or hosted-provider claim."
},
"scope": "Published npm 0.1.5 in the Next.js standalone starter. Three CI environments and a fresh downloadable ZIP install pass 15 HTTP/worker/error-recovery checks. The retained invoice PDF and preview match. No application authorization, hosting-provider, speed, or standards certification claim."
"browser": {
"ok": true,
"checked_at": "2026-10-06T01:05:29.710577+00:00",
"browser": "154.0.8037.98",
"isolation": "process",
"checks": [
{
"width": 1440,
"keyboard": false,
"layout": {
"width": 1440,
"documentWidth": 1440,
"bodyWidth": 1440
},
"pdf_sha256": "9d93174ed961bb2ef577f5f38d2836763b414edc53365f1a9c61e2b50d40f054",
"page_errors": []
},
{
"width": 390,
"keyboard": true,
"layout": {
"width": 390,
"documentWidth": 390,
"bodyWidth": 390
},
"pdf_sha256": "9d93174ed961bb2ef577f5f38d2836763b414edc53365f1a9c61e2b50d40f054",
"page_errors": []
},
{
"width": 320,
"keyboard": false,
"layout": {
"width": 320,
"documentWidth": 320,
"bodyWidth": 320
},
"pdf_sha256": "9d93174ed961bb2ef577f5f38d2836763b414edc53365f1a9c61e2b50d40f054",
"page_errors": []
}
],
"scope": "Independent headless Chrome and isolated Next standalone artifact; real PDF downloads, keyboard activation, narrow layouts. Existing authenticated browser sessions were not used."
},
"scope": "Published npm 0.2.0 with process isolation in the Next.js standalone starter. Three CI environments and a fresh downloadable ZIP install pass 17 HTTP/process/error-recovery checks. Real browser downloads match the retained invoice. No application authorization, hosted-provider, speed, or standards certification claim.",
"mergedCommit": "36a5b1d382c27d5a0f3414c732a88529e0bf5c7b"
}
18 changes: 9 additions & 9 deletions docs/assets/node/project.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
{
"package_version": "0.1.5",
"package_version": "0.2.0",
"engine_version": "2.5.8",
"source_commit": "847b943934ee050c735c712ffcaaff1d3d4c277e",
"package_url": "https://github.com/fullbleed-engine/fullbleed-node/releases/download/v0.1.5/fullbleed-0.1.5.tgz",
"package_integrity": "sha512-3AvPt+n2j/0KMoUk1rq/cu4dzcsnyUNKJNOwpUJkW48vkndFcroFtXgMx4CXJX46O2/gDSli67tuhUUiVsu5OQ==",
"package_sha256": "817e9ba5a4741b6626b62c5e829fdd921c0b69d1e165fb4905483d56887237dc",
"source_commit": "969f23c479cd02f366cc1d2e099b6bda19dfaac9",
"package_url": "https://github.com/fullbleed-engine/fullbleed-node/releases/download/v0.2.0/fullbleed-0.2.0.tgz",
"package_integrity": "sha512-7khp008/oaJxMbroCQuv82ICOnJVQ1RUgYsOZWAqcW92qjKEAVzRK80UZDIJkNWcaMh1yDdTR8BJ5PAFc3QbnA==",
"package_sha256": "90bd0bbf4ae542b6be1deb3103ba492b9d8675e47b71f895060b40419d705f4a",
"rendered": {
"invoice.pdf": "9d93174ed961bb2ef577f5f38d2836763b414edc53365f1a9c61e2b50d40f054",
"invoice.png": "b76f6db748fb47b928c93c12fe788de94a0f5d8da4bb350f644a58705c163cf7"
Expand All @@ -27,7 +27,7 @@
},
"README.md": {
"bytes": 902,
"sha256": "bc0a1e02e586dceb49ce48c5b08cbae46f840474a865b177ba0cc926ada55088"
"sha256": "98501bbbfe6844436d01f3d53cf7ea33c58910333734a981ff4ec599cc26f8ba"
},
"invoice.css": {
"bytes": 3546,
Expand All @@ -39,16 +39,16 @@
},
"package-lock.json": {
"bytes": 1075,
"sha256": "2432927cb75a10910107f41ff9e372dde8cbcf170588b07bd4948a066c71a24c"
"sha256": "9041f8e21fcde488123d7178b0d0f00b98b6e856141e2c0465ff914daf59d549"
},
"package.json": {
"bytes": 241,
"sha256": "07cdcec79b81d4f5dc9df229c0a97523ef1af7c32576adc6cd16c7673e1fce64"
"sha256": "6f638329f16f5dd22b767ce3784ce01ef219fcf7bb371261d0a28e0a2b3b5184"
},
"render.mjs": {
"bytes": 1064,
"sha256": "dd63e83658800df2672c8c5ca1b176dbe49fc0d5c49b8c2b79af91515a68e776"
}
},
"zip_sha256": "8b49592ad3a49d52ea27fc8eff14e013f9b63da201ca118e2138849f1fc5bcbb"
"zip_sha256": "3cdf9f3fb454dd269f4b2430eec7bd7ff468ce65d24e30f949c48ff4e39022a3"
}
Binary file modified docs/assets/node/project.zip
Binary file not shown.
60 changes: 48 additions & 12 deletions docs/getting-started/node.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,13 @@ Fullbleed's optional Node package renders static HTML/CSS into PDFs using a
bundled WebAssembly build of the Rust engine. It includes fonts and runs locally;
you do not need Python, Rust, or a browser to use the installed package.

This guide uses **Node package 0.1.5**, powered by **Fullbleed 2.5.8**. The
This guide uses **Node package 0.2.0**, powered by **Fullbleed 2.5.8**. The
integration and core engine have separate versions.

Version 0.2.0 adds optional process isolation for server applications. A failed
render child can reject its request while the caller keeps running. The engine
and default worker mode are unchanged from 0.1.5.

Version 0.1.5 fixes regular font selection when an italic face is registered first.
Use the actual family name for normal/italic CSS selection, or a PostScript name
for an explicit face. Review appearance and line breaks when upgrading; the
Expand All @@ -30,7 +34,7 @@ With Node.js 22 or newer, install the [npm package](https://www.npmjs.com/packag
npm install fullbleed
```

To pin this guide's version, use `npm install --save-exact fullbleed@0.1.5`.
To pin this guide's version, use `npm install --save-exact fullbleed@0.2.0`.
The npm package contains the same verified bytes as the GitHub release.

Save this as `invoice.mjs` and run `node invoice.mjs`:
Expand Down Expand Up @@ -88,7 +92,7 @@ of the finalized PDF. Fullbleed 2.5.5 fixes gradient fills that were missing fro
these PNG previews in earlier releases.

[Open the report PDF](../assets/node/report.pdf){ .md-button }
[Explore its HTML and CSS](https://github.com/fullbleed-engine/fullbleed-node/tree/v0.1.5/examples){ .md-button }
[Explore its HTML and CSS](https://github.com/fullbleed-engine/fullbleed-node/tree/v0.2.0/examples){ .md-button }

## Bring fonts and image assets

Expand All @@ -99,7 +103,7 @@ in CSS. Pass images through `assets`, mapping relative names to `Buffer` or

The engine uses an in-memory filesystem for the supplied inputs and does not
fetch remote URLs. Data URIs also work for document images. The
[package API reference](https://github.com/fullbleed-engine/fullbleed-node/tree/v0.1.5#fonts-and-assets)
[package API reference](https://github.com/fullbleed-engine/fullbleed-node/tree/v0.2.0#fonts-and-assets)
includes a complete font and asset example.

## Use it in an application
Expand All @@ -108,7 +112,7 @@ For a working web-app integration, use the [Next.js PDF download starter](../gui
It includes an App Router handler, designed invoice, bundled-asset configuration
and an isolated check of the production standalone server.

Rendering runs in a worker, with separate document state for concurrent calls.
By default, rendering runs in a worker, with separate document state for concurrent calls.
The promise waits for its worker to exit, including after failure, timeout, or
cancellation. Sequential `await renderPdf()` calls therefore do not overlap
worker lifetimes. A timeout or abort starts termination; the promise settles
Expand All @@ -124,13 +128,43 @@ rejected. Use registered font families: unavailable CSS families can fall back,
and the engine's glyph report does not establish visual correctness. Review the
final PDF and previews when adapting a design.

### Contain render-process failures

On a Node host that permits child processes, use `isolation: 'process'` to run
each request's engine and worker in a fresh process:

```javascript
const result = await renderPdf({
html: '<h1>Monthly statement</h1>',
isolation: 'process',
timeoutMs: 10_000,
maxPages: 20,
});
```

The caller does not compile WebAssembly or create render workers in this mode.
The promise waits for process exit and IPC disconnection before settling, even
after success. A failed child exit rejects with `PROCESS_FAILED`; available
`exitCode` and `signal` fields describe the exit. Timeouts and aborts terminate
the child before rejecting. A PDF received before a failed shutdown is not
returned as a successful result.

Process startup adds latency and memory use. There is no process pool or
automatic retry; keep concurrency bounded. Application startup flags and
`NODE_OPTIONS` are not replayed in the child. This option requires a normal
Node executable and is not an operating-system security sandbox. See the
[process isolation guide](https://github.com/fullbleed-engine/fullbleed-node/blob/v0.2.0/docs/process-isolation.md)
for deployment details and the tested failure paths. The Next.js starter uses
this mode for its PDF route.

An intermittent process crash on Linux with Node 24.21.0 was observed with
`fullbleed@0.1.2`; [issue #7](https://github.com/fullbleed-engine/fullbleed-node/issues/7)
remains open. Version 0.1.3 fixes worker shutdown timing, but has not established
that this native crash is resolved. See the
[runtime investigation](https://github.com/fullbleed-engine/fullbleed-node/blob/main/docs/runtime-diagnostics.md)
for the observed scope and synthetic diagnostic. A process crash can occur
before JavaScript can return an error.
before JavaScript can return an error in worker mode. Process isolation contains
tested child failures; it does not establish a fix for that native crash.

This first Node API covers ordinary PDF rendering and previews. Use the
[Python API](../engine/pdf-engine.md) or [Rust crate](rust.md) for profiles,
Expand All @@ -144,15 +178,17 @@ TypeScript. Its release evidence compares retained native and WebAssembly
fixtures and installs the same tarball across Node 22, 24, and 26 on Windows,
Linux, and macOS. These are scoped engineering checks, not PDF standards certification.

The [npm publication record](https://github.com/fullbleed-engine/fullbleed-node/releases/download/v0.1.5/npm-publication-0.1.5.json)
The [npm publication record](https://github.com/fullbleed-engine/fullbleed-node/releases/download/v0.2.0/npm-publication-0.2.0.json)
confirms the registry tarball matches that release. A fresh registry install on
Windows / Node 22 reproduces its PDF/PNG hashes, including ESM/CommonJS and
recovery after a cold timeout. Seven font fixtures also pass independent font,
text, and page-pixel checks against the registry-installed package. Ten custom-family
cases also match explicit-face controls; the same checker rejects the incorrect
0.1.4 result. [Inspect the family-selection evidence](https://github.com/fullbleed-engine/fullbleed-node/releases/download/v0.1.5/font-family-verification.json).
recovery after a cold timeout. The process consumer also forbids parent
WebAssembly and render workers, checks that application preloads stay out of
children, forces a child termination, and renders again. The release's CI
checks retain seven embedded-font fixtures and ten custom-family cases with
independent font, text, and page-pixel checks.
[Inspect the family-selection evidence](https://github.com/fullbleed-engine/fullbleed-node/releases/download/v0.2.0/font-family-verification.json).

[Package source and API](https://github.com/fullbleed-engine/fullbleed-node) ·
[npm package](https://www.npmjs.com/package/fullbleed) ·
[Versioned release and evidence](https://github.com/fullbleed-engine/fullbleed-node/releases/tag/v0.1.5) ·
[Versioned release and evidence](https://github.com/fullbleed-engine/fullbleed-node/releases/tag/v0.2.0) ·
[CSS coverage](../css-coverage.md) · [Examples](../examples.md)
Loading
Loading