- Added repeatable `--tag` argument parsing in `gen-npm-packages.ts` and threaded parsed tags into `generateNpmPackages` for targeted leaf publishing. - Exported `prepareNativeCorePackage` and expanded package manifest typing to support scripted manifest rewrites used by release workflows. - Reworked install-test smoke logic to pack the host leaf package, pack the rewritten natives core, and assert the platform leaf package resolves from the core optional dependency.
7.8 KiB
Natives Addon Loader Runtime
This document covers the runtime loader shipped by @oh-my-pi/pi-natives: how native/index.js decides which .node file to require, how compiled-binary embedded payloads are extracted, and what startup failures report.
Implementation files
packages/natives/native/index.jspackages/natives/native/loader-state.jspackages/natives/native/embedded-addon.jspackages/natives/scripts/embed-native.tspackages/natives/package.json
Scope and responsibility
The loader is intentionally narrow:
- Build a platform/CPU-aware candidate list for addon filenames and directories.
- Treat an embedded-addon manifest as the authoritative compiled-binary signal when present.
- Optionally materialize an embedded addon into a versioned per-user cache directory.
- Attempt candidates in deterministic order and return the first addon that
require(...)loads.
The current loader does not run a separate validateNative(...) export-presence gate. API shape is provided by the generated N-API binding file (native/index.d.ts) and the loaded addon itself. A stale binary therefore normally fails as a missing property or native load error rather than as a custom "missing exports" validation error.
Runtime inputs and derived state
At module initialization, native/index.js computes:
- Platform tag:
${process.platform}-${process.arch}(for exampledarwin-arm64). - Package version: from
packages/natives/package.json. - Core directories:
leafPackageDir: directory of the platform leaf package, resolved viarequire.resolve("@oh-my-pi/pi-natives-<tag>/package.json");nullwhen no leaf is installed (e.g. local dev).nativeDir: package-localpackages/natives/native.execDir: directory containingprocess.execPath.versionedDir:<getNativesDir()>/<packageVersion>.userDataDirfallback:- Windows:
%LOCALAPPDATA%/ompor%USERPROFILE%/AppData/Local/omp. - Non-Windows:
~/.local/bin.
- Windows:
- Natives cache root (
getNativesDir()):- if
$XDG_DATA_HOME/ompexists,$XDG_DATA_HOME/omp/natives; - otherwise
~/.omp/natives.
- if
- Compiled-binary mode (
detectCompiledBinary): true if any of:- embedded-addon manifest is non-null,
PI_COMPILEDenv var is set,import.meta.urlcontains Bun embedded markers ($bunfs,~BUN,%7EBUN).
- Variant override:
PI_NATIVE_VARIANT(modern/baselineonly; invalid values ignored). - Selected variant: explicit override, otherwise runtime AVX2 detection on x64 (
modernif AVX2, elsebaseline).
Platform support and tag resolution
SUPPORTED_PLATFORMS is fixed to:
linux-x64linux-arm64darwin-x64darwin-arm64win32-x64
Unsupported platforms are not rejected before probing. The loader first tries the computed candidate paths. If all fail and platformTag is unsupported, it throws an unsupported-platform error listing supported tags.
Variant selection (modern / baseline / default)
x64 behavior
PI_NATIVE_VARIANT=modern|baselinewins when valid.- Otherwise AVX2 support is detected:
- Linux: scan
/proc/cpuinfoforavx2. - macOS:
sysctl -n machdep.cpu.leaf7_features, thenmachdep.cpu.features. - Windows: PowerShell
[System.Runtime.Intrinsics.X86.Avx2]::IsSupported.
- Linux: scan
- AVX2 selects
modern; unavailable or undetectable AVX2 selectsbaseline.
Non-x64 behavior
No variant suffix is used; the filename is pi_natives.<platform>-<arch>.node.
Filename construction
loader-state.js#getAddonFilenames returns:
- Non-x64 or no variant:
pi_natives.<tag>.node - x64 +
modern:pi_natives.<tag>-modern.nodepi_natives.<tag>-baseline.nodepi_natives.<tag>.node
- x64 +
baseline:pi_natives.<tag>-baseline.nodepi_natives.<tag>.node
The default unsuffixed fallback remains part of the x64 candidate list.
Candidate path construction and fallback ordering
resolveLoaderCandidates(...) expands every filename across directories, then de-duplicates while preserving first occurrence order.
Non-compiled runtime
For each filename, candidates are, in order:
<leafPackageDir>/<filename>(omitted whenleafPackageDirisnull)<nativeDir>/<filename><execDir>/<filename>
The leaf package dir comes first so the optional-dependency binary published with the release is preferred over any .node left in the core package's native/ (e.g. a stale local-dev build).
On Windows installs where nativeDir is inside a node_modules segment (shouldStageNodeModulesAddon), <versionedDir>/<filename> staging candidates are prepended ahead of the leaf candidates so a locked node_modules binary can be sidestepped during bun install -g updates.
Compiled runtime
For each filename, candidates are:
<versionedDir>/<filename><userDataDir>/<filename><nativeDir>/<filename><execDir>/<filename>
At load time, an extracted embedded candidate, when produced, is prepended ahead of these de-duplicated candidates.
Embedded addon extraction lifecycle
embedded-addon.js is generated by scripts/embed-native.ts. The reset stub exports embeddedAddon = null. A populated manifest has:
platformTagversionfiles[]entries withvariant,filename, andfilePath
Extraction (maybeExtractEmbeddedAddon) runs only when:
- compiled-binary mode is true,
embeddedAddonis non-null,- manifest
platformTagequals the runtime platform tag, - manifest
versionequals the package version, - a variant-appropriate embedded file exists.
Variant file selection:
- Non-x64: prefer
default, then first available file. - x64 +
modern: prefermodern, fallback tobaseline. - x64 +
baseline: requirebaseline.
Materialization:
- Ensure
<versionedDir>exists. - Reuse
<versionedDir>/<selected filename>if it already exists. - Otherwise read
selectedEmbeddedFile.filePathand write the target path. - Return the target path as the first candidate.
Directory creation or write failures are appended to the loader error list; probing continues through normal candidates.
Lifecycle and state transitions
Init
-> Load package metadata and embedded-addon manifest
-> Compute platform/version/variant/filenames/candidate paths
-> (compiled + embedded manifest matches?)
yes -> try extract to versionedDir (record errors, continue)
no -> skip extraction
-> For each runtime candidate in order:
require(candidate)
-> success: return addon exports (READY)
-> failure: record error, continue
-> none loaded:
if unsupported platform tag -> throw Unsupported platform
else -> throw Failed to load (tried-path diagnostics + hints)
Failure behavior and diagnostics
Unsupported platform
If all candidates fail and platformTag is not supported, the loader throws:
Unsupported platform: <tag>- supported platform list
- issue-reporting guidance
No loadable candidate
If the platform is supported but no candidate can be loaded, the final error includes:
Failed to load pi_natives native addon for <platformTag>or<platformTag> (<variant>)- every attempted path with the corresponding
require(...)error - mode-specific remediation hints
Compiled-binary startup failures
Compiled mode diagnostics include:
- expected versioned cache target paths (
<versionedDir>/<filename>), - remediation to delete the versioned cache and rerun,
- direct release download
curlcommands for each expected filename.
Non-compiled startup failures
Normal package/runtime diagnostics include:
- reinstall hint (
bun install @oh-my-pi/pi-natives), - local rebuild command (
bun --cwd=packages/natives run build), - optional x64 variant build hint (
TARGET_VARIANT=baseline|modern bun --cwd=packages/natives run build).