Skip to content
Draft
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
144 changes: 144 additions & 0 deletions .github/workflows/ci-node.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
# Build + test the ffi/node napi-rs addon.
#
# Two jobs:
# • test — native build + offline smoke tests on Linux/macOS/Windows. This is
# the fast signal that the addon loads and works on each OS.
# • build — the full cross-compile platform matrix (8 targets), proving each
# prebuilt `.node` compiles and packages:
# linux (gnu+musl) -> Zig + cargo-zigbuild (-x)
# macOS/Win -> native runners (arm64 host builds the x64 slice)
#
# All four Linux targets go through cargo-zigbuild rather than --use-napi-cross:
# napi-cross hits an npm optional-dependency bug (npm/cli#4828) on CI, and Zig
# already cross-compiles the full ant-core native tree (QUIC/libp2p/rustls/evmlib
# + C deps like secp256k1/blst) cleanly for musl and gnu alike.
#
# Follow-up: verify the gnu glibc floor zigbuild targets is old enough for broad
# distro support (musl is static, so unaffected).
#
# `fail-fast: false` so every target's result is visible in one run. `npm install`
# (not `npm ci`) so npm resolves @napi-rs/cli's per-platform optional native deps
# for the runner — a lockfile generated on one OS omits the others' binaries.

name: CI (node ffi)

on:
push:
branches: [main]
paths:
- "ffi/node/**"
- "ffi/rust/**"
- ".github/workflows/ci-node.yml"
pull_request:
paths:
- "ffi/node/**"
- "ffi/rust/**"
- ".github/workflows/ci-node.yml"
workflow_dispatch:

permissions:
contents: read

concurrency:
group: ci-node-${{ github.ref }}
cancel-in-progress: true

env:
CARGO_TERM_COLOR: always

defaults:
run:
working-directory: ffi/node

jobs:
test:
name: test (${{ matrix.os }}, node ${{ matrix.node }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
# @napi-rs/cli needs Node >= 20.12 to run (uses util.styleText); the
# built addon itself is napi8 (Node 16+). setup-node installs the latest
# minor, so "20" resolves to a 20.x that has styleText.
node: [20, 22]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node }}
- uses: dtolnay/rust-toolchain@stable
- uses: actions/cache@v4
with:
path: |
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
ffi/node/target/
key: test-${{ matrix.os }}-cargo-${{ hashFiles('ffi/node/Cargo.lock') }}
- run: npm install
- name: Build (native, debug)
run: npx napi build --platform
- name: Offline smoke tests
run: npm test

