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
13 changes: 11 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ jobs:
run: |
node tools/render-engine-regressions.mjs
python tools/verify-engine-regressions.py
- name: Verify hidden text and author display overrides in installed output
run: |
node tools/render-hidden-text.mjs
python tools/verify-hidden-text.py
- name: Verify inline wrapping from the installed package
run: |
npm run render:inline
Expand All @@ -60,7 +64,7 @@ jobs:
npm run render:fonts -- --package-root output/font-baseline-consumer/node_modules/fullbleed --out output/font-baseline
npm run verify:fonts -- --evidence-root output/font-baseline --allow-legacy-metadata
npm run render:fonts
npm run verify:fonts -- --baseline output/font-baseline --reviewed-layout test/fixtures/inline-layout-2.5.22.json
npm run verify:fonts -- --baseline output/font-baseline --reviewed-layout test/fixtures/inline-layout-2.5.24.json
- name: Verify installed custom font families against explicit faces
run: |
npm run render:families
Expand Down Expand Up @@ -103,6 +107,7 @@ jobs:
output/standard-baseline/
output/standard-fonts/
output/engine-regressions/
output/hidden-text/
retention-days: 7

installed:
Expand Down Expand Up @@ -143,7 +148,7 @@ jobs:
run: |
python -m pip install pypdf==6.19.0 pypdfium2==5.14.0 fonttools==4.65.0 pillow==12.3.0
npm run render:fonts
npm run verify:fonts -- --reviewed-layout test/fixtures/inline-layout-2.5.22.json
npm run verify:fonts -- --reviewed-layout test/fixtures/inline-layout-2.5.24.json
npm run render:families
npm run verify:families
npm run render:inline
Expand All @@ -152,6 +157,8 @@ jobs:
npm run verify:standard
node tools/render-engine-regressions.mjs
python tools/verify-engine-regressions.py
node tools/render-hidden-text.mjs
python tools/verify-hidden-text.py
- uses: actions/upload-artifact@v4
if: always() && matrix.os == 'windows-latest' && matrix.node == '22'
with:
Expand All @@ -162,6 +169,7 @@ jobs:
output/inline-wrapping/
output/standard-fonts/
output/engine-regressions/
output/hidden-text/
retention-days: 7
- uses: actions/upload-artifact@v4
if: always()
Expand Down Expand Up @@ -221,6 +229,7 @@ jobs:
timeout-minutes: 5
- run: python tools/check-browser.py --browser ${{ matrix.browser }} --label ci
- run: python tools/verify-engine-regressions.py output/browser-${{ matrix.browser }}-ci --browser
- run: python tools/verify-hidden-text.py output/browser-${{ matrix.browser }}-ci --browser
- uses: actions/upload-artifact@v4
if: always()
with:
Expand Down
14 changes: 11 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ also includes a ZIP for local development.
Using Vue? The [Vue and TypeScript starter](examples/vue) includes editable
templates, automatic previews, downloads, and a reusable `usePdfPreview` composable.

