Skip to content

npm publish

npm publish #9

Workflow file for this run

# Publish the `docling.rs` npm package (Node.js / Bun native bindings) for a
# chosen release. The package is a native N-API addon, so it can't be a one-line
# `npm publish`: it's built on a matrix of native runners (one per OS/arch),
# each producing a platform `.node`, then a publish job assembles the main
# package plus per-platform `optionalDependencies` (docling.rs-<triple>) via
# napi-rs and publishes them all.
#
# Trigger: manual only (workflow_dispatch). By default it builds the latest
# master (the version in the workspace Cargo.toml); optionally pass a release
# tag to build that instead. Either way the workflow checks out the chosen ref
# and publishes, so npm releases stay decoupled from the crates.io release on
# every master push. Run it from the Actions tab (or
# `gh workflow run npm-publish.yml`, optionally `-f tag=v0.7.0`).
#
# Requires one repository secret: NPM_TOKEN — an npm automation token with
# publish rights to `docling.rs` and the `docling.rs-*` platform packages.
name: npm publish
on:
workflow_dispatch:
inputs:
tag:
description: "Release tag to build (e.g. v0.7.0). Blank = latest master."
required: false
default: ""
version:
description: "Override the npm version (e.g. 0.7.0). Blank = tag, or workspace version on master."
required: false
default: ""
concurrency:
group: npm-publish-${{ inputs.tag || github.ref }}
cancel-in-progress: false
defaults:
run:
working-directory: crates/docling-node
jobs:
build:
name: build ${{ matrix.target }}
runs-on: ${{ matrix.host }}
strategy:
fail-fast: false
matrix:
include:
- target: x86_64-unknown-linux-gnu
host: ubuntu-22.04
# GitHub-hosted ARM64 Linux runner (native — avoids cross-compiling the
# ONNX/ort build). Requires the arm64 runner image to be available.
- target: aarch64-unknown-linux-gnu
host: ubuntu-24.04-arm
# macOS (darwin) prebuilds are omitted: GitHub-hosted macOS runners are
# blocked in this environment, and darwin can't be cross-compiled on
# Linux (needs the Apple SDK). macOS users build from source. To re-add
# when macOS runners are available, add the darwin targets back here AND
# to `napi.triples.additional` in package.json:
# - { target: aarch64-apple-darwin, host: macos-14 }
# - { target: x86_64-apple-darwin, host: macos-14 } # cross via --target
- target: x86_64-pc-windows-msvc
host: windows-latest
steps:
- uses: actions/checkout@v7
with:
ref: ${{ inputs.tag || github.ref }}
# rustup is preinstalled on GitHub-hosted runners (Linux + Windows); use it
# directly — the docling-project org allowlists only GitHub-owned / vetted
# actions, not marketplace toolchain actions.
- name: Install Rust (stable)
shell: bash
run: |
rustup toolchain install stable --profile minimal
rustup default stable
rustup target add ${{ matrix.target }}
# One workspace, key the cache per target so the 5 jobs don't collide.
- uses: actions/cache@v4
with:
path: |
~/.cargo/registry/index
~/.cargo/registry/cache
~/.cargo/git/db
target
key: ${{ runner.os }}-cargo-${{ matrix.target }}-${{ hashFiles('**/Cargo.lock') }}
restore-keys: ${{ runner.os }}-cargo-${{ matrix.target }}-
- uses: actions/setup-node@v6
with:
node-version: 20
- name: Install napi CLI
run: npm install
# Native addon + the JS loader / d.ts. `--strip` keeps the (ONNX-linked)
# binary as small as possible; strip isn't available under MSVC, so the
# Windows build omits it.
- name: Build (unix)
if: runner.os != 'Windows'
run: npx napi build --platform --release --strip --target ${{ matrix.target }} --js native.js --dts native.d.ts
- name: Build (windows)
if: runner.os == 'Windows'
run: npx napi build --platform --release --target ${{ matrix.target }} --js native.js --dts native.d.ts
- name: Upload prebuilt binary
uses: actions/upload-artifact@v7
with:
name: bindings-${{ matrix.target }}
path: crates/docling-node/docling-rs.*.node
if-no-files-found: error
# The JS loader + types are platform-agnostic; upload them once (from the
# linux-x64 build) for the publish job to include in the main package.
- name: Upload JS binding
if: matrix.target == 'x86_64-unknown-linux-gnu'
uses: actions/upload-artifact@v7
with:
name: js-binding
path: |
crates/docling-node/native.js
crates/docling-node/native.d.ts
if-no-files-found: error
publish:
name: publish to npm
needs: build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
with:
ref: ${{ inputs.tag || github.ref }}
- uses: actions/setup-node@v6
with:
node-version: 20
registry-url: "https://registry.npmjs.org"
- name: Install napi CLI
run: npm install
# Prebuilt binaries → artifacts/<name>/docling-rs.<triple>.node
- name: Download prebuilt binaries
uses: actions/download-artifact@v8
with:
pattern: bindings-*
path: crates/docling-node/artifacts
# The JS loader + types → the package root.
- name: Download JS binding
uses: actions/download-artifact@v8
with:
name: js-binding
path: crates/docling-node
# Version = the explicit override, else the selected tag (sans leading `v`),
# else the workspace version from the root Cargo.toml (latest-master run).
- name: Resolve version
id: ver
run: |
v="${{ inputs.version }}"
if [ -z "$v" ]; then
if [ -n "${{ inputs.tag }}" ]; then
v="${{ inputs.tag }}"; v="${v#v}"
else
v="$(grep -m1 '^version = ' ../../Cargo.toml | sed -E 's/.*"([^"]+)".*/\1/')"
fi
fi
echo "version=$v" >> "$GITHUB_OUTPUT"
echo "Publishing docling.rs@$v (ref: ${{ inputs.tag || github.ref }})"
# Skip cleanly if this version is already on npm (idempotent re-runs).
- name: Check if already published
id: check
run: |
v="${{ steps.ver.outputs.version }}"
if npm view "docling.rs@$v" version >/dev/null 2>&1; then
echo "published=true" >> "$GITHUB_OUTPUT"
echo "docling.rs@$v is already on npm — skipping."
else
echo "published=false" >> "$GITHUB_OUTPUT"
fi
- name: Set package version
if: steps.check.outputs.published == 'false'
run: npm version "${{ steps.ver.outputs.version }}" --no-git-tag-version --allow-same-version
# Create the per-platform package dirs and move each prebuilt .node into
# its dir. `npm publish` then runs `prepublishOnly` (napi prepublish), which
# publishes the docling.rs-<triple> packages and wires them into the main
# package's optionalDependencies before the main package is published.
- name: Assemble platform packages
if: steps.check.outputs.published == 'false'
run: |
npx napi create-npm-dir -t .
npx napi artifacts --dir artifacts
- name: Publish
if: steps.check.outputs.published == 'false'
run: npm publish --access public
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}