Skip to content

Commit 4916edd

Browse files
authored
Merge pull request #17 from artiz/claude/nodejs-bun-typescript-bindings-8pk2wk
ci(node): make npm-publish tag optional (default: latest master)
2 parents 372b5cf + 2ae240b commit 4916edd

7 files changed

Lines changed: 113 additions & 61 deletions

File tree

.github/workflows/ci.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ jobs:
3333
name: fmt · clippy (pinned)
3434
runs-on: ubuntu-latest
3535
steps:
36-
- uses: actions/checkout@v4
36+
- uses: actions/checkout@v5
3737

3838
- uses: dtolnay/rust-toolchain@master
3939
with:
@@ -52,7 +52,7 @@ jobs:
5252
name: test (stable)
5353
runs-on: ubuntu-latest
5454
steps:
55-
- uses: actions/checkout@v4
55+
- uses: actions/checkout@v5
5656

5757
# Tests stay on the current stable so they catch real compiler breakage.
5858
- uses: dtolnay/rust-toolchain@stable
@@ -75,7 +75,7 @@ jobs:
7575
permissions:
7676
contents: write # push the version-bump commit + tag
7777
steps:
78-
- uses: actions/checkout@v4
78+
- uses: actions/checkout@v5
7979
with:
8080
fetch-depth: 0 # full history + tags, for the semantic version bump
8181
# Push the release commit + tag as an admin PAT so it satisfies the

.github/workflows/npm-publish.yml

Lines changed: 38 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@
55
# package plus per-platform `optionalDependencies` (fleischwolf-<triple>) via
66
# napi-rs and publishes them all.
77
#
8-
# Trigger: manual only (workflow_dispatch). Pick the release tag to build — the
9-
# workflow checks out that tag and publishes the npm version derived from it, so
10-
# npm releases stay decoupled from the crates.io release on every master push.
11-
# Run it from the Actions tab (or `gh workflow run npm-publish.yml -f tag=v0.7.0`).
8+
# Trigger: manual only (workflow_dispatch). By default it builds the latest
9+
# master (the version in the workspace Cargo.toml); optionally pass a release
10+
# tag to build that instead. Either way the workflow checks out the chosen ref
11+
# and publishes, so npm releases stay decoupled from the crates.io release on
12+
# every master push. Run it from the Actions tab (or
13+
# `gh workflow run npm-publish.yml`, optionally `-f tag=v0.7.0`).
1214
#
1315
# Requires one repository secret: NPM_TOKEN — an npm automation token with
1416
# publish rights to `fleischwolf` and the `fleischwolf-*` platform packages.
@@ -19,15 +21,16 @@ on:
1921
workflow_dispatch:
2022
inputs:
2123
tag:
22-
description: "Release tag to build and publish (e.g. v0.7.0)."
23-
required: true
24+
description: "Release tag to build (e.g. v0.7.0). Blank = latest master."
25+
required: false
26+
default: ""
2427
version:
25-
description: "Override the npm version (e.g. 0.7.0). Blank = derive from the tag."
28+
description: "Override the npm version (e.g. 0.7.0). Blank = tag, or workspace version on master."
2629
required: false
2730
default: ""
2831

2932
concurrency:
30-
group: npm-publish-${{ inputs.tag }}
33+
group: npm-publish-${{ inputs.tag || github.ref }}
3134
cancel-in-progress: false
3235

3336
defaults:
@@ -48,16 +51,19 @@ jobs:
4851
# ONNX/ort build). Requires the arm64 runner image to be available.
4952
- target: aarch64-unknown-linux-gnu
5053
host: ubuntu-24.04-arm
51-
- target: x86_64-apple-darwin
52-
host: macos-13
53-
- target: aarch64-apple-darwin
54-
host: macos-14
54+
# macOS (darwin) prebuilds are omitted: GitHub-hosted macOS runners are
55+
# blocked in this environment, and darwin can't be cross-compiled on
56+
# Linux (needs the Apple SDK). macOS users build from source. To re-add
57+
# when macOS runners are available, add the darwin targets back here AND
58+
# to `napi.triples.additional` in package.json:
59+
# - { target: aarch64-apple-darwin, host: macos-14 }
60+
# - { target: x86_64-apple-darwin, host: macos-14 } # cross via --target
5561
- target: x86_64-pc-windows-msvc
5662
host: windows-latest
5763
steps:
58-
- uses: actions/checkout@v4
64+
- uses: actions/checkout@v5
5965
with:
60-
ref: ${{ inputs.tag }}
66+
ref: ${{ inputs.tag || github.ref }}
6167

