Real-world Reflow 08: a polyphonic synthesizer with ctx.pool (C++) #25
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # Build and publish the @offbit-ai/reflow Node SDK. | |
| # | |
| # Triggers | |
| # -------- | |
| # - Tag push matching `node-v*` (e.g. `node-v0.2.0`) → build every | |
| # platform addon, run tests, then publish to npm. | |
| # - Manual `workflow_dispatch` → build + test only. | |
| # | |
| # Publishing auth | |
| # --------------- | |
| # Uses an automation token stored as the `NPM_TOKEN` secret. Flip to | |
| # npm trusted publishing (OIDC) once the first release is up. | |
| name: publish-node | |
| on: | |
| push: | |
| tags: | |
| - 'node-v*' | |
| workflow_dispatch: | |
| permissions: | |
| contents: read | |
| jobs: | |
| build: | |
| name: build / ${{ matrix.settings.target }} | |
| runs-on: ${{ matrix.settings.host }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| settings: | |
| # `napi build --target X` is required on every entry, not just | |
| # cross-builds: without it the output `.node` file lacks the | |
| # platform suffix that `napi artifacts` looks for in publish. | |
| - host: macos-14 | |
| target: aarch64-apple-darwin | |
| build: npm run build -- --target aarch64-apple-darwin | |
| # macos-13 (Intel) runners have long queue times and the x86_64 | |
| # SDK is already present on macos-14, so we cross-compile the | |
| # Intel addon from the aarch64 runner instead. | |
| - host: macos-14 | |
| target: x86_64-apple-darwin | |
| build: npm run build -- --target x86_64-apple-darwin | |
| - host: ubuntu-latest | |
| target: x86_64-unknown-linux-gnu | |
| docker: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-debian | |
| build: npm run build -- --target x86_64-unknown-linux-gnu | |
| - host: ubuntu-latest | |
| target: aarch64-unknown-linux-gnu | |
| docker: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-debian-aarch64 | |
| build: npm run build -- --target aarch64-unknown-linux-gnu | |
| - host: windows-latest | |
| target: x86_64-pc-windows-msvc | |
| build: npm run build -- --target x86_64-pc-windows-msvc | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: actions/setup-node@v4 | |
| with: | |
| node-version: 20 | |
| - name: Install Rust toolchain | |
| if: ${{ !matrix.settings.docker }} | |
| uses: dtolnay/rust-toolchain@stable | |
| with: | |
| targets: ${{ matrix.settings.target }} | |
| - uses: mozilla-actions/sccache-action@v0.0.5 | |
| if: ${{ !matrix.settings.docker }} | |
| - name: Install npm deps | |
| working-directory: sdk/node | |
| run: npm ci || npm install | |
| - name: Build addon (host) | |
| if: ${{ !matrix.settings.docker }} | |
| working-directory: sdk/node | |
| run: ${{ matrix.settings.build }} | |
| - name: Build addon (docker) | |
| if: ${{ matrix.settings.docker }} | |
| uses: addnab/docker-run-action@v3 | |
| with: | |
| image: ${{ matrix.settings.docker }} | |
| options: -v ${{ github.workspace }}:/build -w /build/sdk/node | |
| # The napi-rs nodejs-rust images invoke scripts through sh | |
| # (dash), which rejects `set -o pipefail`. `-eux` is portable. | |
| # | |
| # The lts-debian images ship an older Rust (1.82 at time of | |
| # writing); reflow_network requires edition 2024, which | |
| # stabilized in 1.85. Bump the toolchain before building. | |
| run: | | |
| set -eux | |
| # rquickjs-sys's build script patches QuickJS sources with | |
| # `patch`, which isn't installed in the napi-rs base images. | |
| (command -v patch >/dev/null) || (apt-get update && apt-get install -y patch) | |
| rustup update stable | |
| rustup default stable | |
| rustup target add ${{ matrix.settings.target }} | |
| npm ci || npm install | |
| ${{ matrix.settings.build }} | |
| - uses: actions/upload-artifact@v4 | |
| with: | |
| name: bindings-${{ matrix.settings.target }} | |
| # napi build emits the .node addon plus a small JS/TS loader | |
| # shim (index.js / index.d.ts) that tests `require()` to find | |
| # the right native binary. Both are gitignored, so test jobs | |
| # need them shipped via the artifact. | |
| path: | | |
| sdk/node/*.node | |
| sdk/node/index.js | |
| sdk/node/index.d.ts | |
| if-no-files-found: error | |
| test: | |
| name: test / ${{ matrix.settings.host }} | |
| needs: build | |
| runs-on: ${{ matrix.settings.host }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| settings: | |
| - host: macos-14 | |
| target: aarch64-apple-darwin | |
| # No macos-13 test run — cross-compiled x86_64 addon would | |
| # need Rosetta-Node to execute, and x86_64 code paths are | |
| # exercised by the Linux x86_64 test anyway. | |
| - host: ubuntu-latest | |
| target: x86_64-unknown-linux-gnu | |
| - host: windows-latest | |
| target: x86_64-pc-windows-msvc | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: actions/setup-node@v4 | |
| with: | |
| node-version: 20 | |
| - name: Download addon for host | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: bindings-${{ matrix.settings.target }} | |
| path: sdk/node | |
| - name: Install + run tests | |
| working-directory: sdk/node | |
| shell: bash | |
| run: | | |
| npm ci || npm install | |
| npm test | |
| publish: | |
| name: publish to npm | |
| needs: [build, test] | |
| runs-on: ubuntu-latest | |
| if: startsWith(github.ref, 'refs/tags/node-v') | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: actions/setup-node@v4 | |
| with: | |
| node-version: 20 | |
| registry-url: 'https://registry.npmjs.org' | |
| - name: Install + download all addons | |
| working-directory: sdk/node | |
| run: npm ci || npm install | |
| - uses: actions/download-artifact@v4 | |
| with: | |
| path: sdk/node/artifacts | |
| # Build the wasm32 browser bundle and stage it into sdk/node/wasm/ | |
| # so it ships inside the same `@offbit-ai/reflow` npm package. | |
| # The `"browser"` conditional export in package.json picks this | |
| # up when bundlers target the browser; Node imports the napi | |
| # addon as before. | |
| - uses: dtolnay/rust-toolchain@stable | |
| with: | |
| targets: wasm32-unknown-unknown | |
| - uses: jetli/wasm-pack-action@v0.4.0 | |
| with: | |
| version: latest | |
| - name: Build browser-WASM bundle | |
| # `--target web` emits an ES module + .wasm pair that loads | |
| # via `await init()`. wasm-pack also writes a per-package | |
| # `package.json` and `.gitignore` into the out-dir; we strip | |
| # them so the wasm/ subtree doesn't shadow the parent | |
| # package.json or look like a standalone npm package. | |
| run: | | |
| wasm-pack build crates/reflow_rt_wasm \ | |
| --target web \ | |
| --release \ | |
| --out-dir ../../sdk/node/wasm | |
| rm -f sdk/node/wasm/package.json sdk/node/wasm/.gitignore | |
| - name: Distribute addons to per-platform npm packages | |
| working-directory: sdk/node | |
| # `napi create-npm-dir` scaffolds `npm/<platform>/` (one | |
| # package.json per triple in package.json's napi.triples) with | |
| # versions already matching the main package. `napi artifacts` | |
| # copies the per-triple `.node` files in. After this step, | |
| # each `npm/<platform>/` is a publishable package — we then | |
| # `npm publish` them one by one in the next step. | |
| # | |
| # We deliberately don't run `napi prepublish` here: in v2.18 it | |
| # also tries to `npm publish` each platform itself, doubling up | |
| # with our manual loop and obscuring real failures. | |
| run: | | |
| npx napi create-npm-dir -t . | |
| npx napi artifacts --dir artifacts | |
| - name: Publish platform packages | |
| working-directory: sdk/node | |
| # No `--provenance`: would require `id-token: write` and a | |
| # trusted-publisher OIDC token. We use a classic NPM_TOKEN here | |
| # which can't sign provenance attestations. Add provenance once | |
| # the org is set up for npm trusted publishing. | |
| # | |
| # First-publish of a new scoped package needs the NPM_TOKEN to | |
| # have *write access to the scope* (granular tokens scoped to | |
| # specific packages will return 404 here). Use a classic | |
| # Automation token, or a granular token with the full scope. | |
| env: | |
| NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} | |
| run: | | |
| set -e | |
| for dir in npm/*/; do | |
| [ -f "$dir/package.json" ] || continue | |
| echo "::group::publish $(basename "$dir")" | |
| (cd "$dir" && npm publish --access public) | |
| echo "::endgroup::" | |
| done | |
| - name: Publish main package | |
| working-directory: sdk/node | |
| env: | |
| NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} | |
| run: npm publish --access public |