Skip to content

Supported payloads

The transport supports the following payloads:

  • number (including NaN, Infinity, and -Infinity)
  • string
  • boolean
  • bigint
  • undefined and null
  • plain JSON-like Object and Array
  • Envelope<header, payload> where header is JSON-like (or string) and payload is ArrayBuffer
  • Buffer (Node.js), ArrayBuffer
  • Uint8Array, Int32Array, Float64Array, BigInt64Array, BigUint64Array
  • DataView
  • Error (name, message, stack, and cause chain)
  • Date
  • symbol from Symbol.for(...) only
  • native Promise<supported> values at the host call boundary

If you need multiple values, pass a tuple or object as the single argument. These types are not supported directly:

  • Map, Set, WeakMap, and custom class instances (except Envelope and subclasses)
  • non-global symbols
  • Blob
  • functions

Promise values are accepted at the call.*() boundary, but promises themselves are runtime state and are not transferred through IPC as payloads. Only resolved values are serialized and sent to workers. If a promise input rejects, the host call rejects and the worker task is not executed. Only native Promise is accepted; thenables are treated as regular values.

See Promise inputs and awaited outputs for details.

type JSONValue =
| string
| number
| boolean
| null
| JSONArray
| JSONObject;
interface JSONObject {
[key: string]: JSONValue;
}
interface JSONArray extends Array<JSONValue> {}
type ValidInput =
| bigint
| void
| JSONValue
| symbol
| Envelope<JSONValue | string, ArrayBuffer>
| Uint8Array
| Int32Array
| Float64Array
| BigInt64Array
| BigUint64Array
| DataView
| ArrayBuffer
| Error
| Date;
type Args = ValidInput | Serializable;
type TaskInput = NoBlob<Args> | Promise<NoBlob<Args>>;

Different types take different code paths and have very different costs. Use the cheapest type that fits your data.

Header-only (fastest): number, boolean, undefined, null, Date, small string, small bigint. These fit in the call header with near-zero overhead. Prefer these whenever possible.

Static payload (fast): Symbol.for(...), large bigint, typed arrays (Uint8Array, Int32Array, etc.). Reuses a small buffer region alongside the header.

Dynamic payload (allocator path): Object, Array (JSON-serialized), Error, Date, and larger strings. These need allocation, serialization, and copying. Still faster than postMessage, but measurably heavier in hot loops.

See the Performance guide for per-type benchmarks and batching guidance.

Envelope is optimized for pair-like metadata + binary payload transport:

import { Envelope } from "@vixeny/knitting";
const message = new Envelope(
{ route: "/upload", contentType: "application/octet-stream" },
new Uint8Array([1, 2, 3]).buffer,
);

Error payloads preserve name, message, stack, and recursive cause chains. Both sync throws and async rejections inside tasks propagate back to the host as Error objects.