Skip to content

v0.7.0 — Mojo 1.0.0 stable, and napi-mojo is a source framework

Choose a tag to compare

@codetalcott codetalcott released this 12 Aug 14:19
· 235 commits to main since this release
02a14b7

Two headline changes: the toolchain moves to stable Mojo 1.0.0, and the npm package now presents itself as the source framework it actually is.

⚠️ Breaking — require('napi-mojo') no longer returns the addon

napi-mojo is a source framework, the way node-addon-api is for C++, and the package now says so.

// 0.6.0
const m = require('napi-mojo');
m.hello();

// 0.7.0
const napiMojo = require('napi-mojo');
napiMojo.include;   // …/node_modules/napi-mojo/src — pass to `mojo build -I`
napiMojo.generator; // the TOML → Mojo code generator

const demo = require('napi-mojo/demo'); // the prebuilt demo addon
demo.hello();

The demo's Mojo source no longer ships — src/addon/, src/lib.mojo, src/generated/ and src/exports.toml are excluded from the package (they remain in the repo as the test harness). The publish gate now asserts their absence and loads the packed index.js to verify the entry paths resolve, so the identity cannot silently regress.

Mojo 1.0.0 stable

The pin moves from a nightly to stable Mojo 1.0.0 (max = "==26.5.0", stable conda channel).

The framework now tracks stable Mojo releases, not nightlies. napi-mojo ships source that your addon compiles against, so the pin is part of the public contract — a nightly pin forces every consumer onto that exact nightly. The Nightly Canary still tests the next release ahead of time.

Adoption required zero source changes. Everything the codebase had migrated for under the "dev2026080905" heading turned out to be Mojo 1.0.0 content, because changelog entries rotate out of nightly-changelog.md into docs/releases/vX.Y.Z.md at release close. Verified green on both Mojo 1.0.0 stable and the latest 26.6 nightly (1.1.0.dev2026081105).

The unsafe_ rename migration

The full raw-pointer surface was renamed upstream; ~1,500 sites migrated: UnsafePointer → Pointer, .bitcast → .unsafe_bitcast, alloc → unsafe_alloc, ptr[i] → ptr[unsafe_offset=i], ptr + n → ptr.unsafe_offset(n), __del__ → __deinit__, InlineArray → Array. parallelize moved to max.algorithm, and the hand-rolled AsyncRT init was replaced by the official std.runtime.initialize_runtime().

Hardening — the guards had blind spots

A full architecture review found that every significant bug sat in a documented guard's blind spot, so this closes the guards' scopes as well as the bugs.

CI was lying. Three test suites resolved to the published v0.2.10 platform package instead of the build under test — the lockfile's version said 0.6.0 while its resolved URL still pinned darwin-arm64-0.2.10.tgz. Tests now load build/index.node directly, and sync-versions.mjs drops resolved/integrity when relabeling.

Widening the compile-coverage gate immediately caught five latent broken bodies shipped since dev2026072306 — both register_method overloads and three throw helpers missing .as_unsafe_any_origin(), never type-checked because Mojo elaborates imported-package bodies only when called.

Framework fixes: unwrap_native[T] was paying a full dlsym per class-method call; ModuleBuilder.flush() double-freed on a second call and leaked on failure; read_latin1 leaked its heap buffer on a raise; all six AsyncWork settle sites now delete the work handle on every path; JsUInt32/JsInt64 gained the env-only create overloads that made generated async uint32/int64 returns uncompilable. Two comptime layout asserts turn silent-corruption assumptions into build failures.

Generated async now settles with zero dlsym. A process-global bindings cache was spiked and rejected — Mojo rejects module-level var outright — so the generated async data struct threads bindings_addr from the entry callback to the complete callback instead.

Security

js-yaml 3.15.0 → 3.15.1, clearing GHSA-5p4m-2wfm-xmqj. Dev-scope only — npm audit --omit=dev reported 0 vulnerabilities, so published consumers were never affected.

Also

  • docs/plan-toolchain-uv-vs-pixi.md records a verified evaluation of uv as an alternative to pixi (uv works and produces an identical build hash; decision is to keep pixi, with the one blocker documented).
  • sync-versions.mjs now owns pixi.toml's workspace version — the one version string nothing synced, which had already drifted once.

Verified

  • 641 Jest tests across 82 suites, plus 7 GC finalizer tests
  • 641 tests pass clean under Guard Malloc with MALLOC_STRICT_SIZE=1
  • Compile-coverage target elaborates all 183 public framework method names
  • A consumer addon compiles against the packed src/ and loads correctly
  • Release pipeline rehearsed end-to-end on both platforms before tagging
  • Per-call overhead 191–327 ns, unchanged

Requires: Mojo 1.0.0 · Node.js 22.12+ (N-API v10). Prebuilt demo binaries for darwin-arm64 and linux-x64.