This is an optional integration around the published **Fullbleed 2.5.22** engine.
The package has its own version, **0.5.0**. Node applications can use a shared
This is an optional integration around the published **Fullbleed 2.5.24** engine.
The package has its own version, **0.5.1**. Node applications can use a shared
render queue to bound active renders and waiting requests, include queue time in
deadlines, cancel waiting jobs, and stop rendering cleanly during shutdown.
The browser entry renders in a Web Worker, and the Node API supports worker and
Expand All @@ -25,6 +25,14 @@ process isolation. See the [browser guide](docs/browser.md),
[font-family checks](https://github.com/fullbleed-engine/fullbleed-node/blob/main/docs/font-families.md), and
[embedded-font checks](https://github.com/fullbleed-engine/fullbleed-node/blob/main/docs/font-subsets.md) for the retained fixtures.

Version 0.5.1 brings the engine's hidden-text and font-decoration fixes to both
JavaScript entries. Script/style elements and `display:none` descendants stay
hidden, while explicit author display overrides remain supported. Font-selected
decoration thickness uses the selected face's metrics. The
[engine update checks](https://github.com/fullbleed-engine/fullbleed-node/blob/main/docs/engine-2.5.24.md)
cover source/control PDFs, font metrics, and browser downloads. Embedded
stylesheets are still ignored; supply template CSS through the `css` option.

Version 0.5.0 adds `defaultStyles: false` to both JavaScript entries. Use it to
preserve a template's original CSS, including font inheritance from `html`,
low-specificity selectors, and cascade layers. Existing calls keep the Inter
Expand All @@ -43,7 +51,7 @@ Use Node.js 22 or newer. Install the [npm package](https://www.npmjs.com/package
npm install fullbleed
```

For a version-pinned installation, use `npm install --save-exact fullbleed@0.5.0`.
For a version-pinned installation, use `npm install --save-exact fullbleed@0.5.1`.
Package archives and retained PDF/PNG evidence are attached to each
[GitHub release](https://github.com/fullbleed-engine/fullbleed-node/releases).
The [installation verification records](https://github.com/fullbleed-engine/fullbleed-node/tree/main/verification)
Expand Down
58 changes: 58 additions & 0 deletions docs/engine-2.5.24.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Engine 2.5.24 update checks

Version 0.5.1 wraps the unmodified published 2.5.24 crate. The checks below
cover the locked WebAssembly build, an isolated npm-tarball installation,
independent PDF readers, and actual browser downloads.

The update carries two fixes:

- Script/style elements are hidden by default, and ordinary `display:none`
descendants stay hidden in flattened paragraphs, lists, captions, and cells.
Author CSS can deliberately display source; `display:revert` restores the
default display value.
- `text-decoration-thickness: from-font` uses the selected font's preferred
thickness. Bundled Inter at 40px specifies 2.051pt; the previous engine used
the automatic 3pt stroke.

The [94 visible-content pairs](../test/fixtures/hidden-text-2.5.24.json) retain
control PDFs and finalized-preview expectations from the installed core
candidate. The published npm 0.5.0 package reproduces 77 affected pairs in each
Node isolation mode while preserving all control outputs.

The [24 decoration fixtures](../test/fixtures/decoration-thickness.json) cover
underlines, overlines, strike-throughs, and combinations at two sizes. fontTools
reads the bundled font's OpenType metrics, and pypdf measures emitted colored
stroke widths. The npm 0.5.0 negative control retains eight affected cases and
40 passing explicit-length, automatic, and small-text controls across both
isolation modes.

From a built checkout with verifier dependencies installed:

```sh
npm run verify:pack
node tools/render-hidden-text.mjs
python tools/verify-hidden-text.py
node tools/render-engine-regressions.mjs
python tools/verify-engine-regressions.py
npm run verify:native
npm run verify:browser:prepare
python tools/check-browser.py --browser chrome --label candidate
python tools/verify-hidden-text.py output/browser-chrome-candidate --browser
python tools/verify-engine-regressions.py output/browser-chrome-candidate --browser
```

CI repeats the browser download checks in Chrome, Firefox, and WebKit. Use a
fresh output directory for each retained run. The Node render tools accept
`--package-root` and `--out` for a separate installation. To reproduce the old
package's defects, use `render-hidden-text.mjs --negative-control`, or render
engine regressions with `--decoration-only` and verify them with
`verify-engine-regressions.py --negative-decoration-control`.

The publication gate requires both Windows and Linux evidence for the complete
fixture sets, all three browser reports, and native/WASI comparisons for every
source and control. It rejects stale fixture hashes, a different tarball,
negative-control reports, and incomplete coverage.

Independent PDFium source/control pixels are compared within each platform.
These checks do not claim identical PDFium rasterization across operating
systems, general browser pixel parity, or PDF standards conformance.
6 changes: 3 additions & 3 deletions engine/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions engine/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
[package]
name = "fullbleed-node-adapter"
version = "0.5.0"
version = "0.5.1"
edition = "2024"
license = "MIT"
publish = false

[dependencies]
fullbleed = { version = "=2.5.22", features = ["svg_raster"] }
fullbleed = { version = "=2.5.24", features = ["svg_raster"] }

[profile.release]
lto = true
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "fullbleed",
"version": "0.5.0",
"version": "0.5.1",
"description": "Generate PDFs from HTML and CSS in Node.js or a browser worker with the Fullbleed Rust engine, bundled fonts, and optional PNG previews.",
"type": "module",
"main": "./src/index.cjs",
Expand Down Expand Up @@ -77,7 +77,7 @@
"access": "public"
},
"fullbleed": {
"engineVersion": "2.5.22"
"engineVersion": "2.5.24"
},
"devDependencies": {
"@types/node": "22.20.5",
Expand Down
8 changes: 5 additions & 3 deletions test/engine-regressions.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@
import { readFile } from 'node:fs/promises';

export const engineRegressionSource = JSON.parse(await readFile(new URL('./fixtures/engine-2.5.22.json', import.meta.url), 'utf8'));
export const engineRegressionFixtures = engineRegressionSource.cases.map(({ name, pages, html, css, previewDpi, fontFiles = [] }) =>
export const decorationRegressionSource = JSON.parse(await readFile(new URL('./fixtures/decoration-thickness.json', import.meta.url), 'utf8'));
export const engineRegressionFixtures = [...engineRegressionSource.cases, ...decorationRegressionSource.cases].map(({ name, pages, html, css, previewDpi, fontFiles = [] }) =>
({ name, pages, html, css, previewDpi, fontFiles }));

export async function loadEngineRegressionFixtures() {
return Promise.all(engineRegressionFixtures.map(async ({ fontFiles, ...fixture }) => ({ ...fixture,
export async function loadEngineRegressionFixtures({ decorationOnly = false } = {}) {
const selected = decorationOnly ? engineRegressionFixtures.filter(fixture => fixture.name.startsWith('decoration-')) : engineRegressionFixtures;
return Promise.all(selected.map(async ({ fontFiles, ...fixture }) => ({ ...fixture,
fonts: await Promise.all(fontFiles.map(name => readFile(new URL('./fonts/' + name, import.meta.url)))),
})));
}
Loading
Loading