Skip to content
Open
130 changes: 52 additions & 78 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,79 +1,57 @@
# III SDK
# iii SDK

Multi-language SDK for the III Engine - a WebSocket-based function orchestration platform.
Official SDKs for the [iii engine](https://github.com/iii-hq/iii).

## Overview
[![npm](https://img.shields.io/npm/v/iii-sdk)](https://www.npmjs.com/package/iii-sdk)
[![PyPI](https://img.shields.io/pypi/v/iii-sdk)](https://pypi.org/project/iii-sdk/)
[![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](LICENSE)

The III SDK provides a unified interface for building distributed applications with function registration, invocation, and trigger management. It enables seamless communication between services through a WebSocket-based engine.
## Packages

## Supported Languages

- **Node.js** - TypeScript/JavaScript SDK with full async support
- **Python** - Async Python SDK with function registration
- **Rust** - High-performance async Rust SDK with automatic reconnection

## Features

- **Function Registration** - Register callable functions that can be invoked by other services
- **Function Invocation** - Call functions synchronously or asynchronously (fire-and-forget)
- **Trigger Management** - Create and manage triggers (API, events, schedules, etc.)
- **Custom Trigger Types** - Define your own trigger types with custom logic
- **Context-Aware Logging** - Built-in logging with execution context
- **OpenTelemetry Integration** - Full observability with traces, metrics, and logs (Node.js)
- **Automatic Reconnection** - Resilient WebSocket connections with auto-reconnect (Rust)
| Package | Language | Install | Docs |
|---------|----------|---------|------|
| [`iii-sdk`](https://www.npmjs.com/package/iii-sdk) | Node.js / TypeScript | `npm install iii-sdk` | [README](./packages/node/iii/README.md) |
| [`iii-sdk`](https://pypi.org/project/iii-sdk/) | Python | `pip install iii-sdk` | [README](./packages/python/iii/README.md) |
| [`iii-sdk`](https://crates.io/crates/iii-sdk) | Rust | Add to `Cargo.toml` | [README](./packages/rust/iii/README.md) |

## Quick Start

### Node.js

```bash
npm install iii-sdk
```

```javascript
import { III } from 'iii-sdk'

const iii = new III('ws://localhost:49134')
import { init } from 'iii-sdk'

iii.registerFunction({ id: 'myFunction' }, (req) => {
return { status_code: 200, body: { message: 'Hello, world!' } }
})
const iii = init('ws://localhost:49134')

iii.registerTrigger({
type: 'http',
function_id: 'myFunction',
config: { api_path: '/hello', http_method: 'POST' },
iii.registerFunction({ id: 'greet' }, async (input) => {
return { message: `Hello, ${input.name}!` }
})

const result = await iii.call('myFunction', { param: 'value' })
const result = await iii.trigger('greet', { name: 'world' })
```

### Python

```bash
pip install iii-sdk
```

```python
import asyncio
from iii import III

iii = III("ws://localhost:49134")

async def my_function(data):
return {"result": "success"}
async def greet(data):
return {"message": f"Hello, {data['name']}!"}

iii.register_function("my.function", my_function)
iii.register_function("greet", greet)

result = await iii.call("other.function", {"param": "value"})
async def main():
await iii.connect()
result = await iii.trigger("greet", {"name": "world"})

asyncio.run(main())
```

### Rust

```toml
[dependencies]
iii-sdk = { path = "path/to/iii" }
```

```rust
use iii_sdk::III;
use serde_json::json;
Expand All @@ -83,43 +61,40 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
let iii = III::new("ws://127.0.0.1:49134");
iii.connect().await?;

iii.register_function("my.function", |input| async move {
Ok(json!({ "message": "Hello, world!", "input": input }))
iii.register_function("greet", |input| async move {
let name = input.get("name").and_then(|v| v.as_str()).unwrap_or("world");
Ok(json!({ "message": format!("Hello, {name}!") }))
});

let result: serde_json::Value = iii
.call("my.function", json!({ "param": "value" }))
.trigger("greet", json!({ "name": "world" }))
.await?;

println!("result: {result}");
Ok(())
}
```

## Documentation
## API Surface

Detailed documentation for each SDK:
| Operation | Node.js | Python | Rust |
|-----------|---------|--------|------|
| Initialize | `init(url)` | `III(url)` | `III::new(url)` |
| Connect | Auto on `init()` | `await iii.connect()` | `iii.connect().await?` |
| Register function | `iii.registerFunction({ id }, handler)` | `iii.register_function(id, handler)` | `iii.register_function(id, \|input\| ...)` |
| Register trigger | `iii.registerTrigger({ type, function_id, config })` | `iii.register_trigger(type, fn_id, config)` | `iii.register_trigger(type, fn_id, config)?` |
| Invoke (sync) | `await iii.trigger(id, data)` | `await iii.trigger(id, data)` | `iii.trigger(id, data).await?` |
| Invoke (fire-and-forget) | `iii.triggerVoid(id, data)` | `iii.trigger_void(id, data)` | `iii.trigger_void(id, data)?` |

- [Node.js SDK](./packages/node/iii/README.md)
- [Python SDK](./packages/python/iii/README.md)
- [Rust SDK](./packages/rust/iii/README.md)

## Examples

Example applications demonstrating SDK usage:

- [Node.js Example](./packages/node/iii-example/)
- [Python Example](./packages/python/iii-example/)
- [Rust Example](./packages/rust/iii-example/)
> `call()` and `callVoid()` / `call_void()` exist as deprecated aliases. Use `trigger()` and `triggerVoid()` / `trigger_void()`.

## Development

### Prerequisites

- Node.js 20+ and pnpm (for Node.js SDK)
- Python 3.8+ and uv (for Python SDK)
- Rust 1.70+ and Cargo (for Rust SDK)
- III Engine running on `ws://localhost:49134`
- Python 3.10+ and uv (for Python SDK)
- Rust 1.85+ and Cargo (for Rust SDK)
- iii engine running on `ws://localhost:49134`

### Building

Expand All @@ -137,19 +112,18 @@ cd packages/python/iii && pytest
cd packages/rust/iii && cargo test
```

## Architecture

The III SDK communicates with the III Engine via WebSocket connections. The engine acts as a central orchestrator for:
## Examples

- Function registry and routing
- Trigger management and execution
- Inter-service communication
- Telemetry and observability
- [Node.js Example](./packages/node/iii-example/)
- [Python Example](./packages/python/iii-example/)
- [Rust Example](./packages/rust/iii-example/)

## License
## Resources

Apache License 2.0 - see [LICENSE](./LICENSE) for details.
- [Documentation](https://iii.dev/docs)
- [iii Engine](https://github.com/iii-hq/iii)
- [Examples](https://github.com/iii-hq/iii-examples)

## Author
## License

Motia LLC
Apache 2.0
108 changes: 54 additions & 54 deletions packages/node/iii/README.md
Original file line number Diff line number Diff line change
@@ -1,100 +1,100 @@
# III SDK for Node.js
# iii-sdk

## Installation
Node.js / TypeScript SDK for the [iii engine](https://github.com/iii-hq/iii).

[![npm](https://img.shields.io/npm/v/iii-sdk)](https://www.npmjs.com/package/iii-sdk)
[![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](../../../LICENSE)

## Install

```bash
npm install iii-sdk
```

## Usage
## Quick Start

```javascript
import { III } from 'iii-sdk'
import { init } from 'iii-sdk'

/**
* Make sure the III Core Instance is up and Running on the given URL.
*/
const iii = new III(process.env.III_BRIDGE_URL ?? 'ws://localhost:49134')
const iii = init('ws://localhost:49134')

iii.registerFunction({ id: 'myFunction' }, (req) => {
return { status_code: 200, body: { message: 'Hello, world!' } }
iii.registerFunction({ id: 'greet' }, async (input) => {
return { message: `Hello, ${input.name}!` }
})

iii.registerTrigger({
type: 'http',
function_id: 'myFunction',
config: { api_path: 'myApiPath', http_method: 'POST' },
function_id: 'greet',
config: { api_path: 'greet', http_method: 'POST' },
})

const result = await iii.trigger('greet', { name: 'world' })
```

### Registering Functions
## API

III Allows you to register functions that can be invoked by other services.
| Method | Description |
|--------|-------------|
| `init(url, options?)` | Create and connect to the engine. Returns an `ISdk` instance |
| `iii.registerFunction({ id }, handler)` | Register a function that can be invoked by name |
| `iii.registerTrigger({ type, function_id, config })` | Bind a trigger (HTTP, cron, queue, etc.) to a function |
| `iii.registerTriggerType({ id, description }, handlers)` | Register a custom trigger type |
| `await iii.trigger(id, data, timeoutMs?)` | Invoke a function and wait for the result |
| `iii.triggerVoid(id, data)` | Invoke a function without waiting (fire-and-forget) |

### Registering Functions

```javascript
iii.registerFunction({ id: 'myFunction' }, (req) => {
// ... do something
return { status_code: 200, body: { message: 'Hello, world!' } }
iii.registerFunction({ id: 'orders.create' }, async (input) => {
return { status_code: 201, body: { id: '123', item: input.body.item } }
})
```

### Registering Triggers

III Allows you to register triggers that can be invoked by other services.

```javascript
iii.registerTrigger({
type: 'http',
function_id: 'myFunction',
config: { api_path: 'myApiPath', http_method: 'POST' },
function_id: 'orders.create',
config: { api_path: 'orders', http_method: 'POST' },
})
```

### Registering Trigger Types

Triggers are mostly created by III Core Modules, but you can also create your own triggers
### Custom Trigger Types

```javascript
iii.registerTrigger_type(
iii.registerTriggerType(
{ id: 'webhook', description: 'External webhook trigger' },
{
/**
* This is the id of the trigger type, it's unique.
* Then, you can register a trigger by calling the registerTrigger method.
*/
id: 'myTrigger_type',
description: 'My trigger type',
},
{
/**
* Trigger config has: id, function_id, and config.
* Your logic should know what to do with the config.
*/
registerTrigger: async (config) => {
// ... do something
},
unregisterTrigger: async (config) => {
// ... do something
},
registerTrigger: async (config) => { /* setup */ },
unregisterTrigger: async (config) => { /* teardown */ },
},
)
```

### Invoking Functions

III Allows you to invoke functions, they can be functions from the Core Modules or
functions registered by workers.

```javascript
const result = await iii.call('myFunction', { param1: 'value1' })
console.log(result)
const result = await iii.trigger('orders.create', { item: 'widget' })

iii.triggerVoid('analytics.track', { event: 'page_view' })
```

### Invoking Functions Async
## Subpath Exports

III Allows you to invoke functions asynchronously, they can be functions from the Core Modules or functions registered by workers.
| Import | What it provides |
|--------|-----------------|
| `iii-sdk` | Core SDK (`init`, types) |
| `iii-sdk/stream` | Stream client for real-time state |
| `iii-sdk/state` | State client for key-value operations |
| `iii-sdk/telemetry` | OpenTelemetry integration |

```javascript
iii.callVoid('myFunction', { param1: 'value1' })
```
## Deprecated

`call()` and `callVoid()` are deprecated aliases for `trigger()` and `triggerVoid()`. They still work but will be removed in a future release.

## Resources

This means the Engine won't hold the execution of the function, it will return immediately. Which means the function will be executed in the background.
- [Documentation](https://iii.dev/docs)
- [iii Engine](https://github.com/iii-hq/iii)
- [Examples](https://github.com/iii-hq/iii-examples)
Loading