Docs  /  Guides

Publishing Rerius to npm

This document explains the CI/CD pipeline and how to publish Rerius to npm.

Repository: https://github.com/ECLS-Studio/rerius

Note: this source tree doesn't include a .github/workflows/ directory, so the workflow descriptions below couldn't be checked against the live files in this pass: verify job names, triggers, and matrix entries on GitHub before relying on specifics.


Overview#

Rerius uses a four-workflow CI/CD system:

Workflow File Trigger Purpose
CI ci.yml push/PR to main Build + test on Linux, macOS, Node matrix
Prebuild prebuild.yml tag push / manual Build .node binaries for all platforms
Publish publish.yml tag push / manual Full release pipeline → npm + GitHub Release
Release release.yml manual Bump version, commit, tag, trigger publish
Nightly nightly.yml daily 02:00 UTC Regression detection, opens issues on failure
CodeQL codeql.yml push/PR/weekly Static security analysis of C source

One-Time Setup#

1. Create an npm token#

  1. Log in to npmjs.com
  2. Go to your profile → Access TokensGenerate New Token
  3. Select Automation type
  4. Copy the token

2. Add the token to GitHub Secrets#

  1. Open your repo on GitHub
  2. SettingsSecrets and variablesActions
  3. Click New repository secret
  4. Name: NPM_TOKEN
  5. Value: paste your npm token

Environments add an approval gate before publishing:

  1. SettingsEnvironmentsNew environment
  2. Name: npm-publish
  3. Add Required reviewers if you want manual approval before each publish

4. Enable GitHub Actions#

Make sure Actions are enabled for your repo: SettingsActionsAllow all actions.


Releasing a New Version#

Use the Release workflow in the Actions tab:

  1. Go to ActionsReleaseRun workflow
  2. Enter the new version (e.g. 1.1.0)
  3. Enter optional release notes
  4. Click Run workflow

The workflow will: - Update the root package.json version (and js/package.json, kept in sync for reference: see the note under npm Package Contents on why the root file is the one that actually matters for publishing) - Add a CHANGELOG.md entry - Commit the changes to main - Create and push the tag v1.1.0 - The Publish workflow triggers automatically from the tag

Option B - Manual tag push#

# 1. Update version in the root package.json (the one npm actually publishes from)
vim package.json       # set "version": "1.1.0"
vim js/package.json    # keep this in sync too, for reference/local `cd js && npm test` etc.

# 2. Update CHANGELOG.md
vim CHANGELOG.md      # add ## [1.1.0] section

# 3. Commit
git add package.json js/package.json CHANGELOG.md
git commit -m "chore: release v1.1.0"
git push origin main

# 4. Tag
git tag -a v1.1.0 -m "Rerius v1.1.0"
git push origin v1.1.0
# → publish.yml triggers automatically

Publish Pipeline Steps#

When a tag v* is pushed, publish.yml runs:

validate          check tag matches package.json version
    ↓
test              build + npm test on Linux x64 + macOS arm64
    ↓
prebuilds         parallel build on 4 platforms:
                    linux-x64     (ubuntu-latest)
                    linux-arm64   (ubuntu-24.04-arm)
                    darwin-arm64  (macos-latest)
                    darwin-x64    (macos-13)
    ↓
publish           download all prebuilds
                  add to js/prebuilds/
                  npm publish --provenance
    ↓
release           create GitHub Release with .node files attached
                  extract CHANGELOG.md section as release notes

Total duration: ~10-15 minutes.


Prebuilds#

Prebuilds are pre-compiled .node files for each platform. When present, users get a zero-compile npm install:

js/prebuilds/
├── rerius-linux-x64.node
├── rerius-linux-arm64.node
├── rerius-darwin-arm64.node
└── rerius-darwin-x64.node

index.js checks for prebuilds automatically:

// Order of lookup:
// 1. js/rerius.node           (local build, takes priority)
// 2. js/prebuilds/rerius-<platform>-<arch>.node
// 3. Throw with install instructions

Generating prebuilds locally#

# Run the prebuild workflow manually (Actions → Prebuild → Run workflow)
# Or build locally and copy:

make
mkdir -p js/prebuilds
cp js/rerius.node js/prebuilds/rerius-linux-x64.node   # on Linux x64
# cp js/rerius.node js/prebuilds/rerius-darwin-arm64.node  # on macOS M-series

