Skip to content

TypeScript Runtime API Reference ​

The TypeScript runtime provides the execution host, memory allocators, and WebAssembly loader for generated modules.


Generated Module Exports ​

Each module generated by emitTsGlueFiles exports:

initNimTs(options?: NimTsOptions): Promise<Exports> ​

Initializes the WebAssembly module. Subsequent calls return the cached exports object.

typescript
import { initNimTs } from './synth.js';

const exports = await initNimTs({
  wasmPath: '/wasm/synth.wasm'
});

getNimTs(): Exports ​

Synchronous getter returning the module's exported functions. Throws an error if initNimTs() has not been called and awaited.

getNimTsModule(): any ​

Returns the raw WebAssembly instance exports (WebAssembly.Instance.exports).

isInitialized(): boolean ​

Returns true if the WebAssembly module has finished loading and is ready for invocation.


NimTsOptions ​

typescript
export interface NimTsOptions {
  /** URL or file path to the .wasm binary */
  wasmPath?: string | URL;

  /** Pre-compiled WebAssembly.Module (ideal for AudioWorklet & Web Workers) */
  wasmModule?: WebAssembly.Module;

  /** Raw WebAssembly binary buffer (Uint8Array or ArrayBuffer) */
  wasmBytes?: BufferSource;

  /** Pre-existing WebAssembly.Instance */
  wasmInstance?: WebAssembly.Instance;

  /** Custom WebAssembly imports to merge into the import object */
  imports?: WebAssembly.Imports;
}

NimTsRuntime Class (@axiomantic/nimts/runtime) ​

The low-level runtime class used internally by generated wrappers:

typescript
import { NimTsRuntime } from '@axiomantic/nimts/runtime';

const runtime = new NimTsRuntime();
await runtime.init(wasmSource);

Methods ​

  • init(source?: string | Uint8Array | WebAssembly.Module): Promise<NimTsExports>: Compiles and instantiates the WebAssembly module.
  • getMemory(): WebAssembly.Memory: Accesses the underlying WebAssembly.Memory instance. Throws if uninitialized.
  • passString(str: string): { ptr: number; len: number }: Encodes a string into UTF-8, allocates memory in WASM, and writes the bytes.
  • readString(ptr: number, len: number): string: Decodes a UTF-8 string from WebAssembly linear memory.
  • passBytes(buf: Uint8Array | ArrayBuffer): { ptr: number; len: number }: Allocates memory in WASM and copies a byte buffer.
  • readBytes(ptr: number, len: number): Uint8Array: Creates a copy of a byte slice from WebAssembly linear memory.
  • free(ptr: number): void: Frees allocated memory in WASM.
  • createImportObject(): WebAssembly.Imports: Creates the standard WebAssembly imports object providing promise callbacks and the WASI preview1 proxy.

Projections & Streaming Classes ​

NimTsIterator<T> ​

Wraps an active Nim closure iterator in WebAssembly linear memory and implements the ES2015 IterableIterator<T> protocol.

typescript
const iter = exports.countUp(1, 10);

// Use in standard for..of loops
for (const n of iter) {
  console.log(n);
  if (n === 5) break; // Automatically triggers .return() and reclaims WASM memory
}

// Or spread into an array
const arr = [...exports.countUp(1, 5)];
  • next(): IteratorResult<T>: Retrieves the next element from the iterator.
  • return(): IteratorResult<T>: Deterministically disposes the iterator slot in WASM and frees heap handles upon early loop termination.
  • [Symbol.iterator](): Enables native JavaScript iteration.

NimTsChannel<T> ​

Wraps an asynchronous SPSC wait-free bounded channel and implements the ES2018 AsyncIterable<T> protocol.

typescript
const channel = exports.createEventStream();

// Consume asynchronously
for await (const event of channel) {
  processEvent(event);
}
  • send(item: T): boolean: Sends an item into the channel buffer.
  • recv(): Promise<T | null>: Awaits the next item from the channel.
  • close(): void: Closes the channel.
  • [Symbol.asyncIterator](): Enables native JavaScript for await..of iteration.

Web Worker Client Runtime (@axiomantic/nimts/worker) ​

The worker runtime hosts WebAssembly modules in background threads (browser Web Workers or node:worker_threads) and proxies function invocations asynchronously.

typescript
import { spawnWorker, extractTransfers, type WorkerClient } from '@axiomantic/nimts/worker';

spawnWorker<T>(moduleOrUrl: any, options?: SpawnWorkerOptions): Promise<WorkerClient<T>> ​

Spawns an isolated WebWorker or worker_threads worker, initializes the compiled NimTS module, and returns a typed proxy client.

typescript
const worker = await spawnWorker<MyExports>('./engine.js', {
  wasmPath: '/wasm/engine.wasm',
  transferBuffers: true
});

SpawnWorkerOptions ​

typescript
export interface SpawnWorkerOptions {
  /** Path or URL to the .wasm binary */
  wasmPath?: string | URL;

  /** Pre-compiled WebAssembly.Module */
  wasmModule?: WebAssembly.Module;

  /** WebAssembly binary bytes */
  wasmBytes?: BufferSource;

  /** Options forwarded to module initNimTs(opts) */
  initOptions?: Record<string, any>;

  /** Underlying Worker constructor options */
  workerOptions?: any;

  /** Automatically detach and transfer ArrayBuffer / TypedArray instances (default: true) */
  transferBuffers?: boolean;
}

WorkerClient<T> Interface ​

A transparent dynamic proxy wrapping all exported functions on T:

  • Transparent Promise Wrapping: Every exported synchronous proc (...args) => R becomes an asynchronous method (...args) => Promise<R>.
  • Automatic Future[T] Awaiting: Procs returning Nim Future[T] are awaited off-thread inside the worker, settling the caller's Promise with the unwrapped value or rejecting on exception.
  • Dual Promise & AsyncIterable Streaming: Procs returning Channel[T] or NimTsChannel[T] stream items across a dedicated MessagePort. The returned call object can be consumed via for await (const chunk of worker.stream()) or directly awaited as an aggregated array with await worker.stream().
  • terminate(): Promise<void>: Cleanly terminates the worker thread, closes communication ports, and rejects any pending RPC calls with 'Worker has been terminated'.
  • readonly isTerminated: boolean: Flag indicating whether the worker has been terminated.
  • readonly rawWorker: Worker: Direct access to the underlying platform Worker instance.

Zero-Copy Buffer Transfers ​

By default (transferBuffers: true), any argument or return value containing an ArrayBuffer or TypedArray backing buffer is automatically collected via extractTransfers and included in the postMessage transfer list.

IMPORTANT

When a buffer is transferred, its memory ownership moves to the recipient thread and the sender's buffer is detached (byteLength becomes 0). This eliminates memory copying overhead and provides maximum throughput for large audio DSP blocks and binary streams. If you need to keep the sender's buffer intact, pass { transferBuffers: false } or .slice() the buffer before passing.

extractTransfers(val: unknown, set?: Set<ArrayBuffer>): ArrayBuffer[] ​

Recursively inspects an object, array, or primitive and extracts all unique ArrayBuffer and TypedArray.buffer references suitable for the postMessage transfer list.

Vite ?worker Query Integration ​

When using @axiomantic/nimts/vite, importing any .nim file with ?worker emits an instantiable Worker class:

typescript
import EngineWorker from './engine.nim?worker';

// Instantiates and spawns the worker client:
const worker = await new EngineWorker();
// Or using static helper:
// const worker = await EngineWorker.spawn();

const result = await worker.addNumbers(10, 20); // 30
await worker.terminate();

Released under the MIT License.