README.md (3125B)
Native JavaScript binding
Node.js uses Koffi to call the Haskell embedding ABI. Use Node.js 22 or newer. The binding is synchronous: reduction and IO block the calling JavaScript thread. Use a Worker or supervised process where appropriate. The browser/WASM adapters have their own execution interfaces.
nix build .#tricu-js .#tricu-js-tests --no-link
JS=$(nix path-info .#tricu-js)
"$JS/bin/arboricx-run" run test/fixtures/id.arboricx id hello
"$JS/bin/arboricx-run" run test/fixtures/true.arboricx true --format bool
Import Library from $JS/lib/src/lib.js:
const library = new Library();
const ctx = library.context();
try {
const argument = ctx.string('hello\0🌳');
const alias = ctx.retain(argument);
ctx.release(argument);
console.log(ctx.toString(alias));
} finally {
ctx.close();
}
Library(path) selects an explicit library. Otherwise discovery uses TRICU_LIB
or the library installed beside the module. Paths resolve through symlinks, and
one library is kept loaded per process. Preserve the complete native runtime
closure; the Nix package supplies it automatically.
Contexts and handles are bigint IDs. number accepts exact safe JS integers or
bigint in the uint64 range; toNumber returns bigint, including small values.
string rejects unpaired surrogates, and strings preserve embedded NULs.
bytes/toBytes exchange octet buffers. kind returns 0/1/2 for Leaf/Stem/Fork;
child returns an owned handle. apply creates a suspension, and reduce demands
its outer constructor. Observation/codecs also demand the parts they observe.
loadBundle(bytes, exportName) verifies a bundle and selects an explicit export.
runIO(program) runs the built-in native IO driver and returns
{outcome, value, cleanup}. Outcome 0/1/2 means completed/failed/cancelled; value
and cleanup are independently owned handles. Failure reasons stay lazy. Ordinary
error Results can be completion values. Boundary failures throw TricuError with
numeric status and diagnostic text.
Every handle returned by a successful call is owned. Release intermediates in
long-lived contexts. close releases all remaining roots and is idempotent;
Symbol.dispose also closes. Decoded buffers are copied into JS-owned buffers and
the native allocation is freed in finally.
The CLI requires run BUNDLE EXPORT, accepts text arguments, and takes explicit
--format string|number|bool|bytes (default string). Bytes render as hex. --io
selects IO execution; terminal failure/cancellation exits nonzero with the reason
left opaque. -- ends option parsing. Integer arguments are available through the
programmatic number method. Explicit formats describe the caller's intended
interpretation because tree encodings overlap.
The native bindings use Haskell value/IO semantics. Fuel, manual collection,
kernel-root helpers, implicit default-export selection, heuristic type decoding,
and the old inspect CLI are retired from this binding. Tests use independent
expected values and retain malformed-bundle, missing-export and ownership controls.