@@ -157,7 +157,8 @@ jobs:
157157 echo "Computed cargo-semver-checks release-type: '${RT:-<derive-from-version>}'"
158158 - uses : obi1kenobi/cargo-semver-checks-action@v2
159159 with :
160- # Only check published crates; skip cli (binary) and schema-gen (publish=false)
160+ # Only check published crates; skip schema-gen (publish=false) and cli, whose
161+ # lib target is new — add it once a release with the lib is on crates.io
161162 package : vespertide,vespertide-core,vespertide-config,vespertide-loader,vespertide-naming,vespertide-planner,vespertide-query,vespertide-exporter,vespertide-macro
162163 feature-group : default-features
163164 # Empty => action derives strictly from the Cargo.toml version.
@@ -564,6 +565,144 @@ jobs:
564565 - name : Check schema drift
565566 run : git diff --no-index --exit-code -- schemas _tmp_schemas
566567
568+ # npm: the CLI as a Node addon (bridge/node, napi-rs). Fires only when the
569+ # npm manifest is in the changepacks wave. Mirrors lsp-release's target
570+ # table; `cross` is used for the same single aarch64-linux cell.
571+ node-build :
572+ name : npm Build (${{ matrix.target }})
573+ needs : changepacks
574+ if : ${{ contains(needs.changepacks.outputs.changepacks, 'bridge/node/package.json') }}
575+ runs-on : ${{ matrix.runs-on }}
576+ strategy :
577+ fail-fast : false
578+ matrix :
579+ include :
580+ - target : x86_64-unknown-linux-gnu
581+ runs-on : ubuntu-latest
582+ use_cross : false
583+ - target : aarch64-unknown-linux-gnu
584+ runs-on : ubuntu-latest
585+ use_cross : true
586+ - target : x86_64-apple-darwin
587+ # Cross-arch on the ARM runner, as in lsp-release.
588+ runs-on : macos-latest
589+ use_cross : false
590+ - target : aarch64-apple-darwin
591+ runs-on : macos-latest
592+ use_cross : false
593+ - target : x86_64-pc-windows-msvc
594+ runs-on : windows-latest
595+ use_cross : false
596+ steps :
597+ - uses : actions/checkout@v7
598+
599+ - uses : actions-rust-lang/setup-rust-toolchain@v1
600+ with :
601+ target : ${{ matrix.target }}
602+
603+ - uses : oven-sh/setup-bun@v2
604+ with :
605+ bun-version : latest
606+
607+ - name : Install cross (aarch64-unknown-linux-gnu only)
608+ if : matrix.use_cross
609+ uses : taiki-e/install-action@v2.86.3
610+ with :
611+ tool : cross
612+
613+ - name : Install
614+ working-directory : bridge/node
615+ run : bun install --frozen-lockfile
616+
617+ - name : Build addon (native)
618+ if : ${{ !matrix.use_cross }}
619+ working-directory : bridge/node
620+ run : bun run build --target ${{ matrix.target }}
621+
622+ - name : Build addon (cross)
623+ if : matrix.use_cross
624+ working-directory : bridge/node
625+ run : bun run build --target ${{ matrix.target }} --use-cross
626+
627+ # The addon only loads where it was built for; the two cross-arch
628+ # cells skip the smoke test.
629+ - name : Smoke test
630+ if : ${{ matrix.target != 'aarch64-unknown-linux-gnu' && matrix.target != 'x86_64-apple-darwin' }}
631+ working-directory : bridge/node
632+ run : bun test
633+
634+ - uses : actions/upload-artifact@v7
635+ with :
636+ name : bindings-${{ matrix.target }}
637+ path : bridge/node/vespertide.*.node
638+ if-no-files-found : error
639+ retention-days : 1
640+
641+ node-publish :
642+ name : npm Publish
643+ needs : [changepacks, node-build]
644+ if : ${{ contains(needs.changepacks.outputs.changepacks, 'bridge/node/package.json') }}
645+ runs-on : ubuntu-latest
646+ permissions :
647+ contents : write
648+ steps :
649+ - uses : actions/checkout@v7
650+
651+ - uses : oven-sh/setup-bun@v2
652+ with :
653+ bun-version : latest
654+
655+ # npm (not bun) performs the publish so the registry auth from
656+ # setup-node applies; `npm publish` runs `prepublishOnly`, which pushes
657+ # the five platform packages before the root one.
658+ - uses : actions/setup-node@v7
659+ with :
660+ node-version : ' 24'
661+ registry-url : ' https://registry.npmjs.org'
662+
663+ - uses : actions-rust-lang/setup-rust-toolchain@v1
664+
665+ - name : Install
666+ working-directory : bridge/node
667+ run : bun install --frozen-lockfile
668+
669+ # `index.js` / `index.d.ts` are build outputs (gitignored); only
670+ # `napi build` writes them, so the publish host builds once for
671+ # its own platform before assembling the packages.
672+ - name : Build addon (regenerates the JS loader)
673+ working-directory : bridge/node
674+ run : bun run build
675+
676+ - name : Create platform package dirs
677+ working-directory : bridge/node
678+ run : bunx napi create-npm-dirs
679+
680+ - uses : actions/download-artifact@v8
681+ with :
682+ path : bridge/node/artifacts
683+
684+ - name : Move addons into platform packages
685+ working-directory : bridge/node
686+ run : bun run artifacts
687+
688+ - name : Upload addons to changepacks release
689+ uses : owjs3901/upload-github-release-asset@main
690+ with :
691+ upload_url : ${{ fromJson(needs.changepacks.outputs.release_assets_urls)['bridge/node/package.json'] }}
692+ asset_path : bridge/node/npm/*/vespertide.*.node
693+
694+ - name : Publish to npm
695+ working-directory : bridge/node
696+ env :
697+ NODE_AUTH_TOKEN : ${{ secrets.NPM_TOKEN }}
698+ run : |
699+ if [ -z "$NODE_AUTH_TOKEN" ]; then
700+ echo "::warning::NPM_TOKEN not set — skipping npm publish"
701+ else
702+ npm publish --access public
703+ fi
704+ shell : bash
705+
567706 insta-pending :
568707 name : insta-pending
569708 runs-on : ubuntu-latest
0 commit comments