> ## Documentation Index
> Fetch the complete documentation index at: https://iii.dev/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Node.js SDK

> API reference for the iii SDK for Node.js / TypeScript.

## Installation

```bash theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
npm install iii-sdk
```

## Initialization

### registerWorker

Register the worker with a iii instance, returns a connected worker client.
The WebSocket connection is established automatically.

**Signature**

```typescript theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
registerWorker(address?: string, options?: InitOptions) => IIIClient
```

> [tab] Parameters
>
> **address** `string`
>
> WebSocket URL of the III engine. Omit to resolve it from
> `process.env.III_URL`, falling back to DEFAULT\_ENGINE\_URL.
>
> **options** `InitOptions`
>
> Optional InitOptions for worker name, timeouts, reconnection, and OTel.
>
> **`InitOptions` fields**
>
> **enableMetricsReporting** `boolean`
>
> Enable worker metrics via OpenTelemetry. Defaults to `true`.
>
> **headers** `Record\<string, string\>`
>
> Custom HTTP headers sent during the WebSocket handshake, on the main connection and on streaming channels. `Authorization: Bearer $III_TOKEN` is added unless you set `Authorization` here.
>
> **invocationTimeoutMs** `number`
>
> Default timeout for `worker.trigger()` invocations in milliseconds. Defaults to `30000`.
>
> **namespace** `string`
>
> Namespace this worker belongs to. Resolution order: `options.namespace` -> `process.env.III_NAMESPACE` -> undefined. When undefined the engine applies its `default` namespace. It scopes more than the registration. The worker and its functions register here, so identically-named entries coexist across namespaces, and everything the worker does afterwards follows it: a `trigger` resolves its target here, and a `registerTrigger` binds here, unless the call names another namespace. One declaration places the whole worker.
>
> **otel** `Omit\<OtelConfig, 'engineWsUrl' | 'engineWsHeaders'\>`
>
> OpenTelemetry configuration. OTel is initialized automatically by default. Set `{ enabled: false }` or env `OTEL_ENABLED=false/0/no/off` to disable. The `engineWsUrl` is set automatically from the III address, and `engineWsHeaders` from the handshake headers of the main connection.
>
> **reconnectionConfig** `Partial\<IIIReconnectionConfig\>`
>
> WebSocket reconnection behavior.
>
> **workerDescription** `string`
>
> One-line, human/LLM-readable summary of what this worker does. Surfaces in `engine::workers::list` / `engine::workers::info`.
>
> **workerName** `string`
>
> Display name for this worker. A non-empty `III_WORKER_NAME` overrides it. Defaults to `hostname:pid`.

> [tab] Example
>
> ```typescript theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
> import { registerWorker } from 'iii-sdk'
>
> // Address from III_URL, set by whatever supervisor spawned this worker.
> const worker = registerWorker()
>
> // Or explicitly, which always wins over the environment.
> const other = registerWorker('ws://localhost:49134', { workerName: 'my-worker' })
> ```

## Methods

### registerTrigger

