@desert-ant-labs/core
v3.2.0
Published
Shared JavaScript runtime for Desert Ant Labs on-device model SDKs: the LiteRT.js host session, the koffi native loader, and the FFI buffer reader that the per-model node packages build on.
Readme
@desert-ant-labs/core
Shared JavaScript runtime for Desert Ant Labs on-device
model SDKs. The per-model node packages (@desert-ant-labs/shapes,
@desert-ant-labs/emo, @desert-ant-labs/redact, ...) build their browser and
Node entries on these model-agnostic pieces, so each model ships only its payload
codecs and its public class - both entry points are a couple of lines of wiring.
Not meant to be used directly; it is the common core the model packages depend on.
What it provides
Browser-safe entry (@desert-ant-labs/core, no node:*):
createWasmSdk({ platform, packageName })- the whole browser/WebAssembly half of a model package: instantiate the core through the package's#platformseam, set up the LiteRT.js session, thenopen(options)either downloads the model from the Hub or adopts the files amodelBaseUrlserves, and returns a readyLoadedModel.LoadedModel- a loaded model behind an opaque core handle:run(text, options, { group, deviceId })returning anFfiReader, plusisDownloaded,withCallGroup, anddispose. The same object on both runtimes, so a package writes its public class once.makeModelHostSeam()/makeLiteRtHost(...)- the model host a wasm core is instantiated with (dalModelHostin its generatedImports, fromSources/JSHost/Host.swift) and the LiteRT.js implementation of it: named-tensorcreateSessionFrom*/runwith the correct dtype marshalling and LiteRT.js manual memory management. The seam is late-bound, so a core can instantiate before its session exists, and nothing is installed onglobalThis.loadLiteRt(...)/assertBrowserRuntime(...)- load@litertjs/coreonce per process (with an install hint) and guard against running the wasm runtime in plain Node.fetchSelfHostedModel(baseUrl, files)- fetch the files amodelBaseUrlserves: sidecars keyed by catalog name, artifact bytes for the host to compile.browserSetup/browserWasmDir/browserReadModelSource/browserCacheRoot- the browser half of a model's#platformseam.- The wasm ABI itself (
create,createSelfHosted,isDownloaded,download,run,endCallGroup,destroy,flushTelemetry), the twin of the nativedal_*symbols, is what BridgeJS generates from the@JSentry points in the model'sWeb/main.swift; its types live in the package's own generateddist/bridge-js.d.ts. Both setups return it, so a model package writes no wasm glue: options and results cross as FFIBuffer payloads it encodes with the codecs it already needs for the native entry. FfiReader/FfiWriter- big-endian cursor over the length-prefixed FFIBuffer payloads both cores speak (the JS counterpart of Kotlin'sFfiReader).
Node entry (@desert-ant-labs/core/node, uses node:* + koffi):
createNativeSdk({ here, packageName, modelId, coreName })- the native half of a model package, mirroringcreateWasmSdk: binds the prebuilt core and returns an SDK whoseopen(options)yields the sameLoadedModel.loadNative({ here, packageName, coreName, modelId })- the loader under it: resolves the prebuilt Swift core undernative/<platform>-<arch>, loads the LiteRT runtime first, binds the C ABI with koffi (genericdal_*calls plus the model's own<modelId>_create), and returnscallAsync+decodeResult+ cache-path helpers. SSR-safe node seam (@desert-ant-labs/core/platform-node, usesnode:*, no koffi):nodeSetup/nodeWasmDir/nodeReadModelSource/nodeCacheRoot- the Node half of the#platformseam, reached when a framework renders the universal wasm entry in Node (Next.js's Client-Component SSR pass).
The two node entries stay apart on purpose. koffi ships native .node addons,
and bundlers statically trace the require("koffi") inside the loader even
though it only runs lazily, so a package's #platform seam importing
/node makes an SSR build fail with Turbopack's "non-ecmascript placeable
asset" (or webpack's equivalent). A model package imports /node from its
/native entry only, and /platform-node from platform-node.js.
Audio models use the separate @desert-ant-labs/core/audio browser entry or
@desert-ant-labs/core/audio/node on Node. Text-model imports never traverse
the audio host or WAV codec.
@litertjs/core and koffi are optional peer dependencies: the browser path
needs @litertjs/core, the native Node path needs koffi, and neither is
required just to import the package.
Tests
mise run test:js # unit tests + the SSR module-graph guard (no network)
mise run test:bundles # the bundle matrix: real bundlers, real tarballsThe packages are isomorphic, so most of what can break lives in a bundler rather than in a function. Two layers cover it:
test/ssr-graph.test.mjswalks the static import graph the way a bundler does and fails if the browser or SSR seam reaches koffi or anode:builtin. Fast, offline, runs on every change.test/bundle/packs the core and every model package and builds them with esbuild, vite, webpack, and Next (Turbopack + webpack), plus plain Node imports of both entries. It reproduces consumer build failures exactly; see js/test/bundle/README.md.
