Skip to content

Commit 8797ef1

Browse files
committed
feat(js-host-api): add npm publishing workflow
- Add npm-publish.yml workflow for cross-platform builds (Linux/Windows x64) - Add platform-specific npm packages for native binaries - Integrate npm publish into CreateRelease workflow - Add .npmignore to control published files - Update README with publishing documentation
1 parent ee21e83 commit 8797ef1

File tree

8 files changed

+368
-2
lines changed

8 files changed

+368
-2
lines changed

.github/workflows/CreateRelease.yml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ jobs:
3030
environment: release
3131
runs-on: [self-hosted, Linux, X64, "1ES.Pool=hld-kvm-amd"]
3232
if: ${{ contains(github.ref, 'refs/heads/release/') }}
33+
outputs:
34+
version: ${{ steps.set-version.outputs.version }}
3335

3436
steps:
3537
- uses: actions/checkout@v6
@@ -48,11 +50,13 @@ jobs:
4850
id: crates-io-auth
4951

5052
- name: Set crate versions
53+
id: set-version
5154
run: |
5255
git fetch --tags || true
5356
version=$(echo "${{ github.ref }}" | sed -E 's#refs/heads/release/v##')
5457
echo "Setting version to 'v$version'"
5558
echo "HYPERLIGHT_JS_VERSION=v$version" >> $GITHUB_ENV
59+
echo "version=$version" >> $GITHUB_OUTPUT
5660
5761
- name: Publish hyperlight-js
5862
run: |
@@ -94,3 +98,13 @@ jobs:
9498
benchmarks_Linux_hyperv3.tar.gz
9599
env:
96100
GH_TOKEN: ${{ github.token }}
101+
102+
publish-npm-packages:
103+
needs: [publish-hyperlight-js-packages-and-create-release]
104+
if: ${{ contains(github.ref, 'refs/heads/release/') }}
105+
uses: ./.github/workflows/npm-publish.yml
106+
with:
107+
version: ${{ needs.publish-hyperlight-js-packages-and-create-release.outputs.version }}
108+
dry-run: false
109+
secrets:
110+
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}

.github/workflows/npm-publish.yml

Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
# yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json
2+
3+
name: Publish npm packages
4+
5+
on:
6+
workflow_dispatch:
7+
inputs:
8+
version:
9+
description: 'Version to publish (e.g., 0.17.0)'
10+
required: true
11+
type: string
12+
dry-run:
13+
description: 'Dry run (skip actual publish)'
14+
required: false
15+
type: boolean
16+
default: false
17+
workflow_call:
18+
inputs:
19+
version:
20+
description: 'Version to publish'
21+
required: true
22+
type: string
23+
dry-run:
24+
description: 'Dry run (skip actual publish)'
25+
required: false
26+
type: boolean
27+
default: false
28+
secrets:
29+
NPM_TOKEN:
30+
required: true
31+
32+
permissions:
33+
contents: read
34+
id-token: write
35+
36+
env:
37+
WORKING_DIR: src/js-host-api
38+
39+
jobs:
40+
build:
41+
strategy:
42+
fail-fast: true
43+
matrix:
44+
include:
45+
- target: x86_64-unknown-linux-gnu
46+
os: [self-hosted, Linux, X64, "1ES.Pool=hld-kvm-amd"]
47+
build_name: linux-x64-gnu
48+
- target: x86_64-pc-windows-msvc
49+
os: [self-hosted, Windows, X64, "1ES.Pool=hld-win2022-amd"]
50+
build_name: win32-x64-msvc
51+
runs-on: ${{ matrix.os }}
52+
steps:
53+
- uses: actions/checkout@v6
54+
with:
55+
fetch-depth: 0
56+
57+
- name: Hyperlight setup
58+
uses: hyperlight-dev/ci-setup-workflow@v1.8.0
59+
with:
60+
rust-toolchain: "1.89"
61+
62+
- name: Setup Node.js
63+
uses: actions/setup-node@v6
64+
with:
65+
node-version: '22'
66+
cache: 'npm'
67+
cache-dependency-path: 'src/js-host-api/package-lock.json'
68+
69+
- name: Install dependencies
70+
working-directory: ${{ env.WORKING_DIR }}
71+
run: npm ci --ignore-scripts --omit=optional
72+
73+
- name: Set package version
74+
working-directory: ${{ env.WORKING_DIR }}
75+
shell: bash
76+
run: |
77+
npm version ${{ inputs.version }} --no-git-tag-version --allow-same-version
78+
79+
- name: Build native module
80+
working-directory: ${{ env.WORKING_DIR }}
81+
run: npm run build
82+
83+
- name: Upload artifact
84+
uses: actions/upload-artifact@v8
85+
with:
86+
name: bindings-${{ matrix.build_name }}
87+
path: ${{ env.WORKING_DIR }}/*.node
88+
if-no-files-found: error
89+
90+
publish:
91+
needs: build
92+
runs-on: [self-hosted, Linux, X64, "1ES.Pool=hld-kvm-amd"]
93+
steps:
94+
- uses: actions/checkout@v6
95+
96+
- name: Setup Node.js
97+
uses: actions/setup-node@v6
98+
with:
99+
node-version: '22'
100+
registry-url: 'https://registry.npmjs.org'
101+
cache: 'npm'
102+
cache-dependency-path: 'src/js-host-api/package-lock.json'
103+
104+
- name: Install dependencies
105+
working-directory: ${{ env.WORKING_DIR }}
106+
run: npm ci --ignore-scripts --omit=optional
107+
108+
- name: Download Linux artifact
109+
uses: actions/download-artifact@v8
110+
with:
111+
name: bindings-linux-x64-gnu
112+
path: ${{ env.WORKING_DIR }}/artifacts/linux-x64-gnu
113+
114+
- name: Download Windows artifact
115+
uses: actions/download-artifact@v8
116+
with:
117+
name: bindings-win32-x64-msvc
118+
path: ${{ env.WORKING_DIR }}/artifacts/win32-x64-msvc
119+
120+
- name: List artifacts
121+
run: ls -la ${{ env.WORKING_DIR }}/artifacts/*/
122+
123+
- name: Move artifacts to npm directories
124+
working-directory: ${{ env.WORKING_DIR }}
125+
run: |
126+
# Rename artifacts to match napi-rs naming convention
127+
mv artifacts/linux-x64-gnu/*.node npm/linux-x64-gnu/js-host-api.linux-x64-gnu.node
128+
mv artifacts/win32-x64-msvc/*.node npm/win32-x64-msvc/js-host-api.win32-x64-msvc.node
129+
ls -la npm/linux-x64-gnu/
130+
ls -la npm/win32-x64-msvc/
131+
132+
- name: Set package versions
133+
working-directory: ${{ env.WORKING_DIR }}
134+
run: |
135+
# Update main package version
136+
npm version ${{ inputs.version }} --no-git-tag-version --allow-same-version
137+
138+
# Update platform package versions
139+
cd npm/linux-x64-gnu && npm version ${{ inputs.version }} --no-git-tag-version --allow-same-version
140+
cd ../win32-x64-msvc && npm version ${{ inputs.version }} --no-git-tag-version --allow-same-version
141+
142+
- name: Update optionalDependencies versions
143+
working-directory: ${{ env.WORKING_DIR }}
144+
run: |
145+
# Update only @hyperlight platform package versions (not other optionalDeps)
146+
node -e "
147+
const fs = require('fs');
148+
const pkg = JSON.parse(fs.readFileSync('package.json', 'utf8'));
149+
for (const dep of Object.keys(pkg.optionalDependencies || {})) {
150+
if (dep.startsWith('@hyperlight/js-host-api-')) {
151+
pkg.optionalDependencies[dep] = '${{ inputs.version }}';
152+
}
153+
}
154+
fs.writeFileSync('package.json', JSON.stringify(pkg, null, 2) + '\n');
155+
"
156+
cat package.json
157+
158+
- name: Generate JS bindings (index.js and index.d.ts)
159+
working-directory: ${{ env.WORKING_DIR }}
160+
run: |
161+
# napi prepublish generates index.js and index.d.ts from the .node artifacts
162+
npx napi prepublish -t npm --skip-gh-release
163+
ls -la index.js index.d.ts
164+
165+
- name: Publish Linux package
166+
if: ${{ !inputs.dry-run }}
167+
working-directory: ${{ env.WORKING_DIR }}/npm/linux-x64-gnu
168+
run: npm publish --access public
169+
env:
170+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
171+
172+
- name: Publish Windows package
173+
if: ${{ !inputs.dry-run }}
174+
working-directory: ${{ env.WORKING_DIR }}/npm/win32-x64-msvc
175+
run: npm publish --access public
176+
env:
177+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
178+
179+
- name: Publish main package
180+
if: ${{ !inputs.dry-run }}
181+
working-directory: ${{ env.WORKING_DIR }}
182+
run: npm publish --access public
183+
env:
184+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
185+
186+
- name: Dry run - show what would be published
187+
if: ${{ inputs.dry-run }}
188+
working-directory: ${{ env.WORKING_DIR }}
189+
run: |
190+
echo "=== DRY RUN - Would publish the following packages ==="
191+
echo ""
192+
echo "--- @hyperlight/js-host-api-linux-x64-gnu ---"
193+
npm pack ./npm/linux-x64-gnu --dry-run
194+
echo ""
195+
echo "--- @hyperlight/js-host-api-win32-x64-msvc ---"
196+
npm pack ./npm/win32-x64-msvc --dry-run
197+
echo ""
198+
echo "--- @hyperlight/js-host-api ---"
199+
npm pack --dry-run

src/js-host-api/.npmignore

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# npm publish ignores - override .gitignore for package publishing
2+
# Include generated files that are gitignored but needed in the package
3+
!index.js
4+
!index.d.ts
5+
6+
# Exclude development files
7+
node_modules/
8+
target/
9+
Cargo.lock
10+
*.tgz
11+
npm-debug.log*
12+
yarn-debug.log*
13+
yarn-error.log*
14+
.DS_Store
15+
16+
# Exclude package-lock from published package
17+
package-lock.json
18+
19+
# Exclude test and dev files
20+
tests/
21+
examples/
22+
*.config.js
23+
*.config.mjs
24+
.prettierrc
25+
TYPE_NAMING.md
26+
build.rs
27+
src/
28+
Cargo.toml
29+
test-examples.sh
30+
31+
# Exclude artifacts directory (only used during CI)
32+
artifacts/

src/js-host-api/README.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -600,3 +600,44 @@ just test-js-host-api release
600600
just build-all
601601
just test-all release
602602
```
603+
604+
## Publishing to npm
605+
606+
The package is published to npmjs.com as `@hyperlight/js-host-api` with platform-specific binary packages.
607+
608+
### Automated Release
609+
610+
Publishing happens automatically when a release is created via the `CreateRelease` workflow on a `release/vX.Y.Z` branch.
611+
612+
### Manual Publishing
613+
614+
You can also trigger the npm publish workflow manually:
615+
616+
1. Go to **Actions****Publish npm packages**
617+
2. Click **Run workflow**
618+
3. Enter the version (e.g., `0.17.0`)
619+
4. Optionally enable **dry-run** to test without publishing
620+
621+
### Setup Requirements
622+
623+
The following secret must be configured in the repository:
624+
625+
| Secret | Description |
626+
|--------|-------------|
627+
| `NPM_TOKEN` | npm access token with publish permissions for the `@hyperlight` scope |
628+
629+
To create an npm token:
630+
1. Log in to [npmjs.com](https://www.npmjs.com/)
631+
2. Go to **Access Tokens****Generate New Token**
632+
3. Select **Automation** token type (for CI/CD)
633+
4. Add the token as a repository secret named `NPM_TOKEN`
634+
635+
### Package Structure
636+
637+
The npm release consists of three packages:
638+
639+
| Package | Description |
640+
|---------|-------------|
641+
| `@hyperlight/js-host-api` | Main package (installs correct binary automatically) |
642+
| `@hyperlight/js-host-api-linux-x64-gnu` | Linux x86_64 native binary |
643+
| `@hyperlight/js-host-api-win32-x64-msvc` | Windows x86_64 native binary |
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
{
2+
"name": "@hyperlight/js-host-api-linux-x64-gnu",
3+
"version": "0.17.0",
4+
"os": [
5+
"linux"
6+
],
7+
"cpu": [
8+
"x64"
9+
],
10+
"main": "js-host-api.linux-x64-gnu.node",
11+
"files": [
12+
"js-host-api.linux-x64-gnu.node"
13+
],
14+
"description": "Node.js API bindings for Hyperlight JS - Linux x64 gnu",
15+
"license": "Apache-2.0",
16+
"repository": {
17+
"type": "git",
18+
"url": "git+https://github.com/hyperlight-dev/hyperlight-js.git"
19+
},
20+
"homepage": "https://github.com/hyperlight-dev/hyperlight-js#readme",
21+
"bugs": {
22+
"url": "https://github.com/hyperlight-dev/hyperlight-js/issues"
23+
},
24+
"engines": {
25+
"node": ">= 18"
26+
}
27+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
{
2+
"name": "@hyperlight/js-host-api-win32-x64-msvc",
3+
"version": "0.17.0",
4+
"os": [
5+
"win32"
6+
],
7+
"cpu": [
8+
"x64"
9+
],
10+
"main": "js-host-api.win32-x64-msvc.node",
11+
"files": [
12+
"js-host-api.win32-x64-msvc.node"
13+
],
14+
"description": "Node.js API bindings for Hyperlight JS - Windows x64 msvc",
15+
"license": "Apache-2.0",
16+
"repository": {
17+
"type": "git",
18+
"url": "git+https://github.com/hyperlight-dev/hyperlight-js.git"
19+
},
20+
"homepage": "https://github.com/hyperlight-dev/hyperlight-js#readme",
21+
"bugs": {
22+
"url": "https://github.com/hyperlight-dev/hyperlight-js/issues"
23+
},
24+
"engines": {
25+
"node": ">= 18"
26+
}
27+
}

src/js-host-api/package-lock.json

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)