Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions .github/workflows/CreateRelease.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ jobs:
environment: release
runs-on: [self-hosted, Linux, X64, "1ES.Pool=hld-kvm-amd"]
if: ${{ contains(github.ref, 'refs/heads/release/') }}
outputs:
version: ${{ steps.set-version.outputs.version }}

steps:
- uses: actions/checkout@v6
Expand All @@ -48,11 +50,13 @@ jobs:
id: crates-io-auth

- name: Set crate versions
id: set-version
run: |
git fetch --tags || true
version=$(echo "${{ github.ref }}" | sed -E 's#refs/heads/release/v##')
echo "Setting version to 'v$version'"
echo "HYPERLIGHT_JS_VERSION=v$version" >> $GITHUB_ENV
echo "version=$version" >> $GITHUB_OUTPUT

- name: Publish hyperlight-js
run: |
Expand Down Expand Up @@ -94,3 +98,13 @@ jobs:
benchmarks_Linux_hyperv3.tar.gz
env:
GH_TOKEN: ${{ github.token }}

publish-npm-packages:
needs: [publish-hyperlight-js-packages-and-create-release]
if: ${{ contains(github.ref, 'refs/heads/release/') }}
uses: ./.github/workflows/npm-publish.yml
with:
version: ${{ needs.publish-hyperlight-js-packages-and-create-release.outputs.version }}
dry-run: false
secrets:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
199 changes: 199 additions & 0 deletions .github/workflows/npm-publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
# yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json

name: Publish npm packages

on:
workflow_dispatch:
inputs:
version:
description: 'Version to publish (e.g., 0.17.0)'
required: true
type: string
dry-run:
description: 'Dry run (skip actual publish)'
required: false
type: boolean
default: false
workflow_call:
inputs:
version:
description: 'Version to publish'
required: true
type: string
dry-run:
description: 'Dry run (skip actual publish)'
required: false
type: boolean
default: false
secrets:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need secrets in workflow_dispatch too? or does this cover both?

NPM_TOKEN:
required: true

permissions:
contents: read
id-token: write

env:
WORKING_DIR: src/js-host-api

jobs:
build:
strategy:
fail-fast: true
matrix:
include:
- target: x86_64-unknown-linux-gnu
os: [self-hosted, Linux, X64, "1ES.Pool=hld-kvm-amd"]
build_name: linux-x64-gnu
- target: x86_64-pc-windows-msvc
os: [self-hosted, Windows, X64, "1ES.Pool=hld-win2022-amd"]
build_name: win32-x64-msvc
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0

- name: Hyperlight setup
uses: hyperlight-dev/ci-setup-workflow@v1.8.0
with:
rust-toolchain: "1.89"

- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: '22'
cache: 'npm'
cache-dependency-path: 'src/js-host-api/package-lock.json'

- name: Install dependencies
working-directory: ${{ env.WORKING_DIR }}
run: npm ci --ignore-scripts --omit=optional

- name: Set package version
working-directory: ${{ env.WORKING_DIR }}
shell: bash
run: |
npm version ${{ inputs.version }} --no-git-tag-version --allow-same-version

- name: Build native module
working-directory: ${{ env.WORKING_DIR }}
run: npm run build

- name: Upload artifact
uses: actions/upload-artifact@v8
with:
name: bindings-${{ matrix.build_name }}
path: ${{ env.WORKING_DIR }}/*.node
if-no-files-found: error

publish:
needs: build
runs-on: [self-hosted, Linux, X64, "1ES.Pool=hld-kvm-amd"]
steps:
- uses: actions/checkout@v6

- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: '22'
registry-url: 'https://registry.npmjs.org'
cache: 'npm'
cache-dependency-path: 'src/js-host-api/package-lock.json'

- name: Install dependencies
working-directory: ${{ env.WORKING_DIR }}
run: npm ci --ignore-scripts --omit=optional

- name: Download Linux artifact
uses: actions/download-artifact@v8
with:
name: bindings-linux-x64-gnu
path: ${{ env.WORKING_DIR }}/artifacts/linux-x64-gnu

- name: Download Windows artifact
uses: actions/download-artifact@v8
with:
name: bindings-win32-x64-msvc
path: ${{ env.WORKING_DIR }}/artifacts/win32-x64-msvc

- name: List artifacts
run: ls -la ${{ env.WORKING_DIR }}/artifacts/*/