build:
name: build ${{ matrix.target }}
runs-on: ${{ matrix.host }}
strategy:
fail-fast: false
matrix:
include:
- target: x86_64-apple-darwin
host: macos-latest
- target: aarch64-apple-darwin
host: macos-latest
- target: x86_64-pc-windows-msvc
host: windows-latest
- target: aarch64-pc-windows-msvc
host: windows-latest
- target: x86_64-unknown-linux-gnu
host: ubuntu-latest
zig: true
build_args: -x
- target: aarch64-unknown-linux-gnu
host: ubuntu-latest
zig: true
build_args: -x
- target: x86_64-unknown-linux-musl
host: ubuntu-latest
zig: true
build_args: -x
- target: aarch64-unknown-linux-musl
host: ubuntu-latest
zig: true
build_args: -x
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
- uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.target }}
- name: Set up Zig + cargo-zigbuild (musl cross)
if: ${{ matrix.zig }}
run: |
pip3 install --break-system-packages "ziglang==0.13.0"
cargo install cargo-zigbuild --locked
- uses: actions/cache@v4
with:
path: |
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
ffi/node/target/
key: build-${{ matrix.target }}-cargo-${{ hashFiles('ffi/node/Cargo.lock') }}
- run: npm install
- name: Build ${{ matrix.target }}
run: npx napi build --platform --release --target ${{ matrix.target }} ${{ matrix.build_args }}
- uses: actions/upload-artifact@v4
with:
name: bindings-${{ matrix.target }}
path: ffi/node/*.node
if-no-files-found: error
151 changes: 151 additions & 0 deletions .github/workflows/publish-node.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
# Build the ffi/node addon across the platform matrix and publish
# @withautonomi/ant-ffi (+ its per-platform packages) to npm, in lockstep.
#
# Mirrors publish-python.yml: the same per-target build the CI job runs, then a
# single publish step. Platform packages (@withautonomi/ant-ffi-<platform>) are
# published by napi's `prepublish` (the package.json `prepublishOnly` hook that
# `npm publish` triggers); the main package carries them as optionalDependencies
# with os/cpu constraints, so `npm install` pulls only the matching prebuilt.
#
# ── One-time setup required before the first publish ──
# 1. Confirm publish access to a scope. NOTE: `@withautonomi` already EXISTS on
# npm (owned by the upstream core devs; currently holds the prior-network
# `@withautonomi/autonomi` client). Either get v2 publish rights to it, or
# point `name` in package.json at a fresh v2 scope. This is an org decision.
# 2. Create a GitHub environment named `npm` (Settings > Environments;
# optionally add reviewers as a release gate).
# 3. Provide npm auth — either:
# a. a granular automation token as repo/environment secret `NPM_TOKEN`
# (Automation type, scoped to the @withautonomi org), OR
# b. npm OIDC trusted publishing (no token) — provenance is already
# enabled below via `id-token: write`.
#
# ── How to run ──
# • Push a tag `node-v<version>` (e.g. node-v0.0.8) -> builds + publishes to npm.
# • Or run manually (Actions > Run workflow) with `publish`:
# none -> build the full matrix only (matrix smoke test, no upload)
# npm -> build + publish to npm

name: Publish Node (ant-ffi)

on:
workflow_dispatch:
inputs:
publish:
description: "Publish the built packages to npm"
type: choice
options: [none, npm]
default: none
push:
tags:
- "node-v*"

permissions:
contents: read

concurrency:
group: publish-node-${{ github.ref }}
cancel-in-progress: false

env:
CARGO_TERM_COLOR: always

defaults:
run:
working-directory: ffi/node

jobs:
build:
name: build ${{ matrix.target }}
runs-on: ${{ matrix.host }}
strategy:
fail-fast: false
matrix:
include:
- target: x86_64-apple-darwin
host: macos-latest
- target: aarch64-apple-darwin
host: macos-latest
- target: x86_64-pc-windows-msvc
host: windows-latest
- target: aarch64-pc-windows-msvc
host: windows-latest
- target: x86_64-unknown-linux-gnu
host: ubuntu-latest
zig: true
build_args: -x
- target: aarch64-unknown-linux-gnu
host: ubuntu-latest
zig: true
build_args: -x
- target: x86_64-unknown-linux-musl
host: ubuntu-latest
zig: true
build_args: -x
- target: aarch64-unknown-linux-musl
host: ubuntu-latest
zig: true
build_args: -x
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
- uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.target }}
- name: Set up Zig + cargo-zigbuild (musl cross)
if: ${{ matrix.zig }}
run: |
pip3 install --break-system-packages "ziglang==0.13.0"
cargo install cargo-zigbuild --locked
- uses: actions/cache@v4
with:
path: |
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
ffi/node/target/
key: publish-${{ matrix.target }}-cargo-${{ hashFiles('ffi/node/Cargo.lock') }}
- run: npm install
- name: Build ${{ matrix.target }}
run: npx napi build --platform --release --target ${{ matrix.target }} ${{ matrix.build_args }}
- uses: actions/upload-artifact@v4
with:
name: bindings-${{ matrix.target }}
path: ffi/node/*.node
if-no-files-found: error

publish:
name: publish to npm
needs: build
runs-on: ubuntu-latest
environment: npm
permissions:
contents: read
id-token: write # npm provenance / OIDC trusted publishing
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
registry-url: https://registry.npmjs.org
- run: npm install
- name: Download all prebuilt binaries
uses: actions/download-artifact@v4
with:
path: ffi/node/artifacts
merge-multiple: true
- name: Assemble per-platform npm dirs
run: |
npx napi create-npm-dirs
npx napi artifacts --output-dir artifacts
ls -R npm
- name: Publish
if: ${{ github.event_name == 'push' || inputs.publish == 'npm' }}
run: |
npm config set provenance true
npm publish --access public
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
7 changes: 7 additions & 0 deletions ffi/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ UniFFI-based foreign function interface bindings for the Autonomi network. Wraps
- **C#** - Generated via [`uniffi-bindgen-cs`](https://github.com/NordSecurity/uniffi-bindgen-cs) (v0.10.0+v0.29.4)
- **Kotlin** - Generated via `uniffi-bindgen` (v0.29.4) with JNA
- **Swift** - Generated via `uniffi-bindgen` (v0.29.4)
- **Python** - Generated via UniFFI's first-party Python backend (see [`python/`](python/README.md))
- **Node.js / Electron** - Hand-written [napi-rs](https://napi.rs) wrapper, **not** UniFFI (no maintained Node backend exists). Depends on `ant-ffi`'s plain `lib` target and mirrors the same surface with `#[napi]`; ships prebuilt per-platform `.node` addons via npm. See [`node/`](node/README.md).

## Architecture

Expand Down Expand Up @@ -40,6 +42,11 @@ ffi/
│ ├── Package.swift
│ └── AntFfi/
│ └── Generated/ # Auto-generated by uniffi-bindgen
├── python/ # First-party UniFFI Python bindings + wheels
├── node/ # napi-rs Node.js/Electron addon (NOT UniFFI)
│ ├── Cargo.toml # cdylib; path-deps on ../rust/ant-ffi
│ ├── package.json # @withautonomi/ant-ffi + platform matrix
│ └── src/ # #[napi] wrappers: client, wallet, convert, progress
├── scripts/
│ ├── build.sh # Linux/macOS build script
│ └── build.ps1 # Windows build script
Expand Down
15 changes: 15 additions & 0 deletions ffi/node/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Rust build output
target/

# Node
node_modules/

# napi-rs build artifacts (regenerated by `napi build` / CI prepublish)
*.node
index.js
index.d.ts

# Generated per-platform npm packages (created by `napi create-npm-dirs` / prepublish)
npm/
# Downloaded CI artifacts staging dir (publish workflow)
artifacts/
Loading
Loading