Testing Before Publish#

# Full test suite
node js/test/basic.js

# Dry-run publish (shows what would be uploaded)
cd js && npm pack --dry-run

# Inspect the package contents
cd js && npm pack
tar -tzf rerius-*.tgz

# Test the packed package
npm install ./rerius-1.0.0.tgz
node -e "const n=require('rerius');console.log(n.version());"

npm Package Contents#

There are two package.json files in this repo, and only one of them produces a working package.

js/package.json lists ../src/, ../include/, ../arch/, and ../build_js.sh in its files array, trying to reach outside the js/ directory. npm's files field can't do this: npm pack run from js/ silently drops anything outside js/ (verified directly with npm pack --dry-run). A package published with cd js && npm publish would ship without the C source needed to compile the native addon, so postinstall would fail on any platform without a matching prebuild. Treat js/package.json as legacy/broken for standalone publishing: it's kept for reference, not as the publish target.

The root package.json (main: "js/index.js", files: ["js/", "src/", "include/", "platform/", "scripts/", "build_js.sh", "setup.sh", "LICENSE", "README.md"]) is the one that actually works: publish from the repository root, not from js/. Verified contents (npm pack --dry-run from the repo root):

rerius/
├── package.json          root manifest -- publish from here
├── LICENSE
├── README.md
├── setup.sh
├── build_js.sh
├── scripts/theme.sh
├── platform/              9 per-OS/arch .S / .asm entry stubs
├── include/                core/, formats/, arch/, ui/ headers
├── src/                     core/, formats/, arch/, analysis/, emu/, util/, cli/ (all C source)
└── js/
    ├── index.js            JS wrapper class
    ├── index.d.ts          TypeScript declarations
    ├── package.json
    ├── README.md
    ├── scripts/
    │   ├── install.js      postinstall build script
    │   └── build.js        npm run build
    ├── server/
    │   └── server.js       REST API server (42 endpoints at http://localhost:7070)
    ├── examples/            6 example scripts
    └── src/rerius_napi.c    N-API bindings

The C source (src/, include/, platform/) is included so users without a matching prebuild can still compile on install.


What Happens on npm install rerius#

npm install rerius
    ↓
npm downloads the package from registry
    ↓
postinstall: node scripts/install.js
    ↓
  1. Check if rerius.node already exists → done
  2. Check js/prebuilds/<platform>-<arch>.node → copy → done
  3. Find build_js.sh in repo root → run it → done
  4. Inline compile with clang/gcc → done
  5. If all fail: print helpful error, exit(0) so npm install succeeds
     → import will throw at runtime with instructions

Adding a New Platform#

To add a new prebuild target (e.g. Windows arm64 in future):

  1. Add a matrix entry to prebuild.yml and publish.yml
  2. Add the expected filename to the "Verify all expected prebuilds" step
  3. Add win32 handling to build_js.sh if needed
  4. Update index.js _findAddon() platform mapping

Troubleshooting#

npm install rerius fails to compile:

# Check if C compiler is available
clang --version || gcc --version

# Manually trigger compilation
node node_modules/rerius/scripts/install.js

CI fails on arm64 runner: The ubuntu-24.04-arm runner requires the repo has access to GitHub's ARM64 runner pool. Make sure your plan supports it (GitHub Free includes limited arm64 minutes).

npm publish fails - 403: - Token type must be Automation (not Read-only or Publish) - Run npm whoami locally to verify login: npm login - Check the npm-publish environment protection rules aren't blocking

Version mismatch error: The tag must match package.json (root) version exactly. Use the Release workflow to keep them in sync, or manually update package.json before tagging.

Note: js/package.json is a legacy file kept for reference. The root package.json is the authoritative npm package configuration.

Edit this page on GitHub Source: docs/PUBLISHING.md · Rerius v1.0.0
On this page
Publishing Rerius to npm Overview One-Time Setup 1. Create an npm token 2. Add the token to GitHub Secrets 3. Create the npm-publish environment (optional, recommended) 4. Enable GitHub Actions Releasing a New Version Option A - Automated (recommended) Option B - Manual tag push Publish Pipeline Steps Prebuilds Generating prebuilds locally Testing Before Publish npm Package Contents What Happens on npm install rerius Adding a New Platform Troubleshooting
ESC
↑↓ navigate openesc close