> ## 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.

# Rust SDK

> API reference for the iii SDK for Rust.

## Installation

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

## Initialization

### register\_worker

**Signature**

```rust theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
register_worker(address: &str, options: InitOptions) -> IIIClient
```

#### Parameters

**address** `&str` *required*

**options** `InitOptions` *required*

**`InitOptions` fields**

**metadata** `Option\<iii::WorkerMetadata\>`

Custom worker metadata. Auto-detected if `None`. In managed identity mode, process-wide identity variables override matching fields.

**headers** `Option\<HashMap\<String, String\>\>`

Custom HTTP headers sent during the WebSocket handshake, on the main connection and on channels from `create_channel`. `Authorization: Bearer $III_TOKEN` is added unless you set `Authorization` here.

**otel** `Option\<iii_helpers::observability::OtelConfig\>`

OpenTelemetry configuration.

**namespace** `Option\<String\>`

Namespace this worker belongs to. In managed mode, resolution order is `namespace` > env `III_NAMESPACE` > `None`. In explicit mode, the environment is not used. It scopes more than the registration. The worker and its functions register here, and everything the worker does afterwards follows it: a `IIIClient::trigger` resolves its target here and a `IIIClient::register_trigger` binds here, unless the call names another namespace.

**identity** `WorkerIdentityMode` *required*

Selects whether process-wide managed identity variables can override this connection's metadata. Auxiliary connections should use `WorkerIdentityMode::Explicit`.

## Methods

### register\_trigger

> [!WARNING]
>
> **Deprecated since 0.25.0.** Use iii.observe(Source::function(..).args(..), target) instead; see [https://iii.dev/docs/upgrading/from-0-24-x](https://iii.dev/docs/upgrading/from-0-24-x.md)

Bind a trigger configuration to a registered function.

It keeps working in 0.25 and logs one warning per process. The http,
cron, queue, state, stream, pubsub and database workers still publish
trigger types, so keep using it for them until they ship source
functions; observe any other function with `observe`.

**Signature**

```rust theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
register_trigger(input: RegisterTriggerInput) -> Result<Trigger, Error>
```

> [tab] Parameters
>
> **input** `RegisterTriggerInput` *required*
>
> Trigger registration input with trigger\_type, function\_id, and config.
>
> **`RegisterTriggerInput` fields**
>
> **trigger\_type** `String` *required*
>
> Identifier of the registered trigger type this trigger uses (e.g. `storage::object-created`, `http`).
>
> **function\_id** `String` *required*
>
> ID of the function this trigger invokes when it fires.
>
> **config** `Value` *required*
>
> Trigger-type-specific configuration, matching the shape the trigger type expects.
>
> **metadata** `Option\<Value\>`
>
> Arbitrary user-specifiable metadata supplied to the triggered handler function on every invocation.
>
> **namespace** `Option\<String\>`
>
> Namespace the trigger's target function resolves in. `None` inherits this worker's namespace; name another namespace, including `default`, to bind the trigger elsewhere.
>
> **trigger\_namespace** `Option\<String\>`
>
> Namespace to find the trigger type's provider in. `None` asks the engine to resolve it: this worker's namespace first, the engine's own second. Naming one is strict.

> [tab] Example
>
> ```rust theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
> let trigger = worker.register_trigger(RegisterTriggerInput::new(
>     "http",
>     "greet",
>     json!({ "api_path": "/greet", "http_method": "GET" }),
> ))?;
> // Later...
> trigger.unregister();
> ```

***

### register\_function

Register a function with the engine.

Argument order matches the Node and Python SDKs:
`(id, registration)`.

**Signature**

```rust theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
register_function(id: impl Into<String>, registration: RegisterFunction) -> FunctionRef
```

> [tab] Parameters
>
> **id** `impl Into\<String\>` *required*
>
> Unique identifier for the function.
>
> **registration** `RegisterFunction` *required*
>
> Built via \[`RegisterFunction::new`], \[`RegisterFunction::new_async`], or \[`RegisterFunction::http`]. Chain `.description(...)`, `.metadata(...)`, `.request_format(...)`, `.response_format(...)` as needed.
>
> **`RegisterFunction` fields**
>
> **description** `fn(desc: impl Into\<String\>) -\> Self` *required*
>
> Set the function description.
>
> **http** `fn(config: HttpInvocationConfig) -\> Self` *required*
>
> Create a registration for an **HTTP-invoked** function (Lambda, Cloudflare Workers, etc.). No local handler runs.
>
> **local\_dispatch** `fn(enabled: bool) -\> Self` *required*
>
> Whether calls to this function from this same worker may run in-process once the engine allows it. Default `true`.
>
> **metadata** `fn(meta: Value) -\> Self` *required*
>
> Set function metadata.
>
> **new** `fn(f: F) -\> Self` *required*
>
> Create a registration for a **sync** typed function.
>
> **new\_async** `fn(f: F) -\> Self` *required*
>
> Create a registration for an **async** typed function.
>
> **observe** `fn(observe: Observe) -\> Self` *required*
>
> How observers of this function are delivered, and the hooks that run when one is added or removed (`Observe::owner` / `Observe::auto`). Every function is observable without it, as `auto` without hooks.
>
> **request\_format** `fn(schema: Value) -\> Self` *required*
>
> Set the request format schema. Overrides any auto-extracted schema.
>
> **response\_format** `fn(schema: Value) -\> Self` *required*
>
> Set the response format schema. Overrides any auto-extracted schema.

> [tab] Example
>
> ```rust theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
> use iii_sdk::{register_worker, InitOptions, Error, RegisterFunction};
> use serde::{Deserialize, Serialize};
> use schemars::JsonSchema;
>
> #[derive(Deserialize, JsonSchema)]
> struct Input { name: String }
> #[derive(Serialize, JsonSchema)]
> struct Output { message: String }
>
> async fn greet(input: Input) -> Result<Output, Error> {
>     Ok(Output { message: format!("Hello, {}!", input.name) })
> }
>
> let worker = register_worker("ws://localhost:49134", InitOptions::default());
> worker.register_function(
>     "greetings::greet",
>     RegisterFunction::new_async(greet).description("Greets a user"),
> );
> ```

***

### trigger

Invoke a function.

The routing behavior depends on the `action` field of the request:

* No action: synchronous, waits for the function to return.
* `TriggerAction::Enqueue`: async via named queue.
* `TriggerAction::Void`: fire-and-forget.

A function this worker registered itself runs in-process once the
engine allowed it ("local dispatch", see `Dispatch`): same result,
error shape and timeout, and nothing on the wire unless an observer's
filters match the call. A sync handler then runs inline on the
caller's task, where the timeout cannot interrupt it: a sync handler
that can block should be async, or registered with
`RegisterFunction::local_dispatch(false)`.
`TriggerRequest::dispatch` with `Dispatch::Remote`
forces the engine path. Calls made from inside a handler carry that
handler as their `caller`.

**Signature**

```rust theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
async trigger(request: impl Into<TriggerRequestWithMetadata>) -> Result<Value, Error>
```

> [tab] Parameters
>
> **request** `impl Into\<TriggerRequestWithMetadata\>` *required*
>
> **`TriggerRequestWithMetadata` fields**
>
> **dispatch** `fn(dispatch: Dispatch) -\> Self` *required*
>
> Choose the path this call takes; see `Dispatch`.
>
> **metadata** `fn(metadata: Value) -\> Self` *required*
>
> Attach per-invocation metadata.
>
> **namespace** `fn(namespace: impl Into\<String\>) -\> Self` *required*
>
> Target a specific namespace for this invocation.
>
> **`TriggerRequest` fields**
>
> **function\_id** `String` *required*
>
> ID of the function to invoke.
>
> **payload** `Value` *required*
>
> Input data passed to the function.
>
> **action** `Option\<TriggerAction\>`
>
> Sets how the trigger is routed. `None` for a synchronous request/response. Set a routing scheme otherwise (e.g. `TriggerAction::Enqueue { .. }`, `TriggerAction::Void`).
>
> **timeout\_ms** `Option\<u64\>`
>
> Override the default invocation timeout, in milliseconds.
>
> **dispatch** `fn(dispatch: Dispatch) -\> TriggerRequestWithMetadata` *required*
>
> Choose the path this call takes: `Dispatch::Auto` (the default) runs a function this worker hosts in-process when the engine allows it; `Dispatch::Remote` always goes through the engine.
>
> **metadata** `fn(metadata: Value) -\> TriggerRequestWithMetadata` *required*
>
> Attach per-invocation metadata without adding a required field to `TriggerRequest` struct literals.
>
> **namespace** `fn(namespace: impl Into\<String\>) -\> TriggerRequestWithMetadata` *required*
>
> Target a specific namespace for this invocation without adding a required field to `TriggerRequest` struct literals. Serializes into `Message::InvokeFunction`'s `namespace`.

> [tab] Example
>
> ```rust theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
> // Synchronous
> let result = worker.trigger(TriggerRequest {
>     function_id: "greet".to_string(),
>     payload: json!({"name": "World"}),
>     action: None,
>     timeout_ms: None,
> }).await?;
>
> // Fire-and-forget
> worker.trigger(TriggerRequest {
>     function_id: "notify".to_string(),
>     payload: json!({}),
>     action: Some(TriggerAction::Void),
>     timeout_ms: None,
> }).await?;
>
> // Enqueue (the queue must be declared in the queue worker's
> // queue_configs)
> let receipt = worker.trigger(TriggerRequest {
>     function_id: "iii::durable::publish".to_string(),
>     payload: json!({"topic": "test"}),
>     action: Some(TriggerAction::Enqueue { queue: "test".to_string() }),
>     timeout_ms: None,
> }).await?;
>
> // Metadata
> worker.trigger(
>     TriggerRequest {
>         function_id: "audit::write".to_string(),
>         payload: json!({"event": "checkout"}),
>         action: Some(TriggerAction::Void),
>         timeout_ms: None,
>     }
>     .metadata(json!({"tenant": "acme"})),
> ).await?;
> ```

***

### register\_trigger\_type

> [!WARNING]
>
> **Deprecated since 0.25.0.** Register a function with RegisterFunction::observe(Observe::owner()..) instead; see [https://iii.dev/docs/upgrading/from-0-24-x](https://iii.dev/docs/upgrading/from-0-24-x.md)

Register a custom trigger type with the engine.

Returns a `TriggerTypeRef` handle that can register triggers and
functions with compile-time validated types.

It keeps working in 0.25 and logs one warning per process. A new
provider registers a function with an observe descriptor instead
(`RegisterFunction::new(..).observe(Observe::owner().args_format::<Config>().handler(..))`):
`ObserveHandler` replaces `TriggerHandler`,
and observers' args replace trigger configs.

**Signature**

```rust theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
register_trigger_type(trigger_type: RegisterTriggerType<H, C, R>) -> TriggerTypeRef<C, R>
```

> [tab] Parameters
>
> **trigger\_type** `RegisterTriggerType\<H, C, R\>` *required*
>
> **`RegisterTriggerType` fields**
>
> **call\_request\_format** `fn() -\> RegisterTriggerType\<H, C, T\>` *required*
>
> Set the call request format schema from a type. Changes `R`, enabling compile-time validation on `TriggerTypeRef::register_function`.
>
> **new** `fn(id: impl Into\<String\>, description: impl Into\<String\>, handler: H) -\> Self` *required*
>
> **trigger\_request\_format** `fn() -\> RegisterTriggerType\<H, T, R\>` *required*
>
> Set the trigger request format schema from a type. Changes `C`, enabling compile-time validation on `TriggerTypeRef::register_trigger`.

> [tab] Example
>
> ```rust theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
> let my_trigger = worker.register_trigger_type(
>     RegisterTriggerType::new("my-trigger", "My custom trigger", MyHandler)
>         .trigger_request_format::<MyConfig>()
>         .call_request_format::<MyRequest>(),
> );
>
> // Compile-time safe: config must be MyConfig, function input must be MyRequest
> my_trigger.register_function("my::handler", |req: MyRequest| -> Result<serde_json::Value, iii_sdk::Error> {
>     Ok(serde_json::json!({ "data": req.data }))
> });
> my_trigger.register_trigger("my::handler", MyConfig { url: "/hook".into() });
> ```

***

### unregister\_trigger\_type

> [!WARNING]
>
> **Deprecated since 0.25.0.** Unregister the function registered with RegisterFunction::observe instead; see [https://iii.dev/docs/upgrading/from-0-24-x](https://iii.dev/docs/upgrading/from-0-24-x.md)

Unregister a previously registered trigger type.

**Deprecated since 0.25.0** with `register_trigger_type`.

**Signature**

```rust theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
unregister_trigger_type(id: impl Into<String>)
```

> [tab] Parameters
>
> **id** `impl Into\<String\>` *required*

> [tab] Example
>
> ```rust theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
> worker.unregister_trigger_type("cron");
> ```

***

### fatal\_error

Fatal error that stopped the worker, if any. Set when the engine rejects
registration (see `Error::RegistrationRejected`); the worker does not
reconnect once this is populated.

**Signature**

```rust theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
fatal_error() -> Option<Error>
```

***

### get\_connection\_state

Get the current connection state.

**Signature**

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

#### Example

```rust theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
if worker.get_connection_state() != IIIConnectionState::Connected {
    eprintln!("engine not reachable yet");
}
```

***

### namespace

The effective worker namespace (resolved from `InitOptions.namespace` /
`III_NAMESPACE`), or `None` for the engine's `default`.

**Signature**

```rust theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
namespace() -> Option<String>
```

***

### observe

Observes `source` and invokes `target` once per matching event.

Returns at once, before the engine answered: the handle starts
`pending`; `ObserverHandle::ready` resolves on `active` and fails on
`error` (`INVALID_ARGS`, `INVALID_FILTER`, `FORBIDDEN`, an owner
rejection, `UNSUPPORTED` against an engine without observe). There is
no inline handler: `target` is a registered function, and the observer
stays `pending` until it is registered.

**Signature**

```rust theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
observe(source: Source, target: impl Into<Target>) -> ObserverHandle
```

#### Parameters

**source** `Source` *required*

**`Source` fields**

**args** `fn(args: Value) -\> Self` *required*

Args for the function's owner (owner-delivered functions only): what to set up for this observer, validated against its `args_format`.

**capture** `fn(capture: impl IntoIterator) -\> Self` *required*

What travels to the target. Default `[input, output, caller]`.

**deliver** `fn(deliver: Deliver) -\> Self` *required*

What the target receives: the `Observed` envelope (default), or the observed input or output alone.

**filters** `fn(filters: Value) -\> Self` *required*

Which events reach the target: a filter over `input`, `output`, `error`, `caller` and `metadata`, with explicit operators (`{ "input.amount": { "$gte": 500 } }`). Unset matches every event.

**function** `fn(function_id: impl Into\<String\>) -\> Self` *required*

Observe `function_id`. Every function is observable.

**function\_id** `fn() -\> &str` *required*

The observed function id.

**namespace** `fn(namespace: impl Into\<String\>) -\> Self` *required*

The namespace the function is in. Unset, it resolves like a `trigger`: this worker's namespace (`default` for `engine::*`).

**on** `fn(on: On) -\> Self` *required*

Which outcomes activate the observer (auto functions only). Default `On::Success`.

**target** `impl Into\<Target\>` *required*

**`Target` fields**

**function** `fn(function_id: impl Into\<String\>) -\> Self` *required*

**namespace** `fn(namespace: impl Into\<String\>) -\> Self` *required*

The target's namespace. Unset, it resolves like a `trigger`.

***

### observe\_with

`observe` with the observer's id, policy and metadata.

**Signature**

```rust theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
observe_with(source: Source, target: impl Into<Target>, options: ObserverOptions) -> ObserverHandle
```

#### Parameters

**source** `Source` *required*

**`Source` fields**

**args** `fn(args: Value) -\> Self` *required*

Args for the function's owner (owner-delivered functions only): what to set up for this observer, validated against its `args_format`.

**capture** `fn(capture: impl IntoIterator) -\> Self` *required*

What travels to the target. Default `[input, output, caller]`.

**deliver** `fn(deliver: Deliver) -\> Self` *required*

What the target receives: the `Observed` envelope (default), or the observed input or output alone.

**filters** `fn(filters: Value) -\> Self` *required*

Which events reach the target: a filter over `input`, `output`, `error`, `caller` and `metadata`, with explicit operators (`{ "input.amount": { "$gte": 500 } }`). Unset matches every event.

**function** `fn(function_id: impl Into\<String\>) -\> Self` *required*

Observe `function_id`. Every function is observable.

**function\_id** `fn() -\> &str` *required*

The observed function id.

**namespace** `fn(namespace: impl Into\<String\>) -\> Self` *required*

The namespace the function is in. Unset, it resolves like a `trigger`: this worker's namespace (`default` for `engine::*`).

**on** `fn(on: On) -\> Self` *required*

Which outcomes activate the observer (auto functions only). Default `On::Success`.

**target** `impl Into\<Target\>` *required*

**`Target` fields**

**function** `fn(function_id: impl Into\<String\>) -\> Self` *required*

**namespace** `fn(namespace: impl Into\<String\>) -\> Self` *required*

The target's namespace. Unset, it resolves like a `trigger`.

**options** `ObserverOptions` *required*

**`ObserverOptions` fields**

**expires\_in** `fn(expires_in: Duration) -\> Self` *required*

Dispose of the observer after this long.

**id** `fn(id: impl Into\<String\>) -\> Self` *required*

The observer's id. Default: a random UUID v4, kept across replays.

**max\_fires** `fn(max_fires: u64) -\> Self` *required*

Dispose of the observer after this many activations.

**max\_in\_flight** `fn(max_in_flight: u32) -\> Self` *required*

At most this many activations running at once; more queue in the engine (or fail an owner's `call` with `OVERFLOW`).

**metadata** `fn(metadata: Value) -\> Self` *required*

Delivered as the metadata sidecar of every activation. The function's owner never sees it.

***

### set\_namespace

Override the worker's target namespace (call before connect). Applied by
`register_worker` after resolving
`InitOptions.namespace` and `III_NAMESPACE`.

**Signature**

```rust theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
set_namespace(namespace: impl Into<String>)
```

#### Parameters

**namespace** `impl Into\<String\>` *required*

***

### shutdown

Shutdown the III client and wait for the connection thread to finish.

This stops the connection loop, sends a shutdown signal, and joins
the background connection thread. OpenTelemetry is flushed inside the
connection thread before it exits.

**Signature**

```rust theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
shutdown()
```

#### Example

```rust theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
worker.shutdown();
```

***

### shutdown\_async

Shutdown the III client.

This stops the connection loop and sends a shutdown signal, but it
does not join `connection_thread`.

This method returns without waiting for `run_connection()` to finish,
making it safe to call from an async context without stalling the
executor; `shutdown` blocks and joins the thread.
The OpenTelemetry flush (`telemetry::shutdown_otel()`) still runs inside the connection thread
after `run_connection()` returns, so it may not complete unless
`shutdown` is used to join the thread.

**Signature**

```rust theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
async shutdown_async()
```

#### Example

```rust theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
worker.shutdown_async().await;
```

***

### wait\_until\_registered

Wait until the engine accepts this worker's initial registration.

Returns `Error::RegistrationRejected` for a fatal identity conflict,
`Error::Timeout` when the deadline expires, and
`Error::NotConnected` when called before the client starts or after it
stops.

**Signature**

```rust theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
async wait_until_registered(timeout: Duration) -> Result<(), Error>
```

#### Parameters

**timeout** `Duration` *required*

## Functions

### current\_invocation

The invocation the calling task is running for, or `None` outside any
handler (and in a task spawned from a handler without `scope`).

**Signature**

```rust theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
current_invocation() -> Option<InvocationCtx>
```

***

### scope

Runs `fut` with `ctx` as its current invocation. Use it to keep the
handler's context in a task it spawns; `None` runs `fut` outside any
invocation. The local-call nesting of the calling task is carried too, so
recursing through spawned tasks stays bounded.

**Signature**

```rust theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
scope(ctx: impl Into<Option<InvocationCtx>>, fut: F) -> impl Future
```

#### Parameters

**ctx** `impl Into\<Option\<InvocationCtx\>\>` *required*

**`InvocationCtx` fields**

**function\_id** `String` *required*

The function being invoked.

**invocation\_id** `String` *required*

This invocation's id (generated by the SDK for a local call).

**caller** `Option\<Caller\>`

Who made the call: the engine-stamped caller of a remote invocation, or this worker (with the calling handler) for a local one. `None` when the engine did not say (an engine older than 0.25).

**activation** `Option\<Activation\>`

Set when this invocation is an observer activation.

**observe\_depth** `u32` *required*

Depth of the causal chain in observe hops; 0 outside observers.

**metadata** `Option\<Value\>`

The invocation's metadata sidecar.

**traceparent** `Option\<String\>`

W3C trace context of the invocation's `execute` span, when tracing is on: events emitted from it join its trace.

**baggage** `Option\<String\>`

W3C baggage of the invocation.

**fut** `F` *required*

## Types

### iii\_sdk

[`EnqueueResult`](#enqueueresult) · [`InitOptions`](#initoptions) · [`RegisterFunction`](#registerfunction) · [`RegisterTriggerType`](#registertriggertype) · [`TelemetryOptions`](#telemetryoptions)

#### EnqueueResult

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

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

***

#### InitOptions

Configuration options passed to `register_worker`.

| Name | Type | Required | Description |
| - | - | - | - |
| `metadata` | Option\<iii::[`WorkerMetadata`](#workermetadata)> | No | Custom worker metadata. Auto-detected if `None`. In managed identity mode, process-wide identity variables override matching fields. |
| `headers` | `Option<HashMap<String, String>>` | No | Custom HTTP headers sent during the WebSocket handshake, on the main connection and on channels from `create_channel`. `Authorization: Bearer<br />$III_TOKEN` is added unless you set `Authorization` here. |
| `otel` | `Option<iii_helpers::observability::OtelConfig>` | No | OpenTelemetry configuration. |
| `namespace` | `Option<String>` | No | Namespace this worker belongs to. In managed mode, resolution order is `namespace` > env `III_NAMESPACE` > `None`. In explicit mode, the environment is not used. It scopes more than the registration. The worker and its functions register here, and everything the worker does afterwards follows it: a `IIIClient::trigger` resolves its target here and a `IIIClient::register_trigger` binds here, unless the call names another namespace. |
| `identity` | [`WorkerIdentityMode`](#workeridentitymode) | Yes | Selects whether process-wide managed identity variables can override this connection's metadata. Auxiliary connections should use `WorkerIdentityMode::Explicit`. |

***

#### RegisterFunction

Function registration builder.

The function ID is supplied separately at registration time via
`IIIClient::register_function`, `RegisterFunction` only carries the handler
and optional metadata.

Constructors:

* `RegisterFunction::new`: sync function. Accepts both typed handlers
  (schemas auto-extracted via `schemars`) and `Fn(Value, Option<Value>) -> Result<Value, Error>`
  closures. The second argument is the per-invocation metadata sidecar and
  is `None` when absent.
* `RegisterFunction::new_async`: async equivalent of `new`.
* `RegisterFunction::http`: function invoked over HTTP (Lambda,
  Cloudflare Workers, etc.).

Builder methods (all consume `self`):

* `description`
* `metadata`
* `request_format`: overrides any auto-extracted schema.
* `response_format`: overrides any auto-extracted schema.
* `observe`: how observers of the function are delivered,
  and the hooks that run when one is added or removed.
* `local_dispatch`: opt out of in-process calls.

| Name | Type | Required | Description |
| - | - | - | - |
| `description` | `fn(desc: impl Into<String>) -> Self` | Yes | Set the function description. |
| `http` | `fn(config: HttpInvocationConfig) -> Self` | Yes | Create a registration for an **HTTP-invoked** function (Lambda, Cloudflare Workers, etc.). No local handler runs. |
| `local_dispatch` | `fn(enabled: bool) -> Self` | Yes | Whether calls to this function from this same worker may run in-process once the engine allows it. Default `true`. |
| `metadata` | `fn(meta: Value) -> Self` | Yes | Set function metadata. |
| `new` | `fn(f: F) -> Self` | Yes | Create a registration for a **sync** typed function. |
| `new_async` | `fn(f: F) -> Self` | Yes | Create a registration for an **async** typed function. |
| `observe` | fn(observe: [`Observe`](#observe)) -> Self | Yes | How observers of this function are delivered, and the hooks that run when one is added or removed (`Observe::owner` / `Observe::auto`). Every function is observable without it, as `auto` without hooks. |
| `request_format` | `fn(schema: Value) -> Self` | Yes | Set the request format schema. Overrides any auto-extracted schema. |
| `response_format` | `fn(schema: Value) -> Self` | Yes | Set the response format schema. Overrides any auto-extracted schema. |

***

#### RegisterTriggerType

Builder for registering a custom trigger type with optional format schemas.

**Deprecated since 0.25.0** together with
`IIIClient::register_trigger_type`: register a function with an observe
descriptor (`RegisterFunction::observe`) instead. Migration guide:
[https://iii.dev/docs/upgrading/from-0-24-x](https://iii.dev/docs/upgrading/from-0-24-x.md).

Type parameters:

* `C` tracks the trigger registration type (set via `.trigger_request_format::<T>()`)
* `R` tracks the call request type (set via `.call_request_format::<T>()`)

Both default to `Value` (untyped) and change when the respective builder
method is called. This allows `IIIClient::register_trigger_type` to return a
`TriggerTypeRef<C, R>` with compile-time safety for both config and
function input types.

| Name | Type | Required | Description |
| - | - | - | - |
| `call_request_format` | fn() -> [`RegisterTriggerType`](#registertriggertype)\<H, C, T> | Yes | Set the call request format schema from a type. Changes `R`, enabling compile-time validation on `TriggerTypeRef::register_function`. |
| `new` | `fn(id: impl Into<String>, description: impl Into<String>, handler: H) -> Self` | Yes | - |
| `trigger_request_format` | fn() -> [`RegisterTriggerType`](#registertriggertype)\<H, T, R> | Yes | Set the trigger request format schema from a type. Changes `C`, enabling compile-time validation on `TriggerTypeRef::register_trigger`. |

***

#### TelemetryOptions

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

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

### iii\_sdk::builtin\_triggers

[`CronCallRequest`](#croncallrequest) · [`CronTriggerConfig`](#crontriggerconfig) · [`HttpCallRequest`](#httpcallrequest) · [`HttpMethod`](#httpmethod) · [`HttpTriggerConfig`](#httptriggerconfig) · [`LogCallRequest`](#logcallrequest) · [`LogLevel`](#loglevel) · [`LogTriggerConfig`](#logtriggerconfig) · [`QueueTriggerConfig`](#queuetriggerconfig) · [`StateCallRequest`](#statecallrequest) · [`StateEventType`](#stateeventtype) · [`StateTriggerConfig`](#statetriggerconfig) · [`SubscribeTriggerConfig`](#subscribetriggerconfig)

#### CronCallRequest

| Name | Type | Required | Description |
| - | - | - | - |
| `trigger` | `String` | Yes | - |
| `job_id` | `String` | Yes | - |
| `scheduled_time` | `String` | Yes | - |
| `actual_time` | `String` | Yes | - |

***

#### CronTriggerConfig

| Name | Type | Required | Description |
| - | - | - | - |
| `expression` | `String` | Yes | Cron expression (6-field format: sec min hour day month weekday) |
| `condition_function_id` | `Option<String>` | No | Optional function ID to evaluate before invoking handler |

***

#### HttpCallRequest

| Name | Type | Required | Description |
| - | - | - | - |
| `query_params` | `HashMap<String, String>` | Yes | - |
| `path_params` | `HashMap<String, String>` | Yes | - |
| `headers` | `HashMap<String, String>` | Yes | - |
| `path` | `String` | Yes | - |
| `method` | `String` | Yes | - |
| `body` | `Value` | Yes | - |

***

#### HttpMethod

| Name | Type | Required | Description |
| - | - | - | - |
| `Get` | `unit` | Yes | - |
| `Post` | `unit` | Yes | - |
| `Put` | `unit` | Yes | - |
| `Delete` | `unit` | Yes | - |
| `Patch` | `unit` | Yes | - |
| `Head` | `unit` | Yes | - |
| `Options` | `unit` | Yes | - |

***

#### HttpTriggerConfig

| Name | Type | Required | Description |
| - | - | - | - |
| `api_path` | `String` | Yes | HTTP endpoint path (e.g. `/users/:id`) |
| `http_method` | Option\<[`HttpMethod`](#httpmethod)> | No | HTTP method (defaults to GET) |
| `condition_function_id` | `Option<String>` | No | Optional function ID to evaluate before invoking handler |

***

#### LogCallRequest

| Name | Type | Required | Description |
| - | - | - | - |
| `timestamp_unix_nano` | `u64` | Yes | - |
| `observed_timestamp_unix_nano` | `u64` | Yes | - |
| `severity_number` | `u32` | Yes | - |
| `severity_text` | `String` | Yes | - |
| `body` | `String` | Yes | - |
| `attributes` | `Value` | Yes | - |
| `trace_id` | `String` | Yes | - |
| `span_id` | `String` | Yes | - |
| `resource` | `Value` | Yes | - |
| `service_name` | `String` | Yes | - |
| `instrumentation_scope_name` | `String` | Yes | - |
| `instrumentation_scope_version` | `String` | Yes | - |

***

#### LogLevel

| Name | Type | Required | Description |
| - | - | - | - |
| `All` | `unit` | Yes | - |
| `Debug` | `unit` | Yes | - |
| `Info` | `unit` | Yes | - |
| `Warn` | `unit` | Yes | - |
| `Error` | `unit` | Yes | - |

***

#### LogTriggerConfig

| Name | Type | Required | Description |
| - | - | - | - |
| `level` | Option\<[`LogLevel`](#loglevel)> | No | Minimum log level to trigger on |

***

#### QueueTriggerConfig

| Name | Type | Required | Description |
| - | - | - | - |
| `topic` | `String` | Yes | Queue topic to subscribe to |
| `condition_function_id` | `Option<String>` | No | Optional function ID to evaluate before invoking handler |
| `queue_config` | `Option<Value>` | No | Queue-specific subscriber configuration |
| `queue_config` | fn(config: impl Serialize) -> Result\<Self, serde\_json::[`Error`](#error)> | Yes | - |

***

#### StateCallRequest

| Name | Type | Required | Description |
| - | - | - | - |
| `message_type` | `String` | Yes | - |
| `event_type` | [`StateEventType`](#stateeventtype) | Yes | - |
| `scope` | `String` | Yes | - |
| `key` | `String` | Yes | - |
| `old_value` | `Option<Value>` | No | - |
| `new_value` | `Value` | Yes | - |

***

#### StateEventType

| Name | Type | Required | Description |
| - | - | - | - |
| `Created` | `unit` | Yes | - |
| `Updated` | `unit` | Yes | - |
| `Deleted` | `unit` | Yes | - |

***

#### StateTriggerConfig

| Name | Type | Required | Description |
| - | - | - | - |
| `scope` | `Option<String>` | No | State scope to watch (exact match filter) |
| `key` | `Option<String>` | No | State key to watch (exact match filter) |
| `condition_function_id` | `Option<String>` | No | Optional function ID to evaluate before invoking handler |

***

#### SubscribeTriggerConfig

| Name | Type | Required | Description |
| - | - | - | - |
| `topic` | `String` | Yes | Topic to subscribe to |
| `condition_function_id` | `Option<String>` | No | Optional function ID to evaluate before invoking handler |

### iii\_sdk::channel

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

#### Channel

A streaming channel pair for worker-to-worker data transfer.

| Name | Type | Required | Description |
| - | - | - | - |
| `writer` | [`ChannelWriter`](#channelwriter) | Yes | - |
| `reader` | [`ChannelReader`](#channelreader) | Yes | - |
| `writer_ref` | [`StreamChannelRef`](#streamchannelref) | Yes | - |
| `reader_ref` | [`StreamChannelRef`](#streamchannelref) | Yes | - |

***

#### ChannelReader

WebSocket-backed reader for streaming binary data and text messages.

| Name | Type | Required | Description |
| - | - | - | - |
| `close` | async fn() -> Result\<(), [`Error`](#error)> | Yes | - |
| `new` | fn(engine\_ws\_base: \&str, channel\_ref: &[`StreamChannelRef`](#streamchannelref)) -> Self | Yes | Authenticates with `III_TOKEN` as a bearer token when it is set. |
| `next_binary` | async fn() -> Result\<Option\<Vec\<u8>>, [`Error`](#error)> | Yes | Read the next binary chunk from the channel. Text messages are dispatched to registered callbacks. Returns `None` when the stream is closed. |
| `on_message` | `async fn(callback: F)` | Yes | Register a callback for text messages received on this channel. |
| `read_all` | async fn() -> Result\<Vec\<u8>, [`Error`](#error)> | Yes | Read the entire stream into a single `Vec<u8>`. |

***

#### ChannelWriter

WebSocket-backed writer for streaming binary data and text messages.

| Name | Type | Required | Description |
| - | - | - | - |
| `close` | async fn() -> Result\<(), [`Error`](#error)> | Yes | - |
| `new` | fn(engine\_ws\_base: \&str, channel\_ref: &[`StreamChannelRef`](#streamchannelref)) -> Self | Yes | Authenticates with `III_TOKEN` as a bearer token when it is set. |
| `send_message` | async fn(msg: \&str) -> Result\<(), [`Error`](#error)> | Yes | - |
| `write` | async fn(data: &\[u8]) -> Result\<(), [`Error`](#error)> | Yes | - |

***

#### StreamChannelRef

| Name | Type | Required | Description |
| - | - | - | - |
| `channel_id` | `String` | Yes | - |
| `access_key` | `String` | Yes | - |
| `direction` | [`ChannelDirection`](#channeldirection) | Yes | - |

### iii\_sdk::channels

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

#### ChannelDirection

| Name | Type | Required | Description |
| - | - | - | - |
| `Read` | `unit` | Yes | - |
| `Write` | `unit` | Yes | - |

***

#### ChannelItem

| Name | Type | Required | Description |
| - | - | - | - |
| `Text` | `(String)` | Yes | - |
| `Binary` | `(Vec<u8>)` | Yes | - |

### iii\_sdk::context

[`InvocationCtx`](#invocationctx)

#### InvocationCtx

The invocation a handler is running for.

| Name | Type | Required | Description |
| - | - | - | - |
| `function_id` | `String` | Yes | The function being invoked. |
| `invocation_id` | `String` | Yes | This invocation's id (generated by the SDK for a local call). |
| `caller` | Option\<[`Caller`](#caller)> | No | Who made the call: the engine-stamped caller of a remote invocation, or this worker (with the calling handler) for a local one. `None` when the engine did not say (an engine older than 0.25). |
| `activation` | Option\<[`Activation`](#activation)> | No | Set when this invocation is an observer activation. |
| `observe_depth` | `u32` | Yes | Depth of the causal chain in observe hops; 0 outside observers. |
| `metadata` | `Option<Value>` | No | The invocation's metadata sidecar. |
| `traceparent` | `Option<String>` | No | W3C trace context of the invocation's `execute` span, when tracing is on: events emitted from it join its trace. |
| `baggage` | `Option<String>` | No | W3C baggage of the invocation. |

### iii\_sdk::engine

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

#### EngineFunctions

Engine function ids for internal operations.

***

#### EngineTriggers

Engine trigger ids.

### iii\_sdk::errors

[`Error`](#error) · [`InvocationError`](#invocationerror)

#### Error

Errors returned by the III SDK.

| Name | Type | Required | Description |
| - | - | - | - |
| `NotConnected` | `unit` | Yes | - |
| `Timeout` | `unit` | Yes | - |
| `Runtime` | `(String)` | Yes | - |
| `Remote` | `{ code: String, message: String, stacktrace: Option<String> }` | Yes | - |
| `Handler` | `(String)` | Yes | - |
| `Serde` | `(String)` | Yes | - |
| `WebSocket` | `(String)` | Yes | - |
| `RegistrationRejected` | `{ code: String, namespace: String, worker_name: Option<String>, function_id: Option<String>, owner_worker_id: String }` | Yes | Fatal registration rejection: another live worker already holds this worker name in the namespace, or the engine sent an unknown rejection code. The SDK stops and does not reconnect. A `FUNCTION_NAMESPACE_CONFLICT` is non-fatal, is logged, and does not produce this error. |
| `invocation_error` | fn() -> Option\<[`InvocationError`](#invocationerror)> | Yes | If this is a remote invocation failure (`Error::Remote`), return its structured form. Returns `None` for transport/serde/handler errors. |

***

#### InvocationError

Structured invocation failure, mirroring the Node and Python `InvocationError`.

Produced from the `Error::Remote` variant via `Error::invocation_error`.
`function_id` is `None` from that accessor because the wire `Remote` payload
does not carry it.

| Name | Type | Required | Description |
| - | - | - | - |
| `code` | `String` | Yes | - |
| `message` | `String` | Yes | - |
| `function_id` | `Option<String>` | No | - |
| `stacktrace` | `Option<String>` | No | - |

### iii\_sdk::observable

[`Observe`](#observe) · [`ObserveHandler`](#observehandler) · [`Observer`](#observer) · [`ObserveRejection`](#observerejection)

#### Observe

The observe descriptor of a function, for
`RegisterFunction::observe`.

* `Observe::auto`: the function's invocations are the events; every
  observer is offered every invocation and the SDK reports the matching
  ones. It takes no args.
* `Observe::owner`: the function's owner reads each observer's args, sets
  up what they ask for and hands each event to the observers it belongs to
  with `Observer::emit` or `Observer::call`.

A function registered without one is still observable, as `auto` without
hooks.

| Name | Type | Required | Description |
| - | - | - | - |
| `allow` | `fn(allow: bool) -> Self` | Yes | `false` refuses every observer (`NOT_OBSERVABLE`). Default `true`. |
| `args_format` | `fn() -> Self` | Yes | The JSON Schema of the observers' args, generated from `T`. The engine validates every `observe` against it (`INVALID_ARGS`) before `ObserveHandler::on_observer_added` runs. `#[serde(deny_unknown_fields)]` on `T` rejects argument typos. |
| `args_format_value` | `fn(schema: Value) -> Self` | Yes | `args_format` from a JSON Schema value. |
| `auto` | `fn() -> Self` | Yes | Auto delivery (the default): every invocation is an event. |
| `handler` | `fn(handler: H) -> Self` | Yes | The callbacks that run when an observer is added to or removed from this function. |
| `legacy_trigger_type` | `fn(trigger_type: impl Into<String>) -> Self` | Yes | Accept the old `register_trigger({ trigger_type })` for this trigger type: when no live provider of it exists, the engine turns such a trigger into an observer of this function, with `Observer::legacy` set. |
| `owner` | `fn() -> Self` | Yes | Owner delivery: this worker routes events to observers by their args. |

***

#### ObserveHandler

Callbacks of an observable function, run once per observer added or
removed, one at a time per function and in the engine's order.

`on_observer_added` runs before the SDK acknowledges the observer, so what
it puts in the owner's index is in place before the engine marks the
observer `active`. Returning an error rejects the observer: an
`ObserveRejection` sets the code, a plain error is `OBSERVE_REJECTED`,
and a callback still running after 30 s is `OWNER_TIMEOUT`.

A callback past the timeout is cancelled (its future is dropped at its
next `.await`) so the function's next callback can run; anything it
spawned keeps running and may overlap that next callback. Callbacks run on
the connection's runtime: do not block in them.

| Name | Type | Required | Description |
| - | - | - | - |
| `on_observer_added` | fn(obs: &'life1 [`Observer`](#observer)) -> Pin\<Box\<dyn Future + Send>> | No | An observer was attached to the function. Index it by its args here. |
| `on_observer_removed` | fn(obs: &'life1 [`Observer`](#observer)) -> Pin\<Box\<dyn Future + Send>> | No | An observer was detached (unobserve, disposal, its worker left for good, a reconnect that no longer lists it). Cannot fail. |

***

#### Observer

One observer of a function this worker hosts, as its owner sees it: its
id, args, filters, target, capture and `on`. Never its metadata, policy or
observing worker.

Cheap to clone (an `Arc`), so owners keep it in their own index. Two
`Observer`s are equal when their ids are.

| Name | Type | Required | Description |
| - | - | - | - |
| `args` | fn() -> Result\<T, [`ObserveRejection`](#observerejection)> | Yes | The observer's args as `T`. The engine validated them against the function's `args_format`; a mismatch with `T` is `INVALID_ARGS`. |
| `args_value` | `fn() -> &Value` | Yes | The observer's args as JSON (`{}` when it has none). |
| `call` | async fn(payload: impl Serialize) -> Result\<R, [`Error`](#error)> | Yes | Calls the observer's target with `payload` through the engine and returns its result: the HTTP response, the queue ack. Owner functions only. Fails with `FILTERS_NOT_MATCHED`, sending nothing, when the observer's filters reject `{ input: payload, caller, metadata }`; with `OBSERVER_NOT_ACTIVE` once it was removed; with the engine's code (`LOOP_GUARD`, `OVERFLOW`, ...) or the target's error otherwise. |
| `call_with_timeout` | async fn(payload: impl Serialize, timeout: Duration) -> Result\<R, [`Error`](#error)> | Yes | `call` with its own timeout. |
| `capture` | fn() -> &\[[`Capture`](#capture)] | Yes | What activations ship to the target. |
| `emit` | fn(event: \&T) -> Result\<bool, [`Error`](#error)> | Yes | Hands `event` to this observer, fire-and-forget. Owner functions only (`NOT_OWNER_DELIVERED` otherwise). |
| `filters` | `fn() -> &Value` | Yes | The observer's filters in normal form (`{}` matches every event). Applied by the SDK on every `emit` and `call`; the owner never changes them. |
| `function_id` | `fn() -> &str` | Yes | The observed function: the one this worker registered. |
| `id` | `fn() -> &str` | Yes | The observer's id (client-generated, stable across replays). |
| `is_active` | `fn() -> bool` | Yes | Whether it is still delivered to: acked, and neither removed nor rejected since. |
| `legacy` | fn() -> Option\<&[`LegacyTrigger`](#legacytrigger)> | Yes | The old trigger this observer stands for, when the engine's legacy shim created it from a `register_trigger`. Read `config` as its args. |
| `matches` | `fn(doc: &Doc<'_>) -> bool` | Yes | Evaluates the observer's filters against `doc`, exactly as given. Lets an owner answer before calling (the HTTP router's 422). |
| `namespace` | `fn() -> &str` | Yes | The observed function's namespace. |
| `on` | fn() -> &[`On`](#on) | Yes | Which outcomes activate it (auto functions only). |
| `reject` | `fn(code: impl Into<String>, message: impl Into<String>)` | Yes | Rejects this observer after it was accepted (a config reload removed what it needs). It stops receiving events now; the engine moves it to `error` with this code and then removes it, which runs `ObserveHandler::on_observer_removed`. The rejection holds across a reconnect: the SDK sends it again whenever the engine lists the observer, until a fresh `observeradded` brings it back. |
| `target` | `fn() -> &str` | Yes | The function each activation invokes. |

***

#### ObserveRejection

An owner's refusal of an observer, with the code its `ready()` fails with.

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

### iii\_sdk::observe

[`Observed`](#observed) · [`ObservedError`](#observederror) · [`ObserverHandle`](#observerhandle) · [`ObserverOptions`](#observeroptions) · [`ObserverReason`](#observerreason) · [`ObserverStatus`](#observerstatus) · [`Source`](#source) · [`StateListener`](#statelistener) · [`Target`](#target)

#### Observed

What an observer's target receives with the default `deliver: envelope`:
the observed invocation (auto) or emitted event (owner `emit`), per the
observer's `capture`.

```rust,no_run theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
iii.register_function(
    "alerts::payment-failed",
    RegisterFunction::new(|event: Observed<Value>| {
        println!("{} failed: {:?}", event.function_id, event.error);
        Ok::<_, Error>(())
    }),
);
```

| Name | Type | Required | Description |
| - | - | - | - |
| `observer_id` | `String` | Yes | - |
| `activation_id` | `String` | Yes | - |
| `function_id` | `String` | Yes | - |
| `namespace` | `Option<String>` | No | - |
| `invocation_id` | `String` | Yes | - |
| `status` | [`InvocationStatus`](#invocationstatus) | Yes | - |
| `input` | `Option<I>` | No | - |
| `output` | `Option<O>` | No | - |
| `error` | Option\<[`ObservedError`](#observederror)> | No | - |
| `caller` | Option\<[`Caller`](#caller)> | No | - |
| `metadata` | `Option<Value>` | No | - |
| `started_at_ms` | `u64` | Yes | - |
| `duration_ms` | `f64` | Yes | - |

***

#### ObservedError

`Observed::error`.

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

***

#### ObserverHandle

Handle to an observer created by `IIIClient::observe`. Cheap to clone.

The observer exists until `dispose` (or its policy runs
out); dropping the handle does not remove it. It works before the
connection is up and is replayed with the same id after a reconnect.

| Name | Type | Required | Description |
| - | - | - | - |
| `dispose` | async fn() -> Result\<(), [`Error`](#error)> | Yes | Removes the observer. Once it resolves (the engine confirmed it, or after 5 s without an answer), no new activation starts and the owner's `call` for it fails with `OBSERVER_NOT_ACTIVE`. |
| `fires` | `fn() -> u64` | Yes | Activations so far, as last reported by the engine. |
| `id` | `fn() -> &str` | Yes | The observer's id. |
| `on_state_change` | fn(listener: F) -> [`StateListener`](#statelistener) | Yes | Calls `listener` on every state change. Listeners run on one process-wide thread, one call at a time and in the order the changes happened, never on the connection's read loop: a listener may call the client. A listener that blocks delays every client's listeners in the process; hand slow work to a task of its own. |
| `ready` | async fn() -> Result\<(), [`Error`](#error)> | Yes | Resolves once the observer is `active`. Fails with the reason's code (`Error::Remote`) when it ends in `error` or `disposed`; waits through `pending` and `suspended`. |
| `reason` | fn() -> Option\<[`ObserverReason`](#observerreason)> | Yes | Why it is in `error` (or `suspended`, `disposed`): an engine code such as `INVALID_ARGS`, `FORBIDDEN`, `UNSUPPORTED`, or the owner's own rejection code. |
| `state` | fn() -> [`ObserverState`](#observerstate) | Yes | The current state. |
| `warnings` | `fn() -> Vec<String>` | Yes | The engine's warnings about the filters (paths it could not verify against an open schema). |

***

#### ObserverOptions

The observer itself: its id, policy and metadata sidecar.

| Name | Type | Required | Description |
| - | - | - | - |
| `expires_in` | `fn(expires_in: Duration) -> Self` | Yes | Dispose of the observer after this long. |
| `id` | `fn(id: impl Into<String>) -> Self` | Yes | The observer's id. Default: a random UUID v4, kept across replays. |
| `max_fires` | `fn(max_fires: u64) -> Self` | Yes | Dispose of the observer after this many activations. |
| `max_in_flight` | `fn(max_in_flight: u32) -> Self` | Yes | At most this many activations running at once; more queue in the engine (or fail an owner's `call` with `OVERFLOW`). |
| `metadata` | `fn(metadata: Value) -> Self` | Yes | Delivered as the metadata sidecar of every activation. The function's owner never sees it. |

***

#### ObserverReason

Why an observer is in its state: `{ code, message }`.

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

***

#### ObserverStatus

An observer's state, why, and how often it fired.

| Name | Type | Required | Description |
| - | - | - | - |
| `state` | [`ObserverState`](#observerstate) | Yes | - |
| `reason` | Option\<[`ObserverReason`](#observerreason)> | No | - |
| `fires` | `u64` | Yes | - |

***

#### Source

The left side of an observer: what is observed.

| Name | Type | Required | Description |
| - | - | - | - |
| `args` | `fn(args: Value) -> Self` | Yes | Args for the function's owner (owner-delivered functions only): what to set up for this observer, validated against its `args_format`. |
| `capture` | `fn(capture: impl IntoIterator) -> Self` | Yes | What travels to the target. Default `[input, output, caller]`. |
| `deliver` | fn(deliver: [`Deliver`](#deliver)) -> Self | Yes | What the target receives: the `Observed` envelope (default), or the observed input or output alone. |
| `filters` | `fn(filters: Value) -> Self` | Yes | Which events reach the target: a filter over `input`, `output`, `error`, `caller` and `metadata`, with explicit operators (`{ "input.amount": { "$gte": 500 } }`). Unset matches every event. |
| `function` | `fn(function_id: impl Into<String>) -> Self` | Yes | Observe `function_id`. Every function is observable. |
| `function_id` | `fn() -> &str` | Yes | The observed function id. |
| `namespace` | `fn(namespace: impl Into<String>) -> Self` | Yes | The namespace the function is in. Unset, it resolves like a `trigger`: this worker's namespace (`default` for `engine::*`). |
| `on` | fn(on: [`On`](#on)) -> Self | Yes | Which outcomes activate the observer (auto functions only). Default `On::Success`. |

***

#### StateListener

A listener added with `ObserverHandle::on_state_change`.

| Name | Type | Required | Description |
| - | - | - | - |
| `unsubscribe` | `fn()` | Yes | Stops calling the listener. |

***

#### Target

The right side of an observer: a registered function.

| Name | Type | Required | Description |
| - | - | - | - |
| `function` | `fn(function_id: impl Into<String>) -> Self` | Yes | - |
| `namespace` | `fn(namespace: impl Into<String>) -> Self` | Yes | The target's namespace. Unset, it resolves like a `trigger`. |

### iii\_sdk::protocol

[`Activation`](#activation) · [`Caller`](#caller) · [`Capture`](#capture) · [`Deliver`](#deliver) · [`Delivery`](#delivery) · [`Dispatch`](#dispatch) · [`DroppedReportStats`](#droppedreportstats) · [`ErrorBody`](#errorbody) · [`FunctionMessage`](#functionmessage) · [`InvocationStatus`](#invocationstatus) · [`LegacyTrigger`](#legacytrigger) · [`LocalFunctionStats`](#localfunctionstats) · [`Message`](#message) · [`ObserveDescriptor`](#observedescriptor) · [`ObservedItem`](#observeditem) · [`ObserverState`](#observerstate) · [`ObserverView`](#observerview) · [`ObserveSource`](#observesource) · [`ObserveTarget`](#observetarget) · [`On`](#on) · [`ParentCaller`](#parentcaller) · [`RegisterFunctionMessage`](#registerfunctionmessage) · [`RegisterTriggerInput`](#registertriggerinput) · [`RegisterTriggerMessage`](#registertriggermessage) · [`RegisterTriggerTypeMessage`](#registertriggertypemessage) · [`TriggerAction`](#triggeraction) · [`TriggerRequest`](#triggerrequest) · [`TriggerRequestWithMetadata`](#triggerrequestwithmetadata) · [`UnregisterTriggerMessage`](#unregistertriggermessage) · [`UnregisterTriggerTypeMessage`](#unregistertriggertypemessage)

#### Activation

`invokefunction.activation`.

| Name | Type | Required | Description |
| - | - | - | - |
| `observer_id` | `String` | Yes | - |
| `activation_id` | `Option<String>` | No | Engine → worker: unique per activation. Absent on an owner's `call`. |

***

#### Caller

Who made an invocation. `worker_id` / `worker_name` are stamped by the
engine from the calling connection; `function_id`, `invocation_id` and
`parent` are asserted by the calling SDK.

| Name | Type | Required | Description |
| - | - | - | - |
| `worker_id` | `Option<String>` | No | - |
| `worker_name` | `Option<String>` | No | - |
| `function_id` | `Option<String>` | No | The handler the call was made from; absent for a top-level call. |
| `invocation_id` | `Option<String>` | No | - |
| `parent` | Option\<[`ParentCaller`](#parentcaller)> | No | The caller of that handler, one level only. |
| `strip` | fn() -> [`ParentCaller`](#parentcaller) | Yes | This caller without its own `parent`, as the `parent` of a call made from the handler it invoked. |

***

#### Capture

What an activation ships to the target. A filter may read any root,
whatever is captured.

| Name | Type | Required | Description |
| - | - | - | - |
| `Input` | `unit` | Yes | - |
| `Output` | `unit` | Yes | - |
| `Error` | `unit` | Yes | - |
| `Caller` | `unit` | Yes | - |
| `Metadata` | `unit` | Yes | - |
| `Unknown` | `(String)` | Yes | A value this SDK does not know, kept verbatim. |
| `as_str` | `fn() -> &str` | Yes | The wire spelling. |

***

#### Deliver

What the target's first argument is.

| Name | Type | Required | Description |
| - | - | - | - |
| `Envelope` | `unit` | Yes | The `Observed` envelope. |
| `Input` | `unit` | Yes | The observed invocation's input alone. |
| `Output` | `unit` | Yes | The observed invocation's output alone. |
| `Unknown` | `(String)` | Yes | A value this SDK does not know, kept verbatim. |
| `as_str` | `fn() -> &str` | Yes | The wire spelling. |

***

#### Delivery

How a function's observers are delivered.

| Name | Type | Required | Description |
| - | - | - | - |
| `Auto` | `unit` | Yes | The function's invocations are the events; every observer is offered every invocation. |
| `Owner` | `unit` | Yes | The owner routes events to observers by their args (`Observer::emit` / `Observer::call`). |
| `Unknown` | `(String)` | Yes | A value this SDK does not know, kept verbatim. |
| `as_str` | `fn() -> &str` | Yes | The wire spelling. |

***

#### Dispatch

Which path `IIIClient::trigger` takes.

A call to a function registered by this same worker runs in-process
("local dispatch") when all of these hold:

1. the function has a handler here (not `RegisterFunction::http`)
   and was not registered with `RegisterFunction::local_dispatch(false)`;
2. the engine confirmed it with `functionregistered { local_dispatch: true }`;
3. the call resolves to the namespace the function is registered in;
4. the action is not `TriggerAction::Enqueue` (a `Void` call runs
   locally, fire-and-forget);
5. the dispatch is not `Dispatch::Remote`.

Otherwise the call goes through the engine as before. A local call returns
the same result, error shape and timeout as a remote one, and is reported
to the engine only when an observer's filters match it.

| Name | Type | Required | Description |
| - | - | - | - |
| `Auto` | `unit` | Yes | Run in-process when the five conditions above hold, else remote. |
| `Remote` | `unit` | Yes | Always route through the engine (engine-side effects, tests). |

***

#### DroppedReportStats

SDK-side report drops in `localinvocationstats`.

| Name | Type | Required | Description |
| - | - | - | - |
| `function_id` | `String` | Yes | - |
| `reason` | `String` | Yes | `observe_codes::BUFFER_FULL`, `observe_codes::TOO_LARGE` or `observe_codes::INACTIVE`. |
| `count` | `u64` | Yes | - |

***

#### ErrorBody

| Name | Type | Required | Description |
| - | - | - | - |
| `code` | `String` | Yes | - |
| `message` | `String` | Yes | - |
| `stacktrace` | `Option<String>` | No | - |

***

#### FunctionMessage

| Name | Type | Required | Description |
| - | - | - | - |
| `function_id` | `String` | Yes | - |
| `description` | `Option<String>` | No | - |
| `request_format` | `Option<Value>` | No | - |
| `response_format` | `Option<Value>` | No | - |
| `metadata` | `Option<Value>` | No | - |

***

#### InvocationStatus

Outcome of an observed invocation. An emitted event is always `success`.

| Name | Type | Required | Description |
| - | - | - | - |
| `Success` | `unit` | Yes | - |
| `Error` | `unit` | Yes | - |
| `Unknown` | `(String)` | Yes | A value this SDK does not know, kept verbatim. |
| `as_str` | `fn() -> &str` | Yes | The wire spelling. |

***

#### LegacyTrigger

The old `registerTrigger` an observer was created from by the engine's
legacy shim. The owner reads `config` as the observer's args.

| Name | Type | Required | Description |
| - | - | - | - |
| `trigger_type` | `String` | Yes | - |
| `config` | `Value` | Yes | - |

***

#### LocalFunctionStats

Per-function counts in `localinvocationstats`.

| Name | Type | Required | Description |
| - | - | - | - |
| `function_id` | `String` | Yes | - |
| `count` | `u64` | Yes | - |
| `errors` | `u64` | Yes | - |
| `duration_ms_sum` | `f64` | Yes | - |

***

#### Message

| Name | Type | Required | Description |
| - | - | - | - |
| `RegisterTriggerType` | `{ id: String, description: String, trigger_request_format: Option<Value>, call_request_format: Option<Value>, namespace: Option<String> }` | Yes | - |
| `RegisterTrigger` | `{ id: String, trigger_type: String, function_id: String, config: Value, metadata: Option<Value>, namespace: Option<String>, trigger_namespace: Option<String> }` | Yes | - |
| `TriggerRegistrationResult` | \{ id: String, trigger\_type: String, function\_id: String, error: Option\<[`ErrorBody`](#errorbody)> } | Yes | - |
| `UnregisterTrigger` | `{ id: String, trigger_type: String }` | Yes | - |
| `UnregisterTriggerType` | `{ id: String, namespace: Option<String> }` | Yes | - |
| `RegisterFunction` | \{ id: String, description: Option\<String>, request\_format: Option\<Value>, response\_format: Option\<Value>, metadata: Option\<Value>, invocation: Option\<iii\_helpers::http::HttpInvocationConfig>, observe: Option\<Box\<[`ObserveDescriptor`](#observedescriptor)>> } | Yes | - |
| `UnregisterFunction` | `{ id: String }` | Yes | - |
| `InvokeFunction` | \{ invocation\_id: Option\<uuid::Uuid>, function\_id: String, data: Value, traceparent: Option\<String>, baggage: Option\<String>, action: Option\<[`TriggerAction`](#triggeraction)>, metadata: Option\<Value>, namespace: Option\<String>, caller: Option\<Box\<[`Caller`](#caller)>>, observe\_depth: Option\<u32>, activation: Option\<[`Activation`](#activation)> } | Yes | - |
| `InvocationResult` | \{ invocation\_id: uuid::Uuid, function\_id: String, result: Option\<Value>, error: Option\<[`ErrorBody`](#errorbody)>, traceparent: Option\<String>, baggage: Option\<String> } | Yes | - |
| `Ping` | `unit` | Yes | - |
| `Pong` | `unit` | Yes | - |
| `Reattach` | `{ previous_worker_id: String, reattach_token: Option<String> }` | Yes | Sent to the engine as the first message of a reconnect, before the registration replay: `previous_worker_id` and `reattach_token` are the values the engine assigned via `WorkerRegistered` on the previous connection. The engine retires that connection so the replay lands on a clean slate; the token is required because worker ids alone are publicly discoverable. |
| `WorkerRegistered` | `{ worker_id: String, reattach_token: Option<String>, features: Vec<String> }` | Yes | - |
| `RegistrationRejected` | `{ code: String, namespace: String, worker_name: Option<String>, function_id: Option<String>, owner_worker_id: String }` | Yes | Pushed by the engine when a registration collides with a live worker in the same namespace. The `code` distinguishes the two cases: `WORKER_NAMESPACE_CONFLICT` is fatal (the engine closes the connection; the SDK stops and does not reconnect), while `FUNCTION_NAMESPACE_CONFLICT` refuses a single function id and keeps the connection open. |
| `Observe` | \{ id: String, source: Box\<[`ObserveSource`](#observesource)>, target: [`ObserveTarget`](#observetarget), metadata: Option\<Value>, max\_fires: Option\<u64>, expires\_in\_ms: Option\<u64>, max\_in\_flight: Option\<u32> } | Yes | Observing worker → engine: create, or idempotently replay, an observer owned by this connection. |
| `Unobserve` | `{ id: String }` | Yes | Observing worker → engine: dispose an observer this connection owns. |
| `ObserveResult` | \{ id: String, state: [`ObserverState`](#observerstate), error: Option\<[`ErrorBody`](#errorbody)>, warnings: Vec\<String> } | Yes | Engine → observing worker: the reply to `observe` (also on replay). |
| `ObserverStateChanged` | \{ id: String, state: [`ObserverState`](#observerstate), reason: Option\<[`ErrorBody`](#errorbody)>, fires: u64 } | Yes | Engine → observing worker: every lifecycle transition. |
| `FunctionRegistered` | \{ id: String, namespace: String, revision: u64, local\_dispatch: bool, observers: Vec\<[`ObserverView`](#observerview)> } | Yes | Engine → owner: the `registerfunction` success ack, with the full current observer set. Enables local dispatch for this function. |
| `ObserverAdded` | \{ function\_id: String, namespace: String, revision: u64, observer: [`ObserverView`](#observerview) } | Yes | Engine → owner: one observer attached to a function this connection hosts. Awaits `observerack`. |
| `ObserverRemoved` | `{ function_id: String, namespace: String, revision: u64, id: String }` | Yes | Engine → owner: one observer detached. |
| `ObserverAck` | \{ function\_id: String, namespace: Option\<String>, id: String, revision: u64, error: Option\<[`ErrorBody`](#errorbody)> } | Yes | Owner → engine: accepts one added observer, or rejects it with `error` (also later, for an active observer: a late rejection). |
| `InvocationsObserved` | \{ items: Vec\<[`ObservedItem`](#observeditem)> } | Yes | Owner → engine: matched local invocations of auto functions and `obs.emit` events of owner functions, batched. |
| `LocalInvocationStats` | \{ window\_ms: u64, functions: Vec\<[`LocalFunctionStats`](#localfunctionstats)>, dropped\_reports: Vec\<[`DroppedReportStats`](#droppedreportstats)> } | Yes | Owner → engine: local invocation counts and SDK-side report drops, every 10 s and only when non-zero. |
| `Unknown` | `unit` | Yes | Any message type this SDK does not know, sent by a newer engine. It is ignored (logged at debug level), never sent. |

***

#### ObserveDescriptor

`registerfunction.observe`: the wire half of a function's observe hooks.

| Name | Type | Required | Description |
| - | - | - | - |
| `delivery` | Option\<[`Delivery`](#delivery)> | No | Absent means `Delivery::Auto`. |
| `args_format` | `Option<Value>` | No | JSON Schema the engine validates observers' `args` against. Owner delivery only. |
| `legacy_trigger_type` | `Option<String>` | No | Old `registerTrigger({ type })` calls bind to this function when no live provider of that trigger type exists. |
| `allow` | `Option<bool>` | No | Absent means `true`; `false` refuses observers (`NOT_OBSERVABLE`). |

***

#### ObservedItem

One item of `invocationsobserved`: a matched local invocation of an auto
function, or an emitted event of an owner function.

`input` / `output` / `error` / `metadata` keep `null` apart from absent.

| Name | Type | Required | Description |
| - | - | - | - |
| `function_id` | `String` | Yes | - |
| `namespace` | `Option<String>` | No | - |
| `invocation_id` | `String` | Yes | - |
| `matched` | `Vec<String>` | Yes | - |
| `status` | [`InvocationStatus`](#invocationstatus) | Yes | - |
| `input` | `Option<Value>` | No | - |
| `output` | `Option<Value>` | No | - |
| `error` | `Option<Value>` | No | - |
| `caller` | Option\<[`Caller`](#caller)> | No | - |
| `metadata` | `Option<Value>` | No | - |
| `started_at_ms` | `u64` | Yes | - |
| `duration_ms` | `f64` | Yes | - |
| `observe_depth` | `u32` | Yes | - |
| `traceparent` | `Option<String>` | No | - |
| `baggage` | `Option<String>` | No | - |

***

#### ObserverState

Observer lifecycle states.

| Name | Type | Required | Description |
| - | - | - | - |
| `Pending` | `unit` | Yes | Waiting for its function's owner (and its ack) or its target. |
| `Active` | `unit` | Yes | Delivering. |
| `Suspended` | `unit` | Yes | Its observing worker or its target is gone for now. |
| `Error` | `unit` | Yes | Rejected; see the reason. |
| `Disposed` | `unit` | Yes | Gone for good. |
| `Unknown` | `(String)` | Yes | A value this SDK does not know, kept verbatim. |
| `as_str` | `fn() -> &str` | Yes | The wire spelling. |

***

#### ObserverView

An observer as its function's owner sees it (`functionregistered`,
`observeradded`): never the observer's metadata, policy or observing
worker.

| Name | Type | Required | Description |
| - | - | - | - |
| `id` | `String` | Yes | - |
| `args` | `Value` | Yes | `{}` for an observer without args. |
| `filters` | `Value` | Yes | The observer's filters in normal form; `{}` matches every event. |
| `target` | `String` | Yes | Target function id (its namespace is not disclosed). |
| `capture` | Vec\<[`Capture`](#capture)> | Yes | - |
| `on` | [`On`](#on) | Yes | - |
| `legacy` | Option\<[`LegacyTrigger`](#legacytrigger)> | No | Set when the engine's legacy shim created this observer from an old `registerTrigger`. `null` reads as absent. |

***

#### ObserveSource

The left side of `iii.observe` on the wire. Absent fields stay absent; the
engine applies the defaults.

| Name | Type | Required | Description |
| - | - | - | - |
| `function_id` | `String` | Yes | - |
| `namespace` | `Option<String>` | No | - |
| `args` | `Option<Value>` | No | - |
| `filters` | `Option<Value>` | No | - |
| `capture` | Option\<Vec\<[`Capture`](#capture)>> | No | - |
| `on` | Option\<[`On`](#on)> | No | - |
| `deliver` | Option\<[`Deliver`](#deliver)> | No | - |

***

#### ObserveTarget

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

| Name | Type | Required | Description |
| - | - | - | - |
| `function_id` | `String` | Yes | - |
| `namespace` | `Option<String>` | No | - |

***

#### On

Which outcomes of an auto function's invocation activate an observer.

| Name | Type | Required | Description |
| - | - | - | - |
| `Success` | `unit` | Yes | - |
| `Error` | `unit` | Yes | - |
| `Complete` | `unit` | Yes | - |
| `Unknown` | `(String)` | Yes | A value this SDK does not know, kept verbatim. |
| `as_str` | `fn() -> &str` | Yes | The wire spelling. |

***

#### ParentCaller

`Caller::parent`: a caller without a parent of its own.

| Name | Type | Required | Description |
| - | - | - | - |
| `worker_id` | `Option<String>` | No | - |
| `worker_name` | `Option<String>` | No | - |
| `function_id` | `Option<String>` | No | - |
| `invocation_id` | `Option<String>` | No | - |

***

#### RegisterFunctionMessage

| Name | Type | Required | Description |
| - | - | - | - |
| `id` | `String` | Yes | - |
| `description` | `Option<String>` | No | - |
| `request_format` | `Option<Value>` | No | - |
| `response_format` | `Option<Value>` | No | - |
| `metadata` | `Option<Value>` | No | - |
| `invocation` | `Option<iii_helpers::http::HttpInvocationConfig>` | No | - |
| `observe` | Option\<[`ObserveDescriptor`](#observedescriptor)> | No | The wire half of the function's observe hooks; see `RegisterFunction::observe`. |
| `to_message` | fn() -> [`Message`](#message) | Yes | - |

***

#### RegisterTriggerInput

Input for `IIIClient::register_trigger`.
The `id` is auto-generated internally.

**Deprecated since 0.25.0** with `register_trigger`: use
`IIIClient::observe` with a
`Source` instead. Migration guide:
[https://iii.dev/docs/upgrading/from-0-24-x](https://iii.dev/docs/upgrading/from-0-24-x.md).

Build it with `RegisterTriggerInput::new`, or with
`IIITrigger` for a type the engine
provides. A struct literal has to name every field, so each field added here
breaks it: `namespace` did that once and `trigger_namespace` did it again,
which is why the constructors exist.

The two are different questions. `namespace` is where the target function
resolves; `trigger_namespace` is where the trigger type's provider is found,
and `None` there asks the engine to take this worker's namespace first and
the engine's own second.

| Name | Type | Required | Description |
| - | - | - | - |
| `trigger_type` | `String` | Yes | Identifier of the registered trigger type this trigger uses (e.g. `storage::object-created`, `http`). |
| `function_id` | `String` | Yes | ID of the function this trigger invokes when it fires. |
| `config` | `Value` | Yes | Trigger-type-specific configuration, matching the shape the trigger type expects. |
| `metadata` | `Option<Value>` | No | Arbitrary user-specifiable metadata supplied to the triggered handler function on every invocation. |
| `namespace` | `Option<String>` | No | Namespace the trigger's target function resolves in. `None` inherits this worker's namespace; name another namespace, including `default`, to bind the trigger elsewhere. |
| `trigger_namespace` | `Option<String>` | No | Namespace to find the trigger type's provider in. `None` asks the engine to resolve it: this worker's namespace first, the engine's own second. Naming one is strict. |

***

#### RegisterTriggerMessage

| Name | Type | Required | Description |
| - | - | - | - |
| `id` | `String` | Yes | - |
| `trigger_type` | `String` | Yes | - |
| `function_id` | `String` | Yes | - |
| `config` | `Value` | Yes | - |
| `metadata` | `Option<Value>` | No | - |
| `namespace` | `Option<String>` | No | - |
| `trigger_namespace` | `Option<String>` | No | - |
| `to_message` | fn() -> [`Message`](#message) | Yes | - |

***

#### RegisterTriggerTypeMessage

| Name | Type | Required | Description |
| - | - | - | - |
| `id` | `String` | Yes | Unique identifier for the trigger type (e.g. `state`, `durable:subscriber`). |
| `description` | `String` | Yes | Human-readable description of what this trigger type does. |
| `trigger_request_format` | `Option<Value>` | No | - |
| `call_request_format` | `Option<Value>` | No | - |
| `namespace` | `Option<String>` | No | Namespace this provider serves. `None` lets the engine use the connection's own, which is what a worker providing a trigger type for its own project wants. |
| `to_message` | fn() -> [`Message`](#message) | Yes | - |

***

#### TriggerAction

Routing action for `TriggerRequest`. Determines how the engine handles
the invocation.

* `Enqueue`: Routes through a named queue for async processing.
* `Void`: Fire-and-forget, no response.

| Name | Type | Required | Description |
| - | - | - | - |
| `Enqueue` | `{ queue: String }` | Yes | Routes the invocation through a named queue. |
| `Void` | `unit` | Yes | Fire-and-forget routing. |

***

#### TriggerRequest

Request object for `trigger()`.

```rust theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
// Simple call
TriggerRequest {
    function_id: "my::function".to_string(),
    payload: json!({ "key": "value" }),
    action: None,
    timeout_ms: None,
};

// With action
TriggerRequest {
    function_id: "my::function".to_string(),
    payload: json!({}),
    action: Some(TriggerAction::Enqueue { queue: "payments".to_string() }),
    timeout_ms: None,
};

// With metadata
TriggerRequest {
    function_id: "my::function".to_string(),
    payload: json!({}),
    action: None,
    timeout_ms: None,
}
.metadata(json!({ "tenant": "acme" }));
```

| Name | Type | Required | Description |
| - | - | - | - |
| `function_id` | `String` | Yes | ID of the function to invoke. |
| `payload` | `Value` | Yes | Input data passed to the function. |
| `action` | Option\<[`TriggerAction`](#triggeraction)> | No | Sets how the trigger is routed. `None` for a synchronous request/response. Set a routing scheme otherwise (e.g. `TriggerAction::Enqueue { .. }`, `TriggerAction::Void`). |
| `timeout_ms` | `Option<u64>` | No | Override the default invocation timeout, in milliseconds. |
| `dispatch` | fn(dispatch: [`Dispatch`](#dispatch)) -> [`TriggerRequestWithMetadata`](#triggerrequestwithmetadata) | Yes | Choose the path this call takes: `Dispatch::Auto` (the default) runs a function this worker hosts in-process when the engine allows it; `Dispatch::Remote` always goes through the engine. |
| `metadata` | fn(metadata: Value) -> [`TriggerRequestWithMetadata`](#triggerrequestwithmetadata) | Yes | Attach per-invocation metadata without adding a required field to `TriggerRequest` struct literals. |
| `namespace` | fn(namespace: impl Into\<String>) -> [`TriggerRequestWithMetadata`](#triggerrequestwithmetadata) | Yes | Target a specific namespace for this invocation without adding a required field to `TriggerRequest` struct literals. Serializes into `Message::InvokeFunction`'s `namespace`. |

***

#### TriggerRequestWithMetadata

Trigger request plus optional per-invocation metadata, target namespace
and dispatch.

| Name | Type | Required | Description |
| - | - | - | - |
| `dispatch` | fn(dispatch: [`Dispatch`](#dispatch)) -> Self | Yes | Choose the path this call takes; see `Dispatch`. |
| `metadata` | `fn(metadata: Value) -> Self` | Yes | Attach per-invocation metadata. |
| `namespace` | `fn(namespace: impl Into<String>) -> Self` | Yes | Target a specific namespace for this invocation. |

***

#### UnregisterTriggerMessage

| Name | Type | Required | Description |
| - | - | - | - |
| `id` | `String` | Yes | - |
| `trigger_type` | `String` | Yes | - |
| `to_message` | fn() -> [`Message`](#message) | Yes | - |

***

#### UnregisterTriggerTypeMessage

| Name | Type | Required | Description |
| - | - | - | - |
| `id` | `String` | Yes | - |
| `to_message` | fn() -> [`Message`](#message) | Yes | - |

### iii\_sdk::runtime

[`FunctionInfo`](#functioninfo) · [`FunctionRef`](#functionref) · [`IIIConnectionState`](#iiiconnectionstate) · [`TriggerInfo`](#triggerinfo) · [`TriggerTypeRef`](#triggertyperef) · [`WorkerIdentityMode`](#workeridentitymode) · [`WorkerInfo`](#workerinfo) · [`WorkerMetadata`](#workermetadata)

#### FunctionInfo

Function information returned by `engine::functions::list`

| Name | Type | Required | Description |
| - | - | - | - |
| `function_id` | `String` | Yes | - |
| `description` | `Option<String>` | No | - |
| `request_format` | `Option<Value>` | No | - |
| `response_format` | `Option<Value>` | No | - |
| `metadata` | `Option<Value>` | No | - |
| `namespace` | `Option<String>` | No | - |

***

#### FunctionRef

| Name | Type | Required | Description |
| - | - | - | - |
| `id` | `String` | Yes | - |
| `is_observed` | `fn() -> bool` | Yes | Whether any observer is active on this function, in one atomic load and without allocating. Check it before building an event nobody would receive. |
| `local_dispatch_active` | `fn() -> bool` | Yes | Whether calls to this function from this worker currently run in-process (the engine confirmed it with `local_dispatch: true`). |
| `observers` | fn() -> Vec\<[`Observer`](#observer)> | Yes | The active observers, as the owner sees them. |
| `unregister` | `fn()` | Yes | - |

***

#### IIIConnectionState

Connection state for the III WebSocket client

| Name | Type | Required | Description |
| - | - | - | - |
| `Disconnected` | `unit` | Yes | - |
| `Connecting` | `unit` | Yes | - |
| `Connected` | `unit` | Yes | - |
| `Reconnecting` | `unit` | Yes | - |
| `Failed` | `unit` | Yes | - |

***

#### TriggerInfo

Trigger information returned by `engine::triggers::list`

| Name | Type | Required | Description |
| - | - | - | - |
| `id` | `String` | Yes | - |
| `trigger_type` | `String` | Yes | - |
| `function_id` | `String` | Yes | - |
| `config` | `Value` | Yes | - |
| `metadata` | `Option<Value>` | No | - |
| `namespace` | `Option<String>` | No | - |

***

#### TriggerTypeRef

Typed handle returned by `IIIClient::register_trigger_type`.

**Deprecated since 0.25.0** with it; see
[https://iii.dev/docs/upgrading/from-0-24-x](https://iii.dev/docs/upgrading/from-0-24-x.md).

Type parameters:

* `C`: trigger registration type for `register_trigger`
* `R`: call request type for `register_function`

| Name | Type | Required | Description |
| - | - | - | - |
| `register_function` | fn(id: impl Into\<String>, f: F) -> [`FunctionRef`](#functionref) | Yes | **Deprecated since 0.25.0.** Use iii.register\_function(id, RegisterFunction::new(f)) instead; see [https://iii.dev/docs/upgrading/from-0-24-x](https://iii.dev/docs/upgrading/from-0-24-x.md). Register a sync function whose input type must match the call request format `R`. |
| `register_function_async` | fn(id: impl Into\<String>, f: F) -> [`FunctionRef`](#functionref) | Yes | **Deprecated since 0.25.0.** Use iii.register\_function(id, RegisterFunction::new\_async(f)) instead; see [https://iii.dev/docs/upgrading/from-0-24-x](https://iii.dev/docs/upgrading/from-0-24-x.md). Register an async function whose input type must match the call request format `R`. |
| `register_trigger` | fn(function\_id: impl Into\<String>, config: C) -> Result\<[`Trigger`](#trigger), [`Error`](#error)> | Yes | **Deprecated since 0.25.0.** Use iii.observe(Source::function(..).args(..), target) instead; see [https://iii.dev/docs/upgrading/from-0-24-x](https://iii.dev/docs/upgrading/from-0-24-x.md). Register a trigger with compile-time validated trigger config. |
| `register_trigger_with_metadata` | fn(function\_id: impl Into\<String>, config: C, metadata: Option\<Value>) -> Result\<[`Trigger`](#trigger), [`Error`](#error)> | Yes | **Deprecated since 0.25.0.** Use iii.observe\_with(Source::function(..).args(..), target, ObserverOptions::default().metadata(..)) instead; see [https://iii.dev/docs/upgrading/from-0-24-x](https://iii.dev/docs/upgrading/from-0-24-x.md). Register a trigger with compile-time validated trigger config and optional metadata. |

***

#### WorkerIdentityMode

Selects where a worker connection gets its engine identity.

| Name | Type | Required | Description |
| - | - | - | - |
| `Managed` | `unit` | Yes | Use the supervisor-managed `III_WORKER_NAME` and `III_NAMESPACE` values when present. This is the default for normal worker connections. |
| `Explicit` | `unit` | Yes | Keep the name from `WorkerMetadata` and the namespace from explicit options or metadata. Process-wide identity environment variables are ignored. Use this for auxiliary connections created by one worker. |

***

#### WorkerInfo

Worker information returned by `engine::workers::list`

| Name | Type | Required | Description |
| - | - | - | - |
| `id` | `String` | Yes | - |
| `name` | `Option<String>` | No | - |
| `runtime` | `Option<String>` | No | - |
| `version` | `Option<String>` | No | - |
| `os` | `Option<String>` | No | - |
| `ip_address` | `Option<String>` | No | - |
| `status` | `String` | Yes | - |
| `connected_at_ms` | `u64` | Yes | - |
| `function_count` | `usize` | Yes | - |
| `functions` | `Vec<String>` | Yes | - |
| `active_invocations` | `usize` | Yes | - |
| `isolation` | `Option<String>` | No | - |
| `namespace` | `Option<String>` | No | - |

***

#### WorkerMetadata

Worker metadata for auto-registration

| Name | Type | Required | Description |
| - | - | - | - |
| `runtime` | `String` | Yes | - |
| `version` | `String` | Yes | - |
| `name` | `String` | Yes | Worker name reported to the engine. In managed identity mode, a non-empty `III_WORKER_NAME` overrides this value when the client is created. |
| `os` | `String` | Yes | - |
| `description` | `Option<String>` | No | One-line, human/LLM-readable summary of what this worker does. Surfaces in `engine::workers::list` / `engine::workers::info`. |
| `pid` | `Option<u32>` | No | - |
| `telemetry` | Option\<[`TelemetryOptions`](#telemetryoptions)> | No | - |
| `isolation` | `Option<String>` | No | - |
| `namespace` | `Option<String>` | No | Namespace this worker belongs to, and therefore the one its calls and its trigger bindings resolve in unless they name another. Absent means the engine applies its default namespace. Managed clients also use `III_NAMESPACE` when no explicit namespace is present. |

### iii\_sdk::stream\_provider

[`IStream`](#istream)

#### IStream

Custom stream-provider trait. Implementors override the engine's built-in
stream storage for a specific stream name when registered through
`create_stream` in the `helpers` submodule.

| Name | Type | Required | Description |
| - | - | - | - |
| `get` | `fn(input: StreamGetInput) -> Pin<Box<dyn Future + Send>>` | Yes | - |
| `set` | `fn(input: StreamSetInput) -> Pin<Box<dyn Future + Send>>` | Yes | - |
| `delete` | `fn(input: StreamDeleteInput) -> Pin<Box<dyn Future + Send>>` | Yes | - |
| `list` | `fn(input: StreamListInput) -> Pin<Box<dyn Future + Send>>` | Yes | - |
| `list_groups` | `fn(input: StreamListGroupsInput) -> Pin<Box<dyn Future + Send>>` | Yes | - |
| `update` | `fn(input: StreamUpdateInput) -> Pin<Box<dyn Future + Send>>` | Yes | - |

### iii\_sdk::structs

[`MiddlewareFunctionInput`](#middlewarefunctioninput)

#### 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 |
| - | - | - | - |
| `function_id` | `String` | Yes | ID of the function being invoked. |
| `payload` | `Value` | Yes | Payload sent by the caller. |
| `action` | Option\<[`TriggerAction`](#triggeraction)> | No | Routing action, if any. |
| `context` | `Value` | Yes | Auth context returned by the auth function for this session. |
| `namespace` | `Option<String>` | No | Target namespace the invoke addressed; forward the call here to stay in the caller's namespace. Absent → the engine's default namespace. |

### iii\_sdk::trigger

[`IIITrigger`](#iiitrigger) · [`Trigger`](#trigger) · [`TriggerConfig`](#triggerconfig) · [`TriggerHandler`](#triggerhandler)

#### IIITrigger

Enum of all built-in trigger types with typed configuration.

**Deprecated since 0.25.0** with `IIIClient::register_trigger`;
see the module docs.

Use `.for_function()` to create a `RegisterTriggerInput`:

```rust,no_run theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
let input = IIITrigger::Cron(CronTriggerConfig::new("0 * * * * *"))
    .for_function("my::handler");
```

| Name | Type | Required | Description |
| - | - | - | - |
| `Http` | ([`HttpTriggerConfig`](#httptriggerconfig)) | Yes | - |
| `Cron` | ([`CronTriggerConfig`](#crontriggerconfig)) | Yes | - |
| `Queue` | ([`QueueTriggerConfig`](#queuetriggerconfig)) | Yes | - |
| `Subscribe` | ([`SubscribeTriggerConfig`](#subscribetriggerconfig)) | Yes | - |
| `State` | ([`StateTriggerConfig`](#statetriggerconfig)) | Yes | - |
| `Stream` | `(iii_helpers::stream::StreamTriggerConfig)` | Yes | - |
| `StreamJoin` | `(iii_helpers::stream::StreamJoinLeaveTriggerConfig)` | Yes | - |
| `StreamLeave` | `(iii_helpers::stream::StreamJoinLeaveTriggerConfig)` | Yes | - |
| `Log` | ([`LogTriggerConfig`](#logtriggerconfig)) | Yes | - |
| `for_function` | fn(function\_id: impl Into\<String>) -> [`RegisterTriggerInput`](#registertriggerinput) | Yes | Create a `RegisterTriggerInput` binding this trigger to a function. |

***

#### Trigger

Handle returned by `IIIClient::register_trigger`.
Call `unregister` to remove the trigger from the engine.

| Name | Type | Required | Description |
| - | - | - | - |
| `new` | `fn(unregister_fn: Arc<dyn Fn() + Send + Sync>) -> Self` | Yes | - |
| `unregister` | `fn()` | Yes | Remove this trigger from the engine. |

***

#### TriggerConfig

Configuration passed to a `TriggerHandler` when a trigger instance is
registered or unregistered.

| Name | Type | Required | Description |
| - | - | - | - |
| `id` | `String` | Yes | Trigger instance ID. |
| `function_id` | `String` | Yes | Function to invoke when the trigger fires. |
| `config` | `Value` | Yes | Trigger-specific configuration. |
| `metadata` | `Option<Value>` | No | Arbitrary user-specifiable metadata supplied to the triggered handler function on every invocation. |
| `namespace` | `Option<String>` | No | Resolved namespace the trigger's target `function_id` uses. Current SDKs fill an omitted registration value from the registering worker's namespace. A provider that stores this config and later calls `trigger()` must pass it through; `None` is the legacy/default case. |

***

#### TriggerHandler

Handler trait for custom trigger types. Implement this and pass to
`IIIClient::register_trigger_type`.

**Deprecated since 0.25.0** with `register_trigger_type`: implement
`ObserveHandler` on an observable function
instead (`on_observer_added` / `on_observer_removed`, with the observer's
args in place of the trigger config). Migration guide:
[https://iii.dev/docs/upgrading/from-0-24-x](https://iii.dev/docs/upgrading/from-0-24-x.md).

| Name | Type | Required | Description |
| - | - | - | - |
| `register_trigger` | fn(config: [`TriggerConfig`](#triggerconfig)) -> Pin\<Box\<dyn Future + Send>> | Yes | Called when a trigger instance is registered. |
| `unregister_trigger` | fn(config: [`TriggerConfig`](#triggerconfig)) -> Pin\<Box\<dyn Future + Send>> | Yes | Called when a trigger instance is unregistered. |

### iii\_sdk::types

[`RemoteFunctionData`](#remotefunctiondata) · [`RemoteFunctionHandler`](#remotefunctionhandler) · [`RemoteTriggerTypeData`](#remotetriggertypedata) · [`StreamRequest`](#streamrequest) · [`StreamResponse`](#streamresponse)

#### RemoteFunctionData

| Name | Type | Required | Description |
| - | - | - | - |
| `message` | [`RegisterFunctionMessage`](#registerfunctionmessage) | Yes | - |
| `handler` | `Option<RemoteFunctionHandlerWithMetadata>` | No | - |

***

#### RemoteFunctionHandler

A dispatchable function handler. Receives the invocation payload.

Handlers that also want the optional per-invocation `metadata` sidecar use
`RemoteFunctionHandlerWithMetadata`; this single-argument shape is kept
for backward compatibility.

```rust theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
type RemoteFunctionHandler = Arc<dyn Fn(Value) -> futures_util::future::BoxFuture<'static, Result<Value, Error>> + Send + Sync>
```

***

#### RemoteTriggerTypeData

| Name | Type | Required | Description |
| - | - | - | - |
| `message` | [`RegisterTriggerTypeMessage`](#registertriggertypemessage) | Yes | - |
| `handler` | Arc\<dyn [`TriggerHandler`](#triggerhandler)> | Yes | - |

***

#### StreamRequest

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

Alias of `iii_helpers::http::HttpRequest`.

```rust theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
type StreamRequest = iii_helpers::http::HttpRequest<T>
```

***

#### StreamResponse

Streaming response type, mirroring the Node and Python `StreamResponse`.

Alias of `iii_helpers::http::HttpResponse`; added for cross-language parity.

```rust theme={"theme":{"light":"catppuccin-latte","dark":"dark-plus"}}
type StreamResponse = iii_helpers::http::HttpResponse<T>
```


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