- name: Move artifacts to npm directories
working-directory: ${{ env.WORKING_DIR }}
run: |
# Rename artifacts to match napi-rs naming convention
mv artifacts/linux-x64-gnu/*.node npm/linux-x64-gnu/js-host-api.linux-x64-gnu.node
mv artifacts/win32-x64-msvc/*.node npm/win32-x64-msvc/js-host-api.win32-x64-msvc.node
ls -la npm/linux-x64-gnu/
ls -la npm/win32-x64-msvc/

- name: Set package versions
working-directory: ${{ env.WORKING_DIR }}
run: |
# Update main package version
npm version ${{ inputs.version }} --no-git-tag-version --allow-same-version

# Update platform package versions
cd npm/linux-x64-gnu && npm version ${{ inputs.version }} --no-git-tag-version --allow-same-version
cd ../win32-x64-msvc && npm version ${{ inputs.version }} --no-git-tag-version --allow-same-version

- name: Update optionalDependencies versions
working-directory: ${{ env.WORKING_DIR }}
run: |
# Update only @hyperlight platform package versions (not other optionalDeps)
node -e "
const fs = require('fs');
const pkg = JSON.parse(fs.readFileSync('package.json', 'utf8'));
for (const dep of Object.keys(pkg.optionalDependencies || {})) {
if (dep.startsWith('@hyperlight/js-host-api-')) {
pkg.optionalDependencies[dep] = '${{ inputs.version }}';
}
}
fs.writeFileSync('package.json', JSON.stringify(pkg, null, 2) + '\n');
"
cat package.json

- name: Generate JS bindings (index.js and index.d.ts)
working-directory: ${{ env.WORKING_DIR }}
run: |
# napi prepublish generates index.js and index.d.ts from the .node artifacts
npx napi prepublish -t npm --skip-gh-release
ls -la index.js index.d.ts

- name: Publish Linux package
if: ${{ !inputs.dry-run }}
working-directory: ${{ env.WORKING_DIR }}/npm/linux-x64-gnu
run: npm publish --access public
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

- name: Publish Windows package
if: ${{ !inputs.dry-run }}
working-directory: ${{ env.WORKING_DIR }}/npm/win32-x64-msvc
run: npm publish --access public
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

- name: Publish main package
if: ${{ !inputs.dry-run }}
working-directory: ${{ env.WORKING_DIR }}
run: npm publish --access public
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

- name: Dry run - show what would be published
if: ${{ inputs.dry-run }}
working-directory: ${{ env.WORKING_DIR }}
run: |
echo "=== DRY RUN - Would publish the following packages ==="
echo ""
echo "--- @hyperlight/js-host-api-linux-x64-gnu ---"
npm pack ./npm/linux-x64-gnu --dry-run
echo ""
echo "--- @hyperlight/js-host-api-win32-x64-msvc ---"
npm pack ./npm/win32-x64-msvc --dry-run
echo ""
echo "--- @hyperlight/js-host-api ---"
npm pack --dry-run
32 changes: 32 additions & 0 deletions src/js-host-api/.npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# npm publish ignores - override .gitignore for package publishing
# Include generated files that are gitignored but needed in the package
!index.js
!index.d.ts

# Exclude development files
node_modules/
target/
Cargo.lock
*.tgz
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.DS_Store

# Exclude package-lock from published package
package-lock.json

# Exclude test and dev files
tests/
examples/
*.config.js
*.config.mjs
.prettierrc
TYPE_NAMING.md
build.rs
src/
Cargo.toml
test-examples.sh

# Exclude artifacts directory (only used during CI)
artifacts/
41 changes: 41 additions & 0 deletions src/js-host-api/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -600,3 +600,44 @@ just test-js-host-api release
just build-all
just test-all release
```

## Publishing to npm

The package is published to npmjs.com as `@hyperlight/js-host-api` with platform-specific binary packages.

### Automated Release

Publishing happens automatically when a release is created via the `CreateRelease` workflow on a `release/vX.Y.Z` branch.

### Manual Publishing

You can also trigger the npm publish workflow manually:

1. Go to **Actions** → **Publish npm packages**
2. Click **Run workflow**
3. Enter the version (e.g., `0.17.0`)
4. Optionally enable **dry-run** to test without publishing

### Setup Requirements

The following secret must be configured in the repository:

| Secret | Description |
|--------|-------------|
| `NPM_TOKEN` | npm access token with publish permissions for the `@hyperlight` scope |

To create an npm token:
1. Log in to [npmjs.com](https://www.npmjs.com/)
2. Go to **Access Tokens** → **Generate New Token**
3. Select **Automation** token type (for CI/CD)
4. Add the token as a repository secret named `NPM_TOKEN`

### Package Structure

The npm release consists of three packages:

| Package | Description |
|---------|-------------|
| `@hyperlight/js-host-api` | Main package (installs correct binary automatically) |
| `@hyperlight/js-host-api-linux-x64-gnu` | Linux x86_64 native binary |
| `@hyperlight/js-host-api-win32-x64-msvc` | Windows x86_64 native binary |
27 changes: 27 additions & 0 deletions src/js-host-api/npm/linux-x64-gnu/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"name": "@hyperlight/js-host-api-linux-x64-gnu",
"version": "0.17.0",
"os": [
"linux"
],
"cpu": [
"x64"
],
"main": "js-host-api.linux-x64-gnu.node",
"files": [
"js-host-api.linux-x64-gnu.node"
],
"description": "Node.js API bindings for Hyperlight JS - Linux x64 gnu",
"license": "Apache-2.0",
"repository": {
"type": "git",
"url": "git+https://github.com/hyperlight-dev/hyperlight-js.git"
},
"homepage": "https://github.com/hyperlight-dev/hyperlight-js#readme",
"bugs": {
"url": "https://github.com/hyperlight-dev/hyperlight-js/issues"
},
"engines": {
"node": ">= 18"
}
}
27 changes: 27 additions & 0 deletions src/js-host-api/npm/win32-x64-msvc/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"name": "@hyperlight/js-host-api-win32-x64-msvc",
"version": "0.17.0",
"os": [
"win32"
],
"cpu": [
"x64"
],
"main": "js-host-api.win32-x64-msvc.node",
"files": [
"js-host-api.win32-x64-msvc.node"
],
"description": "Node.js API bindings for Hyperlight JS - Windows x64 msvc",
"license": "Apache-2.0",
"repository": {
"type": "git",
"url": "git+https://github.com/hyperlight-dev/hyperlight-js.git"
},
"homepage": "https://github.com/hyperlight-dev/hyperlight-js#readme",
"bugs": {
"url": "https://github.com/hyperlight-dev/hyperlight-js/issues"
},
"engines": {
"node": ">= 18"
}
}
10 changes: 10 additions & 0 deletions src/js-host-api/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading