Publishing
The repository uses one lockstep SemVer version for the Rust crates, Nebulus, WASM npm metadata, and the docs site.
Use cargo release with the workspace release.toml to update the shared
version, update Bun lockfiles, update the changelog, create the release commit,
and create the annotated Git tag.
Install it once on your machine:
cargo install cargo-release git-cliff
Preview a release:
cargo release patch --workspace
Create the version bump commit, annotated Git tag, and push both:
cargo release patch --workspace --execute
Create the release commit and tag locally without pushing:
cargo release patch --workspace --execute --no-push
release.toml has publish = false, so local release commands do not publish
to crates.io. The release hook updates the Bun-managed package.json versions,
regenerates the docs bun.lock with bun install --lockfile-only, and
prepends release notes to CHANGELOG.md with git-cliff.
cargo release atomically pushes the release commit and its annotated tag. The
single master workflow detects that v0.2.0 points at the pushed commit. After
validation and site deployment pass, it calls the reusable release workflow to
publish crates.io packages, publish @openipc-rs/web through npm trusted
publishing, and upload Nebulus desktop and Android artifacts.
Required release secret:
CARGO_REGISTRY_TOKEN
Configure npm trusted publishing for @openipc-rs/web on npmjs.com:
| Field | Value |
|---|---|
| Publisher | GitHub Actions |
| Organization or user | neelsani |
| Repository | openipc-rs |
| Workflow filename | ci.yml |
| Allowed action | npm publish |
The publish job is implemented in reusable release.yml, but npm validates
the calling workflow for workflow_call, so the configured filename remains
ci.yml.
The existing Cloudflare secrets are required for deployments from master:
CLOUDFLARE_API_TOKENCLOUDFLARE_ACCOUNT_ID
CI deploys the public sites:
- Nebulus: nebulus.openipc-rs.neels.dev
- Docs: openipc-rs.neels.dev
Release commits use the same workflow run as ordinary master commits. The
release tag adds publishing and platform packaging after validation and site
deployment; it does not create a second tag-triggered workflow run.
Release Checklist
-
Make normal source commits.
-
Run a dry run:
cargo release patch --workspace -
Review the planned version bump, changelog, and files touched by the hook.
-
Execute the release:
cargo release patch --workspace --execute -
Watch the GitHub Actions run for the release commit on
master.
Use minor or major instead of patch when the public API or package
contract changes enough to require it.
The release hook syncs JavaScript package versions with Bun. If you ever need to manually align one package, use the same shape:
bun pm version 0.2.0 --cwd docs --no-git-tag-version --allow-same-version
Generated Artifacts
Generated artifacts are ignored by git:
- Rust
target/, .cargo-tools/,crates/openipc-web/pkg/,- app
node_modules/anddist/, - docs
node_modules/,.docusaurus/, andbuild/, - stray
package-lock.jsonfiles, - root-level package tarballs.
Clean them with:
sh scripts/clean-generated.sh
WASM npm Package
Build before packing or publishing:
bun run --cwd crates/openipc-web build
bun pm pack --cwd crates/openipc-web/pkg --dry-run
Publish when ready:
npm publish crates/openipc-web/pkg --access public --provenance
CI performs this automatically when the master commit carries the matching
annotated v* tag. The workflow builds the package with Bun, installs npm only
for the publish step, and runs npm publish so npm trusted publishing can issue
the release token.
Cargo Crates
The library crates are intended for crates.io publication:
openipc-coreopenipc-rtl88xxopenipc-videoopenipc-webwfb-rsnebulus
apps/openipc-cli is versioned with the workspace but marked publish = false.
The published Nebulus package contains its internal decode-worker binary
target; Trunk bundles that target into the site instead of publishing another
crate.
openipc-core is the easiest crate to publish because it owns protocol logic
and does not need USB access. openipc-video has target-specific decoder
dependencies for desktop, Android, and WebAssembly. openipc-rtl88xx,
openipc-web, and wfb-rs
depend on the published nusb-webusb package while importing it as nusb:
nusb = { package = "nusb-webusb", version = "0.2.3" }
Dry-run the workspace publish before publishing:
cargo publish --workspace --dry-run
Publish after logging in to crates.io or configuring CARGO_REGISTRY_TOKEN:
cargo publish --workspace
Nebulus is published as a Cargo package for source installation and reuse, and is also distributed as ready-to-run GitHub Release artifacts. Its versioned path dependencies resolve to the corresponding crates.io versions when Cargo packages it.
Desktop Releases
Nebulus desktop builds are uploaded to the GitHub Release for each v* tag.
Artifacts have explicit operating-system and architecture names:
nebulus-[platform]-[architecture]-[version].[ext]
Build targets:
| Release label | GitHub runner | Rust target |
|---|---|---|
linux-x64 | ubuntu-24.04 | x86_64-unknown-linux-gnu |
linux-arm64 | ubuntu-24.04-arm | aarch64-unknown-linux-gnu |
macos-apple-silicon | macos-15 | aarch64-apple-darwin |
macos-intel | macos-15-intel | x86_64-apple-darwin |
windows-x64 | windows-2025 | x86_64-pc-windows-msvc |
windows-arm64 | windows-11-arm | aarch64-pc-windows-msvc |
Linux releases are built on Ubuntu runners and published as architecture-named
executables; they are not separate per-distribution builds or AppImages. macOS
releases are .dmg disk images, Windows releases are installer .exe files,
and Android is one APK containing arm64-v8a, armeabi-v7a, x86_64, and x86.
The .app inside each macOS disk image is ad-hoc signed. Windows installers
and Linux executables are not code-signed. Users may see operating-system
warnings until platform signing and macOS notarization are configured.
Nebulus Web App
The hosted browser/WebUSB ground station is Nebulus. Build it with Trunk:
cd apps/nebulus
trunk build --release
The deployable output is apps/nebulus/dist. GitHub Actions builds it once and
deploys that artifact to the nebulus Cloudflare Pages project on master
pushes, including release commits. Deployment does not require a local script.