> [!WARNING]
>
> **Deprecated.** Use IIIClient.observe instead: `iii.observe({ function_id, args, filters }, target, { metadata })`. Logs a warning once per process. The http, cron, queue, state, stream, pubsub and database workers still publish trigger types: keep using `registerTrigger` for them until they ship source functions. Migration guide: [https://iii.dev/docs/upgrading/from-0-24-x](https://iii.dev/docs/upgrading/from-0-24-x.md)

Registers a new trigger. A trigger is a way to invoke a function when a certain event occurs.

**Signature**

```typescript theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
registerTrigger(trigger: RegisterTriggerInput) => Trigger
```

> [tab] Parameters
>
> **trigger** `RegisterTriggerInput` *required*
>
> The trigger to register.
>
> **`RegisterTriggerInput` fields**
>
> **config** `unknown` *required*
>
> Trigger-type-specific configuration, matching the shape the trigger type expects.
>
> **function\_id** `string` *required*
>
> ID of the function this trigger invokes when it fires.
>
> **metadata** `Record\<string, unknown\>`
>
> Arbitrary user-specifiable metadata supplied to the triggered handler function on every invocation.
>
> **namespace** `string`
>
> Namespace the trigger's target function resolves in. Omitting it does not bind in the engine's default: `registerTrigger` fills it from this worker's namespace, because the function a trigger names is one this worker registered, and that landed in the worker's namespace. Name another namespace, `default` included, to bind elsewhere.
>
> **trigger\_namespace** `string`
>
> Namespace to find the trigger type's provider in. Omitting it is not the same as `'default'`: it asks the engine to resolve, taking this worker's namespace first and the engine's own second. That is what lets a project ship its own provider for a type id the engine also provides, while a worker that has not been migrated keeps reaching the engine's without saying so. Naming one is strict.
>
> **type** `string` *required*
>
> Identifier of the registered trigger type this trigger uses (e.g. `storage::object-created`, `http`).

> [tab] Example
>
> ```typescript theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
> const trigger = worker.registerTrigger({
>   type: 'cron',
>   function_id: 'my-service::process-batch',
>   config: { expression: '0 */5 * * * * *' },
> })
>
> // Later, remove the trigger
> trigger.unregister()
> ```

***

### registerFunction

Registers a new function with a local handler or an HTTP invocation config.

**Signature**

```typescript theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
registerFunction(functionId: string, handler: HttpInvocationConfig | RemoteFunctionHandler<any, any>, options?: RegisterFunctionOptions) => FunctionRef
```

> [tab] Parameters
>
> **functionId** `string` *required*
>
> Unique identifier for the function.
>
> **handler** `HttpInvocationConfig | RemoteFunctionHandler\<any, any\>` *required*
>
> Async handler for local execution, or an HTTP invocation config for external functions (Lambda, Cloudflare Workers, etc.).
>
> **options** `RegisterFunctionOptions`
>
> Optional function registration options (description, request/response formats, metadata).
>
> **`RegisterFunctionOptions` fields**
>
> **description** `string`
>
> The description of the function.
>
> **invocation** `HttpInvocationConfig`
>
> HTTP invocation config for external HTTP functions (Lambda, Cloudflare Workers, etc.).
>
> **localDispatch** `boolean`
>
> Calls this worker makes to its own function run in-process once the engine confirmed it (default `true`). Set `false` for a handler that must always run through the engine.
>
> **metadata** `Record\<string, unknown\>`
>
> Arbitrary metadata attached to the function.
>
> **observe** `ObserveHooks`
>
> Makes the function observable on its own terms: owner delivery (`delivery: 'owner'`, `args_format`), and callbacks when an observer is added or removed. Without it the function is still observable (auto delivery, no args).
>
> **request\_format** `RegisterFunctionFormat`
>
> The request format of the function.
>
> **response\_format** `RegisterFunctionFormat`
>
> The response format of the function.

> [tab] Example
>
> ```typescript theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
> // Local handler
> const ref = worker.registerFunction(
>   'greet',
>   async (data: { name: string }) => ({ message: `Hello, ${data.name}!` }),
>   { description: 'Returns a greeting' },
> )
>
> // HTTP invocation
> const lambdaRef = worker.registerFunction(
>   'external::my-lambda',
>   {
>     url: 'https://abc123.lambda-url.us-east-1.on.aws',
>     method: 'POST',
>     timeout_ms: 30_000,
>     auth: { type: 'bearer', token_key: 'LAMBDA_AUTH_TOKEN' },
>   },
>   { description: 'Proxied Lambda function' },
> )
>
> // Later, remove the function
> ref.unregister()
> ```

***

### trigger

Invokes a function using a request object.

**Signature**

```typescript theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
trigger(request: TriggerRequest<TInput>) => Promise<TOutput>
```

> [tab] Parameters
>
> **request** `TriggerRequest\<TInput\>` *required*
>
> The trigger request containing function\_id, payload, and optional action/timeout.
>
> **`TriggerRequest` fields**
>
> **action** `TriggerAction`
>
> Sets how the trigger is routed. Omit for a synchronous request/response. Specify for a specific routing scheme (e.g. `TriggerAction.Enqueue()`, `TriggerAction.Void()`).
>
> **dispatch** `'auto' | 'remote'`
>
> `auto` (default) runs a function this worker hosts in-process when the engine confirmed it for local dispatch; `remote` always goes through the engine. Tests use it, and so do callers that rely on engine-side effects.
>
> **function\_id** `string` *required*
>
> ID of the function to invoke.
>
> **metadata** `unknown`
>
> Arbitrary user-specifiable metadata supplied to the triggered handler function on every invocation.
>
> **namespace** `string`
>
> Target namespace for routing. Omit to inherit this worker's; say `default` to reach the engine's from a namespaced worker. Serialized into the InvokeFunctionMessage `namespace` field.
>
> **payload** `TInput` *required*
>
> Input data passed to the function.
>
> **timeoutMs** `number`
>
> Override the default invocation timeout, in milliseconds.

> [tab] Example
>
> ```typescript theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
> // Synchronous invocation
> const result = await worker.trigger<{ name: string }, { message: string }>({
>   function_id: 'greet',
>   payload: { name: 'World' },
>   timeoutMs: 5000,
> })
> console.log(result.message) // "Hello, World!"
>
> // Fire-and-forget
> await worker.trigger({
>   function_id: 'send-email',
>   payload: { to: 'user@example.com' },
>   action: TriggerAction.Void(),
> })
>
> // Enqueue for async processing (the queue must be declared in the
> // queue worker's queue_configs)
> const receipt = await worker.trigger({
>   function_id: 'process-order',
>   payload: { orderId: '123' },
>   action: TriggerAction.Enqueue({ queue: 'orders' }),
> })
> ```

***

### registerTriggerType

> [!WARNING]
>
> **Deprecated.** Register a function with an observe descriptor instead: `registerFunction(id, handler, { observe: { delivery: 'owner', onObserverAdded, onObserverRemoved } })`. Logs a warning once per process. Migration guide: [https://iii.dev/docs/upgrading/from-0-24-x](https://iii.dev/docs/upgrading/from-0-24-x.md)

Registers a new trigger type. A trigger type is a way to invoke a function when a certain event occurs.

**Signature**

```typescript theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
registerTriggerType(triggerType: RegisterTriggerTypeInput, handler: TriggerHandler<TConfig>) => TriggerTypeRef<TConfig>
```

> [tab] Parameters
>
> **triggerType** `RegisterTriggerTypeInput` *required*
>
> The trigger type to register.
>
> **`RegisterTriggerTypeInput` fields**
>
> **description** `string` *required*
>
> Human-readable description of what this trigger type does.
>
> **id** `string` *required*
>
> Unique identifier for the trigger type (e.g. `state`, `durable:subscriber`).
>
> **namespace** `string`
>
> Namespace this provider serves. Omit to let the engine use this connection's own, which is what a worker providing a trigger type for its own project wants.
>
> **handler** `TriggerHandler\<TConfig\>` *required*
>
> The handler for the trigger type.
>
> **`TriggerHandler` fields**
>
> **registerTrigger** `(config: TriggerConfig\<TConfig\>) =\> Promise\<void\>` *required*
>
> Called when a trigger instance is registered.
>
> **unregisterTrigger** `(config: TriggerConfig\<TConfig\>) =\> Promise\<void\>` *required*
>
> Called when a trigger instance is unregistered.

> [tab] Example
>
> ```typescript theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
> type CronConfig = { expression: string }
>
> worker.registerTriggerType<CronConfig>(
>   { id: 'cron', description: 'Fires on a cron schedule' },
>   {
>     async registerTrigger({ id, function_id, config }) {
>       startCronJob(id, config.expression, () =>
>         worker.trigger({ function_id, payload: {} }),
>       )
>     },
>     async unregisterTrigger({ id }) {
>       stopCronJob(id)
>     },
>   },
> )
> ```

***

### unregisterTriggerType

> [!WARNING]
>
> **Deprecated.** Trigger types are replaced by functions with an observe descriptor.

Unregisters a trigger type.

**Signature**

```typescript theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
unregisterTriggerType(triggerType: RegisterTriggerTypeInput) => void
```

> [tab] Parameters
>
> **triggerType** `RegisterTriggerTypeInput` *required*
>
> The trigger type to unregister.
>
> **`RegisterTriggerTypeInput` fields**
>
> **description** `string` *required*
>
> Human-readable description of what this trigger type does.
>
> **id** `string` *required*
>
> Unique identifier for the trigger type (e.g. `state`, `durable:subscriber`).
>
> **namespace** `string`
>
> Namespace this provider serves. Omit to let the engine use this connection's own, which is what a worker providing a trigger type for its own project wants.

> [tab] Example
>
> ```typescript theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
> worker.unregisterTriggerType({ id: 'cron', description: 'Fires on a cron schedule' })
> ```

***

### currentInvocation

The invocation the calling code runs in (remote or local handler), or
`undefined` outside any handler.

**Signature**

```typescript theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
currentInvocation() => InvocationContext | undefined
```

***

### getAddress

Engine address this worker resolved to: the explicit `registerWorker`
argument, else `III_URL`, else `ws://127.0.0.1:49134`.

**Signature**

```typescript theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
getAddress() => string
```

***

### getConnectionState

The current WebSocket connection state. `'failed'` is terminal: it follows
a fatal registration rejection (see getFatalError). Mirrors the
Python/Rust SDKs' `get_connection_state()`.

**Signature**

```typescript theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
getConnectionState() => IIIConnectionState
```

***

### getFatalError

The fatal registration rejection that terminated this connection, if any
(e.g. a `WORKER_NAMESPACE_CONFLICT`); `undefined` while healthy. Mirrors the
Python (`_fatal_error`) and Rust (`fatal_error()`) SDKs.

**Signature**

```typescript theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
getFatalError() => RegistrationRejectedError | undefined
```

***

### observe

Observes a function: every event of `source` that passes its `filters`
invokes `target`, a registered function. Returns synchronously (also
before the connection is up); the observer is replayed with the same id
on reconnect. Errors show up as state `error` and reject `ready()`.

**Signature**

```typescript theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
observe(source: ObserveSource, target: Target, options?: ObserverOptions) => ObserverHandle
```

> [tab] Parameters
>
> **source** `ObserveSource` *required*
>
> What is observed: `function_id`, `args` (owner-delivered functions only), `filters`, `on`, `capture`, `deliver`.
>
> **`ObserveSource` fields**
>
> **args** `Record\<string, unknown\>`
>
> Owner-delivered functions only: for the owner; validated against its `args_format`.
>
> **capture** `Capture[]`
>
> Auto and `obs.emit`; default `['input', 'output', 'caller']`.
>
> **deliver** `'input' | 'output' | 'envelope'`
>
> Auto and `obs.emit`; default `'envelope'`.
>
> **filters** `Filter`
>
> Which events reach the target; `{}` (or absent) = every event.
>
> **function\_id** `string` *required*
>
> The observed function.
>
> **namespace** `string`
>
> Defaults to this worker's namespace (`engine::*` resolves to `default`).
>
> **on** `'error' | 'success' | 'complete'`
>
> Auto only; default `'success'`.
>
> **target** `Target` *required*
>
> The function to invoke.
>
> **options** `ObserverOptions`
>
> `id`, `max_fires`, `expires_in_ms`, `max_in_flight`, `metadata`.
>
> **`ObserverOptions` fields**
>
> **expires\_in\_ms** `number`
>
> The observer is disposed this many milliseconds after it is created (`EXPIRED`). Default: never.
>
> **id** `string`
>
> Default: a random UUID, stable across replays.
>
> **max\_fires** `number`
>
> The observer is disposed after this many activations (`MAX_FIRES`). Default: unlimited.
>
> **max\_in\_flight** `number`
>
> Activations running at once; further ones queue, then drop as `OVERFLOW`. Default: the engine's `observers.default_max_in_flight` (64).
>
> **metadata** `Record\<string, unknown\>`
>
> Delivered as the metadata sidecar of every activation.

> [tab] Example
>
> ```typescript theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
> // A regular function: large orders reach alerts::big-order
> worker.observe(
>   { function_id: 'orders::create', filters: { 'input.total': { $gte: 500 } } },
>   'alerts::big-order',
> )
>
> // An engine-hosted event source, delivered as the event itself
> const workers = worker.observe(
>   { function_id: 'engine::on-workers-changed', deliver: 'input' },
>   'ops::on-worker-change',
> )
> await workers.ready()
> ```

***

### shutdown

Gracefully shutdown the iii, cleaning up all resources.

**Signature**

```typescript theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
shutdown() => Promise<void>
```

#### Example

```typescript theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
process.on('SIGTERM', async () => {
  await worker.shutdown()
  process.exit(0)
})
```

## Subpath Exports

The `iii-sdk` package provides additional entry points:

| Import path | Contents |
| - | - |
| `iii-sdk/channel` | `Channel`, `ChannelReader`, `ChannelWriter`, `StreamChannelRef` |
| `iii-sdk/engine` | `EngineFunctions`, `EngineTriggers`, `RemoteFunctionHandler` |
| `iii-sdk/errors` | `InvocationError`, `InvocationErrorInit`, `ObserveRejection`, `RegistrationRejectedError`, `RegistrationRejectedInit`, `isErrorBody` |
| `iii-sdk/helpers` | `ChannelDirection`, `ChannelItem`, `createChannel`, `createStream`, `extractChannelRefs`, `isChannelRef` |
| `iii-sdk` | `Caller`, `CallerInfo`, `Capture`, `DEFAULT_ENGINE_URL`, `EnqueueResult`, `Filter`, `FunctionRef`, `IIIClient`, `IIIConnectionState`, `InitOptions`, `InvocationContext`, `InvocationError`, `InvocationErrorInit`, `JsonValue`, `MiddlewareFunctionInput`, `ObserveDoc`, `ObserveHooks`, `ObserveReason`, `ObserveRejection`, `ObserveSource`, `Observed`, `Observer`, `ObserverHandle`, `ObserverOptions`, `ObserverState`, `RegisterFunctionOptions`, `RegistrationRejectedError`, `StreamRequest`, `StreamResponse`, `Target`, `TelemetryOptions`, `TriggerAction`, `registerWorker` |
| `iii-sdk/protocol` | `ActivationWire`, `CallerWire`, `CaptureWire`, `DroppedReportStatsWire`, `ErrorBody`, `FEATURE_LOCAL_DISPATCH_V1`, `FEATURE_OBSERVE_V1`, `FunctionRegisteredMessage`, `InvocationsObservedMessage`, `LocalFunctionStatsWire`, `LocalInvocationStatsMessage`, `MessageType`, `ObserveDescriptorWire`, `ObserveMessage`, `ObserveResultMessage`, `ObserveSourceWire`, `ObservedItemWire`, `ObserverAckMessage`, `ObserverAddedMessage`, `ObserverInfoWire`, `ObserverRemovedMessage`, `ObserverStateChangedMessage`, `RegisterFunctionFormat`, `RegisterFunctionInput`, `RegisterFunctionMessage`, `RegisterFunctionOptions`, `SDK_FEATURES`, `TriggerRequest`, `UnobserveMessage` |
| `iii-sdk/runtime` | `FunctionRef`, `IIIConnectionState` |
| `iii-sdk/state` | `IState`, `StateDeleteInput`, `StateDeleteResult`, `StateEventData`, `StateEventType`, `StateGetInput`, `StateListInput`, `StateSetInput`, `StateSetResult`, `StateUpdateInput`, `StateUpdateResult` |
| `iii-sdk/stream` | `IStream` |

## Types

### iii-sdk

[`Caller`](#caller) · [`CallerInfo`](#callerinfo) · [`Capture`](#capture) · [`EnqueueResult`](#enqueueresult) · [`Filter`](#filter) · [`InitOptions`](#initoptions) · [`InvocationContext`](#invocationcontext) · [`JsonValue`](#jsonvalue) · [`MiddlewareFunctionInput`](#middlewarefunctioninput) · [`Observed`](#observed) · [`ObserveDoc`](#observedoc) · [`ObserveHooks`](#observehooks) · [`Observer`](#observer) · [`ObserveReason`](#observereason) · [`ObserverHandle`](#observerhandle) · [`ObserverOptions`](#observeroptions) · [`ObserverState`](#observerstate) · [`ObserveSource`](#observesource) · [`StreamRequest`](#streamrequest) · [`StreamResponse`](#streamresponse) · [`Target`](#target) · [`TelemetryOptions`](#telemetryoptions) · [`TriggerAction`](#triggeraction)

#### Caller

Who started an invocation: the worker (`worker_id` / `worker_name`, stamped
by the engine), and the function and invocation the call was made from.

| Name | Type | Required | Description |
| - | - | - | - |
| `function_id` | `string` | No | The handler the call was made from; absent for top-level calls. |
| `invocation_id` | `string` | No | - |
| `parent` | Omit\<[`Caller`](#caller), "parent"> | No | The caller of that handler, one level only. |
| `worker_id` | `string` | No | Absent on activations, whose caller is the engine (`worker_name: 'iii-engine'`). |
| `worker_name` | `string` | No | - |

***

#### CallerInfo

A caller as the SDK knows it: every field may be missing (a top-level call
has no function; a call made before `WorkerRegistered` has no worker id).

```typescript theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
type CallerInfo = Partial<Omit<Caller, "parent">> & { parent?: Partial<Omit<Caller, "parent">> }
```

***

#### Capture

What an observer ships to its target. Default `['input', 'output', 'caller']`.

```typescript theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
type Capture = "input" | "output" | "error" | "caller" | "metadata"
```

***

#### EnqueueResult

Result returned when a function is invoked with `TriggerAction.Enqueue`.

| Name | Type | Required | Description |
| - | - | - | - |
| `messageReceiptId` | `string` | Yes | Unique receipt ID for the enqueued message. |

***

#### Filter

A declarative filter over `input`, `output`, `error`, `caller` and
`metadata`, with explicit operators only:
`{ 'input.amount': { $gte: 500 } }`. See the filter language reference.

```typescript theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
type Filter = Record<string, unknown>
```

***

#### InitOptions

Configuration options passed to registerWorker.

| Name | Type | Required | Description |
| - | - | - | - |
| `enableMetricsReporting` | `boolean` | No | Enable worker metrics via OpenTelemetry. Defaults to `true`. |
| `headers` | `Record<string, string>` | No | Custom HTTP headers sent during the WebSocket handshake, on the main connection and on streaming channels. `Authorization: Bearer $III_TOKEN` is added unless you set `Authorization` here. |
| `invocationTimeoutMs` | `number` | No | Default timeout for `worker.trigger()` invocations in milliseconds. Defaults to `30000`. |
| `namespace` | `string` | No | Namespace this worker belongs to. Resolution order: `options.namespace` -> `process.env.III_NAMESPACE` -> undefined. When undefined the engine applies its `default` namespace. It scopes more than the registration. The worker and its functions register here, so identically-named entries coexist across namespaces, and everything the worker does afterwards follows it: a `trigger` resolves its target here, and a `registerTrigger` binds here, unless the call names another namespace. One declaration places the whole worker. |
| `otel` | `Omit<OtelConfig, "engineWsUrl" \| "engineWsHeaders">` | No | OpenTelemetry configuration. OTel is initialized automatically by default. Set `{ enabled: false }` or env `OTEL_ENABLED=false/0/no/off` to disable. The `engineWsUrl` is set automatically from the III address, and `engineWsHeaders` from the handshake headers of the main connection. |
| `reconnectionConfig` | `Partial<IIIReconnectionConfig>` | No | WebSocket reconnection behavior. |
| `workerDescription` | `string` | No | One-line, human/LLM-readable summary of what this worker does. Surfaces in `engine::workers::list` / `engine::workers::info`. |
| `workerName` | `string` | No | Display name for this worker. A non-empty `III_WORKER_NAME` overrides it. Defaults to `hostname:pid`. |

***

#### InvocationContext

The invocation the current code runs in, in every handler, remote or
local (`iii.currentInvocation()`).

| Name | Type | Required | Description |
| - | - | - | - |
| `activation` | `{ activation_id?: string; observer_id: string }` | No | Set when this invocation is the activation of an observer's target. |
| `caller` | [`CallerInfo`](#callerinfo) | No | - |
| `function_id` | `string` | Yes | - |
| `invocation_id` | `string` | Yes | - |
| `observe_depth` | `number` | Yes | - |

***

#### JsonValue

Any JSON value: the TypeScript equivalent of the engine's arbitrary-JSON
wire values (Rust `serde_json::Value`). Used where the wire contract is
"any JSON", e.g. per-invocation `metadata`.

```typescript theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
type JsonValue = string | number | boolean | null | JsonValue[] | { [key: string]: JsonValue }
```

***

#### MiddlewareFunctionInput

Input passed to the RBAC middleware function on every function invocation
through the RBAC port. The middleware can inspect, modify, or reject the
call before it reaches the target function.

| Name | Type | Required | Description |
| - | - | - | - |
| `action` | [`TriggerAction`](#triggeraction) | No | Routing action, if any. |
| `context` | `Record<string, unknown>` | Yes | Auth context returned by the auth function for this session. |
| `function_id` | `string` | Yes | ID of the function being invoked. |
| `namespace` | `string` | No | Target namespace the invoke addressed; forward the call here to stay in the caller's namespace. Absent → the engine's default namespace. |
| `payload` | `Record<string, unknown>` | Yes | Payload sent by the caller. |

***

#### Observed

What the target of an auto observer (or of `obs.emit`) receives with
`deliver: 'envelope'` (the default). Fields not in the observer's
`capture` are absent.

| Name | Type | Required | Description |
| - | - | - | - |
| `activation_id` | `string` | Yes | - |
| `caller` | [`Caller`](#caller) | No | - |
| `duration_ms` | `number` | Yes | - |
| `error` | `{ code: string; message: string }` | No | - |
| `function_id` | `string` | Yes | - |
| `input` | `I` | No | - |
| `invocation_id` | `string` | Yes | - |
| `metadata` | `Record<string, unknown>` | No | - |
| `namespace` | `string` | Yes | - |
| `observer_id` | `string` | Yes | - |
| `output` | `O` | No | - |
| `started_at_ms` | `number` | Yes | - |
| `status` | `"error" \| "success"` | Yes | - |

***

#### ObserveDoc

The document an observer's filters read (filters.md §1).

| Name | Type | Required | Description |
| - | - | - | - |
| `caller` | [`CallerInfo`](#callerinfo) | No | - |
| `error` | `unknown` | No | - |
| `input` | `unknown` | No | - |
| `metadata` | `unknown` | No | - |
| `output` | `unknown` | No | - |

***

#### ObserveHooks

The `observe` option of `registerFunction`: how the function's observers
are delivered, and the callbacks that run when one is added or removed.

The callbacks of one function run one at a time, in revision order, with
one exception: a callback still running after 30 s is treated as failed
(`OWNER_TIMEOUT`) and the next one starts, so a hung callback cannot stall
its function forever. It may then overlap with the callbacks after it, and
if a timed-out `onObserverAdded` completes later, `onObserverRemoved` runs
for that observer.

| Name | Type | Required | Description |
| - | - | - | - |
| `allow` | `boolean` | No | Default `true`; `false` refuses every observer (`NOT_OBSERVABLE`). |
| `args_format` | [`RegisterFunctionFormat`](#registerfunctionformat) | No | Owner only: JSON Schema of the observers' `args` (the engine answers `INVALID_ARGS`). |
| `delivery` | `"auto" \| "owner"` | No | `auto` (default): every invocation is offered to every observer. `owner`: the handler hands each event to the observers it belongs to, with `obs.emit` / `obs.call`. |
| `legacy_trigger_type` | `string` | No | Accept old `registerTrigger({ type })` calls for this trigger type. |
| `onObserverAdded` | (obs: [`Observer`](#observer)) => void \| Promise\<void> | No | Runs once per added observer, before the SDK acks it. Throw to reject it (an ObserveRejection sets the code, anything else is `OBSERVE_REJECTED`); after 30 s it is rejected with `OWNER_TIMEOUT`. |
| `onObserverRemoved` | (obs: [`Observer`](#observer)) => void \| Promise\<void> | No | Runs once per removed observer. Cannot fail: errors are logged. |

***

#### Observer

An observer as the function's owner sees it (`onObserverAdded`,
`FunctionRef.observers()`): its args, filters, target, capture and `on`.
Never its metadata, policy or the observing worker.

| Name | Type | Required | Description |
| - | - | - | - |
| `args` | `Record<string, unknown>` | Yes | The observer's args, validated against `args_format` by the engine. |
| `capture` | [`Capture`](#capture)\[] | Yes | - |
| `filters` | [`Filter`](#filter) | Yes | The observer's filters, normalized; the SDK applies them in `emit` / `call`. |
| `function_id` | `string` | Yes | The observed function (the one this worker hosts). |
| `id` | `string` | Yes | - |
| `legacy` | `{ config: unknown; trigger_type: string }` | No | Set when the engine's legacy shim created the observer from an old `registerTrigger`. |
| `on` | `"error" \| "success" \| "complete"` | Yes | Auto only. |
| `target` | `string` | Yes | The target function id. |
| `call` | `(payload: unknown, opts?: { metadata?: undefined; timeoutMs?: number }) => Promise<R>` | Yes | Owner delivery, request/response: invokes the target with `payload` and resolves with its result. Rejects with `FILTERS_NOT_MATCHED` (nothing is sent) when the filters reject the payload, and with `OBSERVER_NOT_ACTIVE` when the observer is no longer active. |
| `emit` | `(event: unknown) => boolean` | Yes | Owner delivery, fire-and-forget: hands `event` to this observer. Returns `false` and sends nothing when its filters reject the event or the observer is no longer active (removed or rejected meanwhile). Throws `NOT_OWNER_DELIVERED` on an auto function. |
| `matches` | (doc: [`ObserveDoc`](#observedoc)) => boolean | Yes | Evaluates the observer's filters on a document. |
| `reject` | `(code: string, message: string) => void` | Yes | Late rejection of an active observer (e.g. after a config reload). It stops receiving events at once, and stays rejected across reconnects until the engine adds it again. |

***

#### ObserveReason

A state reason or an error: a machine-readable code and a message.

| Name | Type | Required | Description |
| - | - | - | - |
| `code` | `string` | Yes | - |
| `message` | `string` | Yes | - |

***

#### ObserverHandle

What `iii.observe` returns, synchronously.

| Name | Type | Required | Description |
| - | - | - | - |
| `id` | `string` | Yes | - |
| `reason` | [`ObserveReason`](#observereason) | No | Why the observer is in its state (`error`, `suspended`, `disposed`). |
| `state` | [`ObserverState`](#observerstate) | Yes | - |
| `dispose` | `() => Promise<void>` | Yes | Removes the observer (`unobserve`). It is not replayed on reconnect. |
| `onStateChange` | (listener: (state: [`ObserverState`](#observerstate), reason?: [`ObserveReason`](#observereason)) => void) => () => void | Yes | Calls `listener` on every state change, in order; returns the unsubscribe function. Listeners are called asynchronously (never on the connection's read path), so they may call the client. |
| `ready` | `() => Promise<void>` | Yes | Resolves when the observer is `active`; rejects with an ObserveRejection carrying the code when it turns `error` or `disposed` first. |

***

#### ObserverOptions

The observer itself: its id, policy and metadata.

| Name | Type | Required | Description |
| - | - | - | - |
| `expires_in_ms` | `number` | No | The observer is disposed this many milliseconds after it is created (`EXPIRED`). Default: never. |
| `id` | `string` | No | Default: a random UUID, stable across replays. |
| `max_fires` | `number` | No | The observer is disposed after this many activations (`MAX_FIRES`). Default: unlimited. |
| `max_in_flight` | `number` | No | Activations running at once; further ones queue, then drop as `OVERFLOW`. Default: the engine's `observers.default_max_in_flight` (64). |
| `metadata` | `Record<string, unknown>` | No | Delivered as the metadata sidecar of every activation. |

***

#### ObserverState

An observer's lifecycle: `pending` (no owner yet, waiting for the owner's
ack, or no target yet) → `active` or `error`; `suspended` while its worker
or target is away; `disposed` at the end.

```typescript theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
type ObserverState = "pending" | "active" | "suspended" | "error" | "disposed"
```

***

#### ObserveSource

The left side of `iii.observe`: what is observed.

| Name | Type | Required | Description |
| - | - | - | - |
| `args` | `Record<string, unknown>` | No | Owner-delivered functions only: for the owner; validated against its `args_format`. |
| `capture` | [`Capture`](#capture)\[] | No | Auto and `obs.emit`; default `['input', 'output', 'caller']`. |
| `deliver` | `"input" \| "output" \| "envelope"` | No | Auto and `obs.emit`; default `'envelope'`. |
| `filters` | [`Filter`](#filter) | No | Which events reach the target; `{}` (or absent) = every event. |
| `function_id` | `string` | Yes | The observed function. |
| `namespace` | `string` | No | Defaults to this worker's namespace (`engine::*` resolves to `default`). |
| `on` | `"error" \| "success" \| "complete"` | No | Auto only; default `'success'`. |

***

#### StreamRequest

Incoming streaming request received by a function registered with a stream trigger.

```typescript theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
type StreamRequest = Omit<InternalHttpRequest<TBody>, "response">
```

***

#### StreamResponse

Response object passed to streaming function handlers. Use `status()` and
`headers()` to set response metadata, write to `stream` for streaming
responses, and call `close()` when done.

| Name | Type | Required | Description |
| - | - | - | - |
| `close` | `() => void` | Yes | Close the response. |
| `headers` | `(headers: Record<string, string>) => void` | Yes | Set response headers. |
| `status` | `(statusCode: number) => void` | Yes | Set the HTTP status code. |
| `stream` | `NodeJS.WritableStream` | Yes | Writable stream for the response body. |

***

#### Target

The right side of `iii.observe`: a registered function.

```typescript theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
type Target = string | { function_id: string; namespace?: string }
```

***

#### TelemetryOptions

Worker metadata reported to the engine (language, framework, project).

| Name | Type | Required | Description |
| - | - | - | - |
| `framework` | `string` | No | Framework name, if applicable. |
| `language` | `string` | No | Programming language of the worker. |
| `project_name` | `string` | No | Name of the project this worker belongs to. |

***

#### TriggerAction

Factory object that constructs routing actions for IIIClient.trigger.

| Name | Type | Required | Description |
| - | - | - | - |
| `Enqueue` | `(opts: { queue: string }) => { queue: string; type: "enqueue" }` | Yes | Routes the invocation through a named queue. The engine enqueues the job, acknowledges the caller with `{ messageReceiptId }`, and processes it asynchronously. Requires the `queue` worker in `worker-compose.yaml`. Without it the trigger rejects with `enqueue_error` (no queue provider). |
| `Void` | `() => { type: "void" }` | Yes | Fire-and-forget routing. The engine forwards the invocation without waiting for a response or queuing the job. |

### iii-sdk/channel

[`Channel`](#channel) · [`ChannelReader`](#channelreader) · [`ChannelWriter`](#channelwriter) · [`StreamChannelRef`](#streamchannelref)

#### Channel

A streaming channel pair for worker-to-worker data transfer. Created via
the `createChannel` helper from `iii-sdk/helpers`.

| Name | Type | Required | Description |
| - | - | - | - |
| `reader` | [`ChannelReader`](#channelreader) | Yes | Reader end of the channel. |
| `readerRef` | [`StreamChannelRef`](#streamchannelref) | Yes | Serializable reference to the reader (can be sent to other workers). |
| `writer` | [`ChannelWriter`](#channelwriter) | Yes | Writer end of the channel. |
| `writerRef` | [`StreamChannelRef`](#streamchannelref) | Yes | Serializable reference to the writer (can be sent to other workers). |

***

#### ChannelReader

Read end of a streaming channel. Provides both a Node.js `Readable` stream
for binary data and an `onMessage` callback for structured text messages.

| Name | Type | Required | Description |
| - | - | - | - |
| `stream` | `Readable` | Yes | Node.js Readable stream for binary data. |

***

#### ChannelWriter

Write end of a streaming channel. Provides both a Node.js `Writable` stream
and a `sendMessage` method for sending structured text messages.

| Name | Type | Required | Description |
| - | - | - | - |
| `stream` | `Writable` | Yes | Node.js Writable stream for binary data. |

***

#### StreamChannelRef

Serializable reference to one end of a streaming channel. Can be included
in invocation payloads to pass channel endpoints between workers.

| Name | Type | Required | Description |
| - | - | - | - |
| `access_key` | `string` | Yes | Access key for authentication. |
| `channel_id` | `string` | Yes | Unique channel identifier. |
| `direction` | `"read" \| "write"` | Yes | Whether this ref is for reading or writing. |

### iii-sdk/engine

[`EngineFunctions`](#enginefunctions) · [`EngineTriggers`](#enginetriggers) · [`RemoteFunctionHandler`](#remotefunctionhandler)

#### EngineFunctions

Engine function paths for internal operations.

Naming note: `LIST_TRIGGERS` / `INFO_TRIGGERS` cover trigger TYPES
(templates). `LIST_REGISTERED_TRIGGERS` / `INFO_REGISTERED_TRIGGERS`
cover trigger INSTANCES (subscriber rows). The old
`engine::trigger-types::list` builtin has been removed and is now
served by `engine::triggers::list`.

| Name | Type | Required | Description |
| - | - | - | - |
| `INFO_FUNCTIONS` | `"engine::functions::info"` | Yes | - |
| `INFO_REGISTERED_TRIGGERS` | `"engine::registered-triggers::info"` | Yes | - |
| `INFO_TRIGGERS` | `"engine::triggers::info"` | Yes | - |
| `INFO_WORKERS` | `"engine::workers::info"` | Yes | - |
| `LIST_FUNCTIONS` | `"engine::functions::list"` | Yes | - |
| `LIST_REGISTERED_TRIGGERS` | `"engine::registered-triggers::list"` | Yes | - |
| `LIST_TRIGGERS` | `"engine::triggers::list"` | Yes | - |
| `LIST_WORKERS` | `"engine::workers::list"` | Yes | - |
| `REGISTER_WORKER` | `"engine::workers::register"` | Yes | - |

***

#### EngineTriggers

Engine trigger types

| Name | Type | Required | Description |
| - | - | - | - |
| `FUNCTIONS_AVAILABLE` | `"engine::functions-available"` | Yes | - |
| `LOG` | `"log"` | Yes | - |

***

#### RemoteFunctionHandler

Async function handler for a registered function. Receives the invocation
payload and an optional per-invocation `metadata` value, and returns the
result.

`metadata` is arbitrary JSON travelling on a separate channel from the
payload. It is `undefined` when the caller did not attach any. Existing
single-argument handlers keep working; they ignore the extra argument.

```typescript theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
type RemoteFunctionHandler = (data: TInput, metadata?: JsonValue) => Promise<TOutput>
```

### iii-sdk/errors

[`InvocationError`](#invocationerror) · [`InvocationErrorInit`](#invocationerrorinit) · [`ObserveRejection`](#observerejection) · [`RegistrationRejectedError`](#registrationrejectederror) · [`RegistrationRejectedInit`](#registrationrejectedinit)

#### InvocationError

| Name | Type | Required | Description |
| - | - | - | - |
| `code` | `string` | Yes | - |
| `function_id` | `string` | No | - |
| `stacktrace` | `string` | No | - |

***

#### InvocationErrorInit

Typed error surfaced when an invocation dispatched over the SDK fails, RBAC
rejection (FORBIDDEN), handler-level failure, or a timeout waiting for the
engine to respond. Wraps the wire `ErrorBody` shape plus the `function_id`
that was targeted, so callers get a single error type across all failure
modes and can disambiguate via `err.code`.

Before this existed, rejection values were plain `ErrorBody`-shaped objects,
which printed as `[object Object]` when stringified, leaving developers to
grep through SDK source to figure out what tripped. The class name, `code`
prefix in the message, and `function_id` field together make a rejection
self-describing.

| Name | Type | Required | Description |
| - | - | - | - |
| `code` | `string` | Yes | - |
| `function_id` | `string` | No | - |
| `message` | `string` | Yes | - |
| `stacktrace` | `string` | No | - |

***

#### ObserveRejection

Thrown by an `onObserverAdded` hook to reject an observer with a code of
its own (`HTTP_ROUTE_CONFLICT`, `INVALID_CRON_EXPRESSION`, ...); any other
error rejects it with `OBSERVE_REJECTED`. Also the error `ObserverHandle.ready()`
rejects with when the observer turns `error` or `disposed`.

| Name | Type | Required | Description |
| - | - | - | - |
| `code` | `string` | Yes | - |

***

#### RegistrationRejectedError

Fatal error surfaced when the engine rejects this worker's identity because
another live worker owns the same `(namespace, worker_name)`, or when an
unknown rejection code is received. The SDK stops and does not reconnect.
A `FUNCTION_NAMESPACE_CONFLICT` is non-fatal and is logged instead of being
surfaced through this class. The wire fields identify the contested
registration and its current owner.

| Name | Type | Required | Description |
| - | - | - | - |
| `code` | `string` | Yes | - |
| `function_id` | `string` | No | - |
| `namespace` | `string` | Yes | - |
| `owner_worker_id` | `string` | Yes | - |
| `worker_name` | `string` | No | - |

***

#### RegistrationRejectedInit

Fields used to construct a RegistrationRejectedError.

| Name | Type | Required | Description |
| - | - | - | - |
| `code` | `string` | Yes | - |
| `function_id` | `string` | No | - |
| `namespace` | `string` | Yes | - |
| `owner_worker_id` | `string` | Yes | - |
| `worker_name` | `string` | No | - |

### iii-sdk/helpers

[`ChannelDirection`](#channeldirection) · [`ChannelItem`](#channelitem)

#### ChannelDirection

Direction of a streaming channel endpoint. Mirrors the Rust SDK's
`ChannelDirection` enum and matches the literal values used by
StreamChannelRef.direction.

```typescript theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
type ChannelDirection = typeof ChannelDirection[keyof typeof ChannelDirection]
```

***

#### ChannelItem

Discriminated runtime tag for an item observed on a streaming channel.
Mirrors the Rust SDK's `ChannelItem` enum (`Text` / `Binary`). Carrier for
factory + type-guard helpers so callers can construct and discriminate
channel items without depending on Rust-specific shape.

```typescript theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
type ChannelItem = { type: "text"; value: string } | { type: "binary"; value: Uint8Array }
```

### iii-sdk/protocol

[`ActivationWire`](#activationwire) · [`CallerWire`](#callerwire) · [`CaptureWire`](#capturewire) · [`DroppedReportStatsWire`](#droppedreportstatswire) · [`ErrorBody`](#errorbody) · [`FunctionRegisteredMessage`](#functionregisteredmessage) · [`InvocationsObservedMessage`](#invocationsobservedmessage) · [`LocalFunctionStatsWire`](#localfunctionstatswire) · [`LocalInvocationStatsMessage`](#localinvocationstatsmessage) · [`MessageType`](#messagetype) · [`ObserveDescriptorWire`](#observedescriptorwire) · [`ObservedItemWire`](#observeditemwire) · [`ObserveMessage`](#observemessage) · [`ObserverAckMessage`](#observerackmessage) · [`ObserverAddedMessage`](#observeraddedmessage) · [`ObserveResultMessage`](#observeresultmessage) · [`ObserverInfoWire`](#observerinfowire) · [`ObserverRemovedMessage`](#observerremovedmessage) · [`ObserverStateChangedMessage`](#observerstatechangedmessage) · [`ObserveSourceWire`](#observesourcewire) · [`RegisterFunctionFormat`](#registerfunctionformat) · [`RegisterFunctionInput`](#registerfunctioninput) · [`RegisterFunctionMessage`](#registerfunctionmessage) · [`RegisterFunctionOptions`](#registerfunctionoptions) · [`TriggerRequest`](#triggerrequest) · [`UnobserveMessage`](#unobservemessage)

#### ActivationWire

`InvokeFunction.activation`: present on every activation of an observer's target.

| Name | Type | Required | Description |
| - | - | - | - |
| `activation_id` | `string` | No | - |
| `observer_id` | `string` | Yes | - |

***

#### CallerWire

Who started an invocation. Engine → worker: `worker_id` / `worker_name`
are stamped by the engine from the calling connection. Worker → engine:
the SDK sends `function_id`, `invocation_id` and `parent` (the caller of the
handler the call was made from, one level only).

| Name | Type | Required | Description |
| - | - | - | - |
| `function_id` | `string` | No | - |
| `invocation_id` | `string` | No | - |
| `parent` | Omit\<[`CallerWire`](#callerwire), "parent"> | No | - |
| `worker_id` | `string` | No | - |
| `worker_name` | `string` | No | - |

***

#### CaptureWire

What an observer ships to its target (`capture`).

```typescript theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
type CaptureWire = OpenEnum<"input" | "output" | "error" | "caller" | "metadata">
```

***

#### DroppedReportStatsWire

| Name | Type | Required | Description |
| - | - | - | - |
| `count` | `number` | Yes | - |
| `function_id` | `string` | Yes | - |
| `reason` | `string` | Yes | `BUFFER_FULL` \| `TOO_LARGE` (SDK-side drops). |

***

#### ErrorBody

| Name | Type | Required | Description |
| - | - | - | - |
| `code` | `string` | Yes | - |
| `message` | `string` | Yes | - |
| `stacktrace` | `string` | No | - |

***

#### FunctionRegisteredMessage

| Name | Type | Required | Description |
| - | - | - | - |
| `id` | `string` | Yes | - |
| `local_dispatch` | `boolean` | Yes | - |
| `message_type` | [`MessageType`](#messagetype).FunctionRegistered | Yes | - |
| `namespace` | `string` | Yes | - |
| `observers` | [`ObserverInfoWire`](#observerinfowire)\[] | Yes | - |
| `revision` | `number` | Yes | - |

***

#### InvocationsObservedMessage

| Name | Type | Required | Description |
| - | - | - | - |
| `items` | [`ObservedItemWire`](#observeditemwire)\[] | Yes | - |
| `message_type` | [`MessageType`](#messagetype).InvocationsObserved | Yes | - |

***

#### LocalFunctionStatsWire

| Name | Type | Required | Description |
| - | - | - | - |
| `count` | `number` | Yes | - |
| `duration_ms_sum` | `number` | No | - |
| `errors` | `number` | No | - |
| `function_id` | `string` | Yes | - |

***

#### LocalInvocationStatsMessage

| Name | Type | Required | Description |
| - | - | - | - |
| `dropped_reports` | [`DroppedReportStatsWire`](#droppedreportstatswire)\[] | Yes | - |
| `functions` | [`LocalFunctionStatsWire`](#localfunctionstatswire)\[] | Yes | - |
| `message_type` | [`MessageType`](#messagetype).LocalInvocationStats | Yes | - |
| `window_ms` | `number` | Yes | - |

***

#### MessageType

| Name | Type | Required | Description |
| - | - | - | - |
| `FunctionRegistered` | `"functionregistered"` | Yes | Engine → owner: the `registerfunction` ack, with the function's full observer set. |
| `InvocationResult` | `"invocationresult"` | Yes | - |
| `InvocationsObserved` | `"invocationsobserved"` | Yes | Owner → engine: matched local invocations and `obs.emit` events, batched. |
| `InvokeFunction` | `"invokefunction"` | Yes | - |
| `LocalInvocationStats` | `"localinvocationstats"` | Yes | Owner → engine: periodic counts of local invocations and report drops. |
| `Observe` | `"observe"` | Yes | Observing worker → engine: create (or idempotently replay) an observer. |
| `ObserverAck` | `"observerack"` | Yes | Owner → engine: accept (or reject) an added observer. |
| `ObserverAdded` | `"observeradded"` | Yes | Engine → owner: one observer attached to a function this connection hosts. |
| `ObserveResult` | `"observeresult"` | Yes | Engine → observing worker: the reply to `observe` (also on replay). |
| `ObserverRemoved` | `"observerremoved"` | Yes | Engine → owner: one observer detached. |
| `ObserverStateChanged` | `"observerstatechanged"` | Yes | Engine → observing worker: an observer's lifecycle transition. |
| `Reattach` | `"reattach"` | Yes | - |
| `RegisterFunction` | `"registerfunction"` | Yes | - |
| `RegisterTrigger` | `"registertrigger"` | Yes | - |
| `RegisterTriggerType` | `"registertriggertype"` | Yes | - |
| `RegistrationRejected` | `"registrationrejected"` | Yes | - |
| `TriggerRegistrationResult` | `"triggerregistrationresult"` | Yes | - |
| `Unobserve` | `"unobserve"` | Yes | Observing worker → engine: dispose an observer this connection owns. |
| `UnregisterFunction` | `"unregisterfunction"` | Yes | - |
| `UnregisterTrigger` | `"unregistertrigger"` | Yes | - |
| `UnregisterTriggerType` | `"unregistertriggertype"` | Yes | - |
| `WorkerRegistered` | `"workerregistered"` | Yes | - |

***

#### ObserveDescriptorWire

`RegisterFunction.observe`: the part of the observe hooks that travels. Callbacks never do.

| Name | Type | Required | Description |
| - | - | - | - |
| `allow` | `boolean` | No | Default `true`; `false` makes every `observe` on it fail with `NOT_OBSERVABLE`. |
| `args_format` | [`RegisterFunctionFormat`](#registerfunctionformat) | No | Owner only: validates the observers' `args` in the engine (`INVALID_ARGS`). |
| `delivery` | `OpenEnum<"auto" \| "owner">` | No | `auto` (default) or `owner`. |
| `legacy_trigger_type` | `string` | No | Phase 5 shim: accept old `registertrigger { trigger_type }` for this type. |

***

#### ObservedItemWire

One matched local invocation (auto) or one `obs.emit` event (owner).

| Name | Type | Required | Description |
| - | - | - | - |
| `baggage` | `string` | No | - |
| `caller` | [`CallerWire`](#callerwire) | No | - |
| `duration_ms` | `number` | Yes | - |
| `error` | `unknown` | No | - |
| `function_id` | `string` | Yes | - |
| `input` | `unknown` | No | `null` is a value here: absent means not captured or does not exist. |
| `invocation_id` | `string` | Yes | - |
| `matched` | `string[]` | Yes | Observer ids whose filters matched (the same event coalesced for several). |
| `metadata` | `unknown` | No | - |
| `namespace` | `string` | No | - |
| `observe_depth` | `number` | No | - |
| `output` | `unknown` | No | - |
| `started_at_ms` | `number` | Yes | - |
| `status` | `OpenEnum<"success" \| "error">` | Yes | - |
| `traceparent` | `string` | No | - |

***

#### ObserveMessage

| Name | Type | Required | Description |
| - | - | - | - |
| `expires_in_ms` | `number` | No | - |
| `id` | `string` | Yes | Client-generated UUID, stable across replays. |
| `max_fires` | `number` | No | - |
| `max_in_flight` | `number` | No | - |
| `message_type` | [`MessageType`](#messagetype).Observe | Yes | - |
| `metadata` | `Record<string, unknown>` | No | - |
| `source` | [`ObserveSourceWire`](#observesourcewire) | Yes | - |
| `target` | `{ function_id: string; namespace?: string }` | Yes | - |

***

#### ObserverAckMessage

| Name | Type | Required | Description |
| - | - | - | - |
| `error` | [`ErrorBody`](#errorbody) | No | Rejects the observer (also a late rejection of an active one). |
| `function_id` | `string` | Yes | - |
| `id` | `string` | Yes | - |
| `message_type` | [`MessageType`](#messagetype).ObserverAck | Yes | - |
| `namespace` | `string` | No | - |
| `revision` | `number` | Yes | - |

***

#### ObserverAddedMessage

| Name | Type | Required | Description |
| - | - | - | - |
| `function_id` | `string` | Yes | - |
| `message_type` | [`MessageType`](#messagetype).ObserverAdded | Yes | - |
| `namespace` | `string` | Yes | - |
| `observer` | [`ObserverInfoWire`](#observerinfowire) | Yes | - |
| `revision` | `number` | Yes | - |

***

#### ObserveResultMessage

| Name | Type | Required | Description |
| - | - | - | - |
| `error` | [`ErrorBody`](#errorbody) | No | - |
| `id` | `string` | Yes | - |
| `message_type` | [`MessageType`](#messagetype).ObserveResult | Yes | - |
| `state` | `ObserverStateWire` | Yes | - |
| `warnings` | `string[]` | No | - |

***

#### ObserverInfoWire

An observer as its function's owner sees it: never the observer's metadata,
policy or connection. `target` is the target function id.

| Name | Type | Required | Description |
| - | - | - | - |
| `args` | `Record<string, unknown>` | Yes | - |
| `capture` | [`CaptureWire`](#capturewire)\[] | Yes | - |
| `filters` | `Record<string, unknown>` | Yes | The observer's filters, normalized by the engine. `{}` matches every event. |
| `id` | `string` | Yes | - |
| `legacy` | `{ config: unknown; trigger_type: string }` | No | Phase 5 shim only: the old trigger config the owner reads as args. |
| `on` | `ObserveOnWire` | Yes | - |
| `target` | `string` | Yes | - |

***

#### ObserverRemovedMessage

| Name | Type | Required | Description |
| - | - | - | - |
| `function_id` | `string` | Yes | - |
| `id` | `string` | Yes | - |
| `message_type` | [`MessageType`](#messagetype).ObserverRemoved | Yes | - |
| `namespace` | `string` | Yes | - |
| `revision` | `number` | Yes | - |

***

#### ObserverStateChangedMessage

| Name | Type | Required | Description |
| - | - | - | - |
| `fires` | `number` | Yes | - |
| `id` | `string` | Yes | - |
| `message_type` | [`MessageType`](#messagetype).ObserverStateChanged | Yes | - |
| `reason` | [`ErrorBody`](#errorbody) | No | - |
| `state` | `ObserverStateWire` | Yes | - |

***

#### ObserveSourceWire

`observe.source`: the left side of `iii.observe`.

| Name | Type | Required | Description |
| - | - | - | - |
| `args` | `Record<string, unknown>` | No | - |
| `capture` | [`CaptureWire`](#capturewire)\[] | No | - |
| `deliver` | `ObserveDeliverWire` | No | - |
| `filters` | `Record<string, unknown>` | No | - |
| `function_id` | `string` | Yes | - |
| `namespace` | `string` | No | - |
| `on` | `ObserveOnWire` | No | - |

***

#### RegisterFunctionFormat

| Name | Type | Required | Description |
| - | - | - | - |
| `description` | `string` | No | The description of the parameter. |
| `items` | `unknown` | No | The items of the parameter (for arrays). |
| `name` | `string` | No | The name of the parameter. |
| `properties` | `Record<string, unknown>` | No | The body of the parameter (for objects). |
| `required` | `string[]` | No | Whether the parameter is required. |
| `type` | `"string" \| "number" \| "boolean" \| "object" \| "array" \| "null" \| "map" \| "integer"` | No | The type of the parameter. |
| `[key: string]` | `unknown` | No | - |

***

#### RegisterFunctionInput

```typescript theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
type RegisterFunctionInput = Omit<RegisterFunctionMessage, "message_type">
```

| Name | Type | Required | Description |
| - | - | - | - |
| `description` | `string` | No | The description of the function. |
| `id` | `string` | Yes | The path of the function (use :: for namespacing, e.g. external::my\_lambda). |
| `invocation` | `HttpInvocationConfig` | No | HTTP invocation config for external HTTP functions (Lambda, Cloudflare Workers, etc.). |
| `metadata` | `Record<string, unknown>` | No | Arbitrary metadata attached to the function. |
| `observe` | [`ObserveDescriptorWire`](#observedescriptorwire) | No | The observe descriptor: how observers of this function are delivered. Only these four fields travel; the hooks stay in the SDK. |
| `request_format` | [`RegisterFunctionFormat`](#registerfunctionformat) | No | The request format of the function. |
| `response_format` | [`RegisterFunctionFormat`](#registerfunctionformat) | No | The response format of the function. |

***

#### RegisterFunctionMessage

| Name | Type | Required | Description |
| - | - | - | - |
| `description` | `string` | No | The description of the function. |
| `id` | `string` | Yes | The path of the function (use :: for namespacing, e.g. external::my\_lambda). |
| `invocation` | `HttpInvocationConfig` | No | HTTP invocation config for external HTTP functions (Lambda, Cloudflare Workers, etc.). |
| `message_type` | [`MessageType`](#messagetype).RegisterFunction | Yes | - |
| `metadata` | `Record<string, unknown>` | No | Arbitrary metadata attached to the function. |
| `observe` | [`ObserveDescriptorWire`](#observedescriptorwire) | No | The observe descriptor: how observers of this function are delivered. Only these four fields travel; the hooks stay in the SDK. |
| `request_format` | [`RegisterFunctionFormat`](#registerfunctionformat) | No | The request format of the function. |
| `response_format` | [`RegisterFunctionFormat`](#registerfunctionformat) | No | The response format of the function. |

***

#### RegisterFunctionOptions

Options of IIIClient.registerFunction: description, request/response
formats, metadata, and the observe hooks.

```typescript theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
type RegisterFunctionOptions = Omit<RegisterFunctionMessage, "message_type" | "id" | "observe"> & { localDispatch?: boolean; observe?: ObserveHooks }
```

| Name | Type | Required | Description |
| - | - | - | - |
| `description` | `string` | No | The description of the function. |
| `invocation` | `HttpInvocationConfig` | No | HTTP invocation config for external HTTP functions (Lambda, Cloudflare Workers, etc.). |
| `localDispatch` | `boolean` | No | Calls this worker makes to its own function run in-process once the engine confirmed it (default `true`). Set `false` for a handler that must always run through the engine. |
| `metadata` | `Record<string, unknown>` | No | Arbitrary metadata attached to the function. |
| `observe` | [`ObserveHooks`](#observehooks) | No | Makes the function observable on its own terms: owner delivery (`delivery: 'owner'`, `args_format`), and callbacks when an observer is added or removed. Without it the function is still observable (auto delivery, no args). |
| `request_format` | [`RegisterFunctionFormat`](#registerfunctionformat) | No | The request format of the function. |
| `response_format` | [`RegisterFunctionFormat`](#registerfunctionformat) | No | The response format of the function. |

***

#### TriggerRequest

Request object passed to IIIClient.trigger.

| Name | Type | Required | Description |
| - | - | - | - |
| `action` | [`TriggerAction`](#triggeraction) | No | Sets how the trigger is routed. Omit for a synchronous request/response. Specify for a specific routing scheme (e.g. `TriggerAction.Enqueue()`, `TriggerAction.Void()`). |
| `dispatch` | `"auto" \| "remote"` | No | `auto` (default) runs a function this worker hosts in-process when the engine confirmed it for local dispatch; `remote` always goes through the engine. Tests use it, and so do callers that rely on engine-side effects. |
| `function_id` | `string` | Yes | ID of the function to invoke. |
| `metadata` | `unknown` | No | Arbitrary user-specifiable metadata supplied to the triggered handler function on every invocation. |
| `namespace` | `string` | No | Target namespace for routing. Omit to inherit this worker's; say `default` to reach the engine's from a namespaced worker. Serialized into the InvokeFunctionMessage `namespace` field. |
| `payload` | `TInput` | Yes | Input data passed to the function. |
| `timeoutMs` | `number` | No | Override the default invocation timeout, in milliseconds. |

***

#### UnobserveMessage

| Name | Type | Required | Description |
| - | - | - | - |
| `id` | `string` | Yes | - |
| `message_type` | [`MessageType`](#messagetype).Unobserve | Yes | - |

### iii-sdk/runtime

[`FunctionRef`](#functionref) · [`IIIConnectionState`](#iiiconnectionstate)

#### FunctionRef

Handle returned by IIIClient.registerFunction. Contains the function's
`id` and an `unregister()` method.

| Name | Type | Required | Description |
| - | - | - | - |
| `id` | `string` | Yes | The unique function identifier. |
| `isObserved` | `() => boolean` | Yes | Whether any observer is active on this function (one load, for the emit fast path: skip building an event nobody receives). |
| `observers` | () => readonly [`Observer`](#observer)\[] | Yes | The active observers, as this owner sees them. |
| `unregister` | `() => void` | Yes | Removes this function from the engine. |

***

#### IIIConnectionState

Connection state for the III WebSocket

```typescript theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
type IIIConnectionState = "disconnected" | "connecting" | "connected" | "reconnecting" | "failed"
```

### iii-sdk/state

[`IState`](#istate) · [`StateDeleteInput`](#statedeleteinput) · [`StateDeleteResult`](#statedeleteresult) · [`StateEventData`](#stateeventdata) · [`StateEventType`](#stateeventtype) · [`StateGetInput`](#stategetinput) · [`StateListInput`](#statelistinput) · [`StateSetInput`](#statesetinput) · [`StateSetResult`](#statesetresult) · [`StateUpdateInput`](#stateupdateinput) · [`StateUpdateResult`](#stateupdateresult)

#### IState

Interface for state management operations. Available via the `iii-sdk/state`
subpath export.

| Name | Type | Required | Description |
| - | - | - | - |
| `delete` | (input: [`StateDeleteInput`](#statedeleteinput)) => Promise\<[`StateDeleteResult`](#statedeleteresult)> | Yes | Delete a state value. |
| `get` | (input: [`StateGetInput`](#stategetinput)) => Promise\<TData \| null> | Yes | Retrieve a value by scope and key. |
| `list` | (input: [`StateListInput`](#statelistinput)) => Promise\<TData\[]> | Yes | List all values in a scope. |
| `set` | (input: [`StateSetInput`](#statesetinput)) => Promise\<[`StateSetResult`](#statesetresult)\<TData> \| null> | Yes | Set (create or overwrite) a state value. |
| `update` | (input: [`StateUpdateInput`](#stateupdateinput)) => Promise\<[`StateUpdateResult`](#stateupdateresult)\<TData> \| null> | Yes | Apply atomic update operations to a state value. |

***

#### StateDeleteInput

Input for deleting a state value.

| Name | Type | Required | Description |
| - | - | - | - |
| `key` | `string` | Yes | Key within the scope. |
| `scope` | `string` | Yes | State scope (namespace). |

***

#### StateDeleteResult

Result of a state delete operation.

| Name | Type | Required | Description |
| - | - | - | - |
| `old_value` | `any` | No | Previous value (if it existed). |

***

#### StateEventData

Payload for state change events.

| Name | Type | Required | Description |
| - | - | - | - |
| `event_type` | [`StateEventType`](#stateeventtype) | Yes | Type of state change. |
| `key` | `string` | Yes | Key within the scope. |
| `new_value` | `TData` | No | New value (for create/update events). |
| `old_value` | `TData` | No | Previous value (for update/delete events). |
| `scope` | `string` | Yes | State scope (namespace). |
| `type` | `"state"` | Yes | - |

***

#### StateEventType

Types of state change events.

| Name | Type | Required | Description |
| - | - | - | - |
| `Created` | `"state:created"` | Yes | - |
| `Deleted` | `"state:deleted"` | Yes | - |
| `Updated` | `"state:updated"` | Yes | - |

***

#### StateGetInput

Input for retrieving a state value.

| Name | Type | Required | Description |
| - | - | - | - |
| `key` | `string` | Yes | Key within the scope. |
| `scope` | `string` | Yes | State scope (namespace). |

***

#### StateListInput

Input for listing all values in a state scope.

| Name | Type | Required | Description |
| - | - | - | - |
| `scope` | `string` | Yes | State scope (namespace). |

***

#### StateSetInput

Input for setting a state value.

| Name | Type | Required | Description |
| - | - | - | - |
| `key` | `string` | Yes | Key within the scope. |
| `scope` | `string` | Yes | State scope (namespace). |
| `value` | `any` | Yes | Value to store. |

***

#### StateSetResult

Result of a state set operation.

| Name | Type | Required | Description |
| - | - | - | - |
| `new_value` | `TData` | Yes | New value that was stored. |
| `old_value` | `TData` | No | Previous value (if it existed). |

***

#### StateUpdateInput

Input for atomically updating a state value.

| Name | Type | Required | Description |
| - | - | - | - |
| `key` | `string` | Yes | Key within the scope. |
| `ops` | `UpdateOp[]` | Yes | Ordered list of update operations to apply atomically. |
| `scope` | `string` | Yes | State scope (namespace). |

***

#### StateUpdateResult

Result of a state update operation.

| Name | Type | Required | Description |
| - | - | - | - |
| `errors` | `UpdateOpError[]` | No | Per-op errors. Currently emitted only by the `merge` op when input violates the validation bounds. See UpdateOpError and the `UpdateMerge` JSDoc in `./stream` for the error codes. Field is omitted from the JSON wire when empty. |
| `new_value` | `TData` | Yes | New value after the update. |
| `old_value` | `TData` | No | Previous value (if it existed). |

### iii-sdk/stream

[`IStream`](#istream)

#### IStream

Interface for custom stream implementations. Passed to `IIIClient.createStream`
to override the engine's built-in stream storage.

| Name | Type | Required | Description |
| - | - | - | - |
| `delete` | `(input: StreamDeleteInput) => Promise<StreamDeleteResult>` | Yes | Delete a stream item. |
| `get` | `(input: StreamGetInput) => Promise<TData \| null>` | Yes | Retrieve a single item by group and item ID. |
| `list` | `(input: StreamListInput) => Promise<TData[]>` | Yes | List all items in a group. |
| `listGroups` | `(input: StreamListGroupsInput) => Promise<string[]>` | Yes | List all group IDs in a stream. |
| `set` | `(input: StreamSetInput) => Promise<StreamSetResult<TData> \| null>` | Yes | Set (create or overwrite) a stream item. |
| `update` | `(input: StreamUpdateInput) => Promise<StreamUpdateResult<TData> \| null>` | Yes | Apply atomic update operations to a stream item. |


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.