diff --git a/.github/workflows/nodejs-package.yml b/.github/workflows/nodejs-package.yml index 33956ece..f6f7d6c8 100644 --- a/.github/workflows/nodejs-package.yml +++ b/.github/workflows/nodejs-package.yml @@ -2,6 +2,7 @@ name: Node.js Package on: push: + branches: ['**'] paths: - 'nodejs/**' - '.github/workflows/nodejs-package.yml' @@ -23,8 +24,7 @@ on: - 'vcpkg*.json' - 'ports/**' - 'LICENSE' - release: - types: [published] + workflow_call: workflow_dispatch: permissions: @@ -144,6 +144,12 @@ jobs: pattern: opendht-node-prebuild-* path: nodejs/prebuilds merge-multiple: true + - name: Set release version + if: github.event_name == 'push' && github.ref_type == 'tag' + working-directory: nodejs + env: + RELEASE_TAG: ${{ github.ref_name }} + run: npm version "${RELEASE_TAG#v}" --no-git-tag-version --ignore-scripts --allow-same-version - name: Pack all platforms working-directory: nodejs run: | @@ -177,23 +183,4 @@ jobs: path: nodejs/dist - name: Test installed archive without a native build toolchain working-directory: nodejs - run: npm run test:package -- dist - - release: - name: Attach npm archive to release - if: github.event_name == 'release' - needs: smoke - runs-on: ubuntu-26.04 - permissions: - contents: write - steps: - - uses: actions/download-artifact@v8 - with: - name: opendht-node-npm - path: dist - - name: Upload verified archive - env: - GH_TOKEN: ${{ github.token }} - GH_REPO: ${{ github.repository }} - RELEASE_TAG: ${{ github.event.release.tag_name }} - run: gh release upload "$RELEASE_TAG" dist/*.tgz --clobber \ No newline at end of file + run: npm run test:package -- dist \ No newline at end of file diff --git a/.github/workflows/release-package.yml b/.github/workflows/release-package.yml index 026ac10f..99712c82 100644 --- a/.github/workflows/release-package.yml +++ b/.github/workflows/release-package.yml @@ -18,6 +18,13 @@ env: IMAGE_NAME_ALPINE_DEPS: ${{ github.repository }}/opendht-deps-alpine jobs: + nodejs-package: + name: Build and verify Node.js package + uses: ./.github/workflows/nodejs-package.yml + permissions: + contents: read + packages: read + build-and-push-deps-image: name: Dependency Docker image runs-on: ubuntu-latest @@ -555,7 +562,7 @@ jobs: create-github-release: name: Create GitHub Release runs-on: ubuntu-latest - needs: [build-windows-msi, build-windows-dhtnode] + needs: [build-windows-msi, build-windows-dhtnode, nodejs-package] permissions: contents: write @@ -575,6 +582,12 @@ jobs: name: opendht-windows-dhtnode path: downloaded_artifacts/static_dhtnode + - name: Download npm archive + uses: actions/download-artifact@v8 + with: + name: opendht-node-npm + path: downloaded_artifacts/nodejs + - name: Create Release id: create_release uses: softprops/action-gh-release@v3 @@ -583,3 +596,34 @@ jobs: files: | downloaded_artifacts/windows_msi/*.msi downloaded_artifacts/static_dhtnode/**/*dhtnode.exe + downloaded_artifacts/nodejs/*.tgz + + publish-npm: + name: Publish opendht to npm + needs: create-github-release + runs-on: ubuntu-26.04 + permissions: + contents: read + id-token: write + steps: + - uses: actions/checkout@v7 + - uses: actions/setup-node@v6 + with: + node-version: '24' + registry-url: https://registry.npmjs.org/ + package-manager-cache: false + - uses: actions/download-artifact@v8 + with: + name: opendht-node-npm + path: nodejs/dist + - name: Publish verified archive + working-directory: nodejs + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + RELEASE_TAG: ${{ github.ref_name }} + run: | + dist_tag=latest + if [[ "${RELEASE_TAG#v}" == *-* ]]; then + dist_tag=next + fi + npm publish dist/*.tgz --access public --provenance --tag "$dist_tag" diff --git a/nodejs/README.md b/nodejs/README.md index 2ddb20db..b8c8254e 100644 --- a/nodejs/README.md +++ b/nodejs/README.md @@ -1,9 +1,14 @@ # OpenDHT Node.js Bindings Initial Node-API bindings using `node-addon-api` directly over the C++ library. -The package is private while its API and binary distribution are being developed. Node.js 22.9 or later is required; the addon targets Node-API version 8. +## Install + +```sh +npm install opendht +``` + ## Build Install the native dependencies described in [BUILD.md](../BUILD.md), plus Node.js, @@ -66,7 +71,7 @@ TypeScript or development dependencies, including from inside `node_modules`. ## Usage ```js -import { DhtRunner, hash } from './nodejs/index.js'; +import { DhtRunner, hash } from 'opendht'; async function main() { const writer = new DhtRunner(); @@ -158,7 +163,7 @@ integer between 2048 and 8192; the default is 2048. transparently decrypted for the recipient by OpenDHT's get/listen layer. ```js -import { Identity, DhtRunner } from './nodejs/index.js'; +import { Identity, DhtRunner } from 'opendht'; async function createAuthenticatedNode() { const identity = await Identity.generate('example', { algorithm: 'rsa', bits: 2048 }); @@ -216,14 +221,35 @@ published `latest` tag. simdutf is linked statically because Ubuntu 24.04 does n provide its development package. CI combines platform prebuilds into one npm archive and verifies that archive on -Node 22, 24, and 26 on each platform, including Ubuntu 24.04 and 26.04. Published -GitHub releases receive the verified archive only after all install tests pass. -The package remains private; -the workflow does not publish to the npm registry or require an npm token. +Node 22, 24, and 26 on each platform, including Ubuntu 24.04 and 26.04. Branch +pushes, pull requests, and manual runs build and test without publishing. musl/Alpine and other architectures are not currently built. Node-API stability does not remove OS/libc or native dependency compatibility requirements. Review the included dependency licenses and source-distribution obligations before -redistributing binaries beyond these development/release artifacts. +redistributing binaries. + +## Releases + +Pushing a `v*` tag starts [the release workflow](../.github/workflows/release-package.yml), +which calls the Node.js package workflow. The npm archive version is taken from +the tag without its leading `v`, for example `v4.4.99` becomes `opendht@4.4.99`. +After all Node install tests and Windows builds pass, the release workflow attaches +the verified npm archive alongside the Windows assets to the draft GitHub Release, +then publishes that same archive to npm with provenance. Stable versions use the +`latest` dist-tag; prerelease versions such as `v4.5.0-rc.1` use `next`. +Publishing to npm happens on the tag push, not when the GitHub draft is published. +Published npm versions cannot be overwritten; use a new version tag for changes. + +Configure an npm trusted publisher for the `opendht` package with GitHub owner +`savoirfairelinux`, repository `opendht`, and workflow filename `release-package.yml` +(not `nodejs-package.yml`). Allow direct `npm publish`. Publication runs on a +GitHub-hosted runner with OIDC, so no npm token is needed once this is configured. + +For the first publication, before the npm package exists, set the repository's +`NPM_TOKEN` secret to a granular npm token with publishing permission and 2FA +bypass. After the first successful tag release, configure the trusted publisher +in the npm package settings, then remove `NPM_TOKEN`. The publishing job supports +the token for this bootstrap and prefers OIDC when available. Query filters, async iterators, AbortSignal support, certificate trust-store validation, CA issuance controls, and proxy controls remain future work. \ No newline at end of file diff --git a/nodejs/package.json b/nodejs/package.json index cbf5f1d3..23d83b61 100644 --- a/nodejs/package.json +++ b/nodejs/package.json @@ -1,9 +1,17 @@ { "name": "opendht", "version": "0.1.0", - "private": true, "description": "Distributed hash table for Node.js", "license": "MIT", + "repository": { + "type": "git", + "url": "git+https://github.com/savoirfairelinux/opendht.git", + "directory": "nodejs" + }, + "publishConfig": { + "access": "public", + "registry": "https://registry.npmjs.org/" + }, "type": "module", "main": "index.js", "types": "index.d.ts",