6268
- uses: dtolnay/rust-toolchain@stable
6369
with:
@@ -69,7 +75,7 @@ jobs:
6975
key: ${{ matrix.target }}
7076
workspaces: "."
7177

72-
- uses: actions/setup-node@v4
78+
- uses: actions/setup-node@v5
7379
with:
7480
node-version: 20
7581

@@ -88,7 +94,7 @@ jobs:
8894
run: npx napi build --platform --release --target ${{ matrix.target }} --js native.js --dts native.d.ts
8995

9096
- name: Upload prebuilt binary
91-
uses: actions/upload-artifact@v4
97+
uses: actions/upload-artifact@v5
9298
with:
9399
name: bindings-${{ matrix.target }}
94100
path: crates/fleischwolf-node/fleischwolf.*.node
@@ -98,7 +104,7 @@ jobs:
98104
# linux-x64 build) for the publish job to include in the main package.
99105
- name: Upload JS binding
100106
if: matrix.target == 'x86_64-unknown-linux-gnu'
101-
uses: actions/upload-artifact@v4
107+
uses: actions/upload-artifact@v5
102108
with:
103109
name: js-binding
104110
path: |
@@ -111,11 +117,11 @@ jobs:
111117
needs: build
112118
runs-on: ubuntu-latest
113119
steps:
114-
- uses: actions/checkout@v4
120+
- uses: actions/checkout@v5
115121
with:
116-
ref: ${{ inputs.tag }}
122+
ref: ${{ inputs.tag || github.ref }}
117123

118-
- uses: actions/setup-node@v4
124+
- uses: actions/setup-node@v5
119125
with:
120126
node-version: 20
121127
registry-url: "https://registry.npmjs.org"
@@ -125,26 +131,33 @@ jobs:
125131

126132
# Prebuilt binaries → artifacts/<name>/fleischwolf.<triple>.node
127133
- name: Download prebuilt binaries
128-
uses: actions/download-artifact@v4
134+
uses: actions/download-artifact@v5
129135
with:
130136
pattern: bindings-*
131137
path: crates/fleischwolf-node/artifacts
132138

133139
# The JS loader + types → the package root.
134140
- name: Download JS binding
135-
uses: actions/download-artifact@v4
141+
uses: actions/download-artifact@v5
136142
with:
137143
name: js-binding
138144
path: crates/fleischwolf-node
139145

140-
# Version = the explicit override, else the selected tag with its leading `v`.
146+
# Version = the explicit override, else the selected tag (sans leading `v`),
147+
# else the workspace version from the root Cargo.toml (latest-master run).
141148
- name: Resolve version
142149
id: ver
143150
run: |
144151
v="${{ inputs.version }}"
145-
if [ -z "$v" ]; then v="${{ inputs.tag }}"; v="${v#v}"; fi
152+
if [ -z "$v" ]; then
153+
if [ -n "${{ inputs.tag }}" ]; then
154+
v="${{ inputs.tag }}"; v="${v#v}"
155+
else
156+
v="$(grep -m1 '^version = ' ../../Cargo.toml | sed -E 's/.*"([^"]+)".*/\1/')"
157+
fi
158+
fi
146159
echo "version=$v" >> "$GITHUB_OUTPUT"
147-
echo "Publishing fleischwolf@$v from tag ${{ inputs.tag }}"
160+
echo "Publishing fleischwolf@$v (ref: ${{ inputs.tag || github.ref }})"
148161
149162
# Skip cleanly if this version is already on npm (idempotent re-runs).
150163
- name: Check if already published

README.md

Lines changed: 31 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -154,32 +154,45 @@ The CLI streams Markdown by default (`--no-stream` opts back into buffering;
154154

155155
## Node.js / Bun bindings
156156

157-
Native TypeScript bindings live in
158-
[`crates/fleischwolf-node`](./crates/fleischwolf-node) (built with
159-
[napi-rs](https://napi.rs)). They ship a real `.node` addon that loads in both
160-
Node.js and Bun (Bun implements N-API — same binary, no rebuild), exposing the
161-
converter with the same knobs as the Rust API: Markdown / docling JSON output,
162-
`strict` mode, image modes, allowed-format restriction, `fetchImages`, sync +
163-
async (`Promise`) calls, and a `streamFileMarkdown` async generator.
157+
Fleischwolf ships as an npm package, [**`fleischwolf`**](https://www.npmjs.com/package/fleischwolf)
158+
— native TypeScript bindings (built with [napi-rs](https://napi.rs)) that live in
159+
[`crates/fleischwolf-node`](./crates/fleischwolf-node). It's a real `.node` addon
160+
that loads in both Node.js and Bun (Bun implements N-API — same binary, no
161+
rebuild), exposing the converter with the same knobs as the Rust API: Markdown /
162+
docling JSON output, `strict` mode, image modes, allowed-format restriction,
163+
`fetchImages`, sync + async (`Promise`) calls, and a `streamFileMarkdown` async
164+
generator.
165+
166+
Install — no Rust toolchain needed, the prebuilt binary for your platform (Linux
167+
x64/arm64, Windows x64) is pulled in automatically:
164168

165169
```bash
166-
cd crates/fleischwolf-node && npm install && npm run build
170+
npm install fleischwolf # or: bun add fleischwolf
167171
```
168172

169173
```ts
170-
import { convertFile, convertFileAsync, streamFileMarkdown } from 'fleischwolf'
174+
import { convert, convertFile, convertFileAsync } from 'fleischwolf'
171175

172-
const { content } = convertFile('report.docx') // Markdown
173-
const json = await convertFileAsync('paper.pdf', { to: 'json' })
174-
for await (const chunk of streamFileMarkdown('paper.pdf')) process.stdout.write(chunk)
176+
// in-memory bytes → Markdown
177+
const md = convert({ name: 'notes.md', data: Buffer.from('# Hello\n\nWorld **bold**') })
178+
console.log(md.content)
179+
180+
// a file → Markdown or docling JSON (format detected from the extension)
181+
const { content } = convertFile('report.docx')
182+
const json = await convertFileAsync('report.docx', { to: 'json' })
175183
```
176184

177-
Declarative formats work out of the box. The PDF/image pipeline needs pdfium +
178-
the ONNX models (not bundled), so it throws until you call `installDependencies()`
179-
— which auto-downloads pdfium/OCR and fetches the layout/TableFormer ONNX from a
180-
`modelsUrl` you host. A reusable `Pipeline` keeps those models warm across many
181-
PDFs. See [`crates/fleischwolf-node/README.md`](./crates/fleischwolf-node/README.md)
182-
for the full API and runnable Node + Bun examples.
185+
Declarative formats (Markdown, HTML, DOCX, XLSX, …) work out of the box. The
186+
PDF/image pipeline needs pdfium + the ONNX models (not bundled), so it throws
187+
until you call `installDependencies()` — which auto-downloads pdfium/OCR and
188+
fetches the layout/TableFormer ONNX from a `modelsUrl` you host. A reusable
189+
`Pipeline` keeps those models warm across many PDFs.
190+
191+
Runnable Node + Bun examples are in
192+
[`crates/fleischwolf-node/examples`](./crates/fleischwolf-node/examples)
193+
(`npm install && node node-basic.mjs`). See
194+
[`crates/fleischwolf-node/README.md`](./crates/fleischwolf-node/README.md) for
195+
the full API.
183196

184197
## Testing
185198

crates/fleischwolf-node/README.md

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,13 @@ needed to use the package:
1919
npm install fleischwolf # or: bun add fleischwolf
2020
```
2121

22-
Prebuilt platforms: Linux x64 / arm64 (glibc), macOS x64 / arm64, Windows x64.
23-
The right binary is pulled in automatically as a platform-specific
24-
`optionalDependency` (`fleischwolf-<triple>`). Releases are published to npm by
22+
Prebuilt platforms: Linux x64 / arm64 (glibc) and Windows x64. (macOS isn't
23+
prebuilt — build from source, see below.) The right binary is pulled in
24+
automatically as a platform-specific `optionalDependency` (`fleischwolf-<triple>`). Releases are published to npm by
2525
manually running the `npm publish` workflow
26-
(`.github/workflows/npm-publish.yml`) for a chosen release tag — decoupled from
27-
the crates.io release.
26+
(`.github/workflows/npm-publish.yml`) — by default it builds the latest master
27+
(the workspace version); optionally pass a release tag to build that instead.
28+
Decoupled from the crates.io release.
2829

2930
## Build from source
3031

@@ -226,16 +227,23 @@ Full TypeScript types are generated into `index.d.ts` / `native.d.ts`.
226227

227228
## Examples
228229

230+
The [`examples/`](examples) folder is a self-contained project that depends on
231+
the published `fleischwolf` package — `npm install` there, then run any of them:
232+
233+
```bash
234+
cd examples
235+
npm install
236+
node node-basic.mjs # ESM: file, bytes, JSON, reuse
237+
bun run bun-basic.ts # Bun + TypeScript: async + streaming
238+
node pdf-pipeline.mjs # installDependencies + warm Pipeline for PDFs
239+
```
240+
229241
- [`examples/node-basic.mjs`](examples/node-basic.mjs) — Node.js (ESM): file, bytes, JSON, reuse.
230242
- [`examples/bun-basic.ts`](examples/bun-basic.ts) — Bun + TypeScript, with async and streaming.
231243
- [`examples/pdf-pipeline.mjs`](examples/pdf-pipeline.mjs)`installDependencies` + warm `Pipeline` for PDFs.
232244

233-
```bash
234-
npm run build # once
235-
node examples/node-basic.mjs
236-
bun run examples/bun-basic.ts
237-
node test/smoke.mjs # or: bun test/smoke.mjs
238-
```
245+
The smoke test exercises the locally-built addon instead: `npm run build` once at
246+
the package root, then `node test/smoke.mjs` (or `bun test/smoke.mjs`).
239247

240248
## License
241249

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
node_modules/
2+
package-lock.json
3+
bun.lockb
4+
artifacts/
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"name": "fleischwolf-examples",
3+
"version": "0.0.0",
4+
"private": true,
5+
"description": "Runnable examples for the fleischwolf npm package. Run `npm install` here, then the scripts below.",
6+
"type": "module",
7+
"scripts": {
8+
"start": "node node-basic.mjs",
9+
"node": "node node-basic.mjs",
10+
"bun": "bun run bun-basic.ts",
11+
"pdf": "node pdf-pipeline.mjs"
12+
},
13+
"dependencies": {
14+
"fleischwolf": "^0.6.1"
15+
}
16+
}

crates/fleischwolf-node/package.json

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,6 @@
3535
"additional": [
3636
"x86_64-unknown-linux-gnu",
3737
"aarch64-unknown-linux-gnu",
38-
"x86_64-apple-darwin",
39-
"aarch64-apple-darwin",
4038
"x86_64-pc-windows-msvc"
4139
]
4240
}
@@ -59,8 +57,8 @@
5957
"prepublishOnly": "napi prepublish -t npm --skip-gh-release",
6058
"version": "napi version",
6159
"test": "node test/smoke.mjs",
62-
"example": "node examples/node-basic.mjs",
63-
"example:bun": "bun run examples/bun-basic.ts"
60+
"example": "npm --prefix examples install && node examples/node-basic.mjs",
61+
"example:bun": "npm --prefix examples install && bun run examples/bun-basic.ts"
6462
},
6563
"devDependencies": {
6664
"@napi-rs/cli": "^2.18.4"

0 commit comments

Comments
 (0)