From af20100fccd598068dc6e7d23907d263cd570d04 Mon Sep 17 00:00:00 2001 From: Rohit Ghumare Date: Thu, 26 Feb 2026 00:26:21 +0530 Subject: [PATCH 01/10] docs: overhaul all SDK READMEs with correct API patterns Root README: - Add API surface table across all three SDKs - Fix Node.js init from new III() to init() - Fix all examples from call() to trigger() - Add deprecation note for call/callVoid/call_void Node.js: - Fix init from new III() to init() - Fix invocations from call/callVoid to trigger/triggerVoid - Add API table, subpath exports table - Add deprecation section Python: - Fix invocations from call/call_void to trigger/trigger_void - Add connection note (explicit await iii.connect() required) - Add API table and deprecation section Rust: - Fix invocations from call() to trigger() - Add API table, streams example, OTel feature docs - Add notes about register_function behavior - Add deprecation section --- README.md | 123 +++++++++++++--------------------- packages/node/iii/README.md | 108 ++++++++++++++--------------- packages/python/iii/README.md | 66 ++++++++++++------ packages/rust/iii/README.md | 83 ++++++++++++++++++----- 4 files changed, 211 insertions(+), 169 deletions(-) diff --git a/README.md b/README.md index c3567fa..143fb07 100644 --- a/README.md +++ b/README.md @@ -1,79 +1,54 @@ -# 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 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"}) ``` ### Rust -```toml -[dependencies] -iii-sdk = { path = "path/to/iii" } -``` - ```rust use iii_sdk::III; use serde_json::json; @@ -83,34 +58,31 @@ async fn main() -> Result<(), Box> { 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 @@ -119,7 +91,7 @@ Example applications demonstrating SDK usage: - 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` +- iii engine running on `ws://localhost:49134` ### Building @@ -137,19 +109,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 diff --git a/packages/node/iii/README.md b/packages/node/iii/README.md index 4d2c7a6..935a79b 100644 --- a/packages/node/iii/README.md +++ b/packages/node/iii/README.md @@ -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) diff --git a/packages/python/iii/README.md b/packages/python/iii/README.md index 9e0955d..36f9cc3 100644 --- a/packages/python/iii/README.md +++ b/packages/python/iii/README.md @@ -1,43 +1,67 @@ -# III SDK for Python +# iii-sdk -Python SDK for the III Engine. +Python SDK for the [iii engine](https://github.com/iii-hq/iii). -## Installation +[![PyPI](https://img.shields.io/pypi/v/iii-sdk)](https://pypi.org/project/iii-sdk/) +[![Python](https://img.shields.io/pypi/pyversions/iii-sdk)](https://pypi.org/project/iii-sdk/) +[![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](../../../LICENSE) + +## Install ```bash pip install iii-sdk ``` -## Usage +## Quick Start ```python import asyncio from iii import III -async def my_function(data): - return {"result": "success"} - iii = III("ws://localhost:49134") -iii.register_function("my.function", my_function) + +async def greet(data): + return {"message": f"Hello, {data['name']}!"} + +iii.register_function("greet", greet) async def main(): await iii.connect() - result = await iii.call("other.function", {"param": "value"}) - print(result) + iii.register_trigger( + type="http", + function_id="greet", + config={"api_path": "greet", "http_method": "POST"} + ) + + result = await iii.trigger("greet", {"name": "world"}) asyncio.run(main()) ``` -### Register API trigger +## API + +| Method | Description | +|--------|-------------| +| `III(url)` | Create an SDK instance | +| `await iii.connect()` | Connect to the engine (sets up WebSocket + OTel) | +| `iii.register_function(id, handler)` | Register a callable function | +| `iii.register_trigger(type, function_id, config)` | Bind a trigger to a function | +| `await iii.trigger(id, data)` | Invoke a function and wait for the result | +| `iii.trigger_void(id, data)` | Invoke a function without waiting (fire-and-forget) | + +### Connection + +Python requires an explicit `await iii.connect()` call (no async constructors in Python). This sets up both the WebSocket connection and OpenTelemetry instrumentation. + +### HTTP Trigger Example ```python -import asyncio from iii import III, ApiRequest, ApiResponse iii = III("ws://localhost:49134") -async def create_todo(data): +async def create_todo(data): req = ApiRequest(**data) return ApiResponse(status=201, data={"id": "123", "title": req.body.get("title")}) @@ -55,14 +79,14 @@ async def main(): "description": "Create a new todo" } ) - -asyncio.run(main()) ``` -## Features +## Deprecated + +`call()` and `call_void()` are deprecated aliases for `trigger()` and `trigger_void()`. They still work but will be removed in a future release. + +## Resources -- WebSocket-based communication with III Engine -- Function registration and invocation -- Trigger registration -- Context-aware logging -- Async/await support +- [Documentation](https://iii.dev/docs) +- [iii Engine](https://github.com/iii-hq/iii) +- [Examples](https://github.com/iii-hq/iii-examples) diff --git a/packages/rust/iii/README.md b/packages/rust/iii/README.md index 6b59c95..ac404ba 100644 --- a/packages/rust/iii/README.md +++ b/packages/rust/iii/README.md @@ -1,17 +1,23 @@ -# III SDK for Rust +# iii-sdk -Rust SDK for the III Engine. +Rust SDK for the [iii engine](https://github.com/iii-hq/iii). -## Installation +[![crates.io](https://img.shields.io/crates/v/iii-sdk)](https://crates.io/crates/iii-sdk) +[![docs.rs](https://img.shields.io/docsrs/iii-sdk)](https://docs.rs/iii-sdk) +[![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](../../../LICENSE) -Add the crate to your `Cargo.toml`: +## Install + +Add to your `Cargo.toml`: ```toml [dependencies] -iii-sdk = { path = "../path/to/iii" } +iii-sdk = "0.3" +serde_json = "1" +tokio = { version = "1", features = ["full"] } ``` -## Usage +## Quick Start ```rust use iii_sdk::III; @@ -22,12 +28,18 @@ async fn main() -> Result<(), Box> { 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}!") })) }); + iii.register_trigger("http", "greet", json!({ + "api_path": "greet", + "http_method": "POST" + }))?; + let result: serde_json::Value = iii - .call("my.function", json!({ "param": "value" })) + .trigger("greet", json!({ "name": "world" })) .await?; println!("result: {result}"); @@ -35,16 +47,51 @@ async fn main() -> Result<(), Box> { } ``` -## Features +## API + +| Method | Description | +|--------|-------------| +| `III::new(url)` | Create an SDK instance | +| `iii.connect().await?` | Connect to the engine (sets up WebSocket + OTel) | +| `iii.register_function(id, \|input\| ...)` | Register a callable function | +| `iii.register_trigger(type, fn_id, config)?` | Bind a trigger to a function | +| `iii.trigger(id, data).await?` | Invoke a function and wait for the result | +| `iii.trigger_void(id, data)?` | Invoke a function without waiting (fire-and-forget) | + +### Connection + +Rust requires an explicit `iii.connect().await?` call. This starts a background task that handles WebSocket communication and automatic reconnection. It also sets up OpenTelemetry instrumentation. + +### Streams + +```rust +let stream = iii.stream(); + +stream.set("room.123", json!({ "users": ["alice", "bob"] })).await?; +let state = stream.get("room.123").await?; +``` -- WebSocket-based communication with III Engine -- Function registration and invocation -- Trigger registration and trigger type handling -- Context-aware logging (`get_context().logger`) -- Async/await support with automatic reconnection +### OpenTelemetry + +Enable the `otel` feature for full tracing and metrics support: + +```toml +[dependencies] +iii-sdk = { version = "0.3", features = ["otel"] } +``` ## Notes -- `III::connect` starts a background task and handles reconnection automatically. -- The engine protocol currently supports `registertriggertype` but does not include an - `unregistertriggertype` message; `unregister_trigger_type` only removes local handlers. +- `III::connect` starts a background task and handles reconnection automatically +- `register_function` does not return a handle (unlike the Node.js and Python SDKs) +- The engine protocol supports `registertriggertype` but does not include `unregistertriggertype`; `unregister_trigger_type` only removes local handlers + +## Deprecated + +`call()` is a deprecated alias for `trigger()`. It still works but will be removed in a future release. + +## Resources + +- [Documentation](https://iii.dev/docs) +- [iii Engine](https://github.com/iii-hq/iii) +- [Examples](https://github.com/iii-hq/iii-examples) From c95a805ed9a4206df2476de49fa047c7e58935c2 Mon Sep 17 00:00:00 2001 From: Rohit Ghumare Date: Fri, 27 Feb 2026 18:34:32 +0530 Subject: [PATCH 02/10] fix: correct Streams example in Rust README - iii.stream() doesn't exist, use Streams::new(iii.clone()) - Streams helper has set_field/update/increment, not set/get --- packages/rust/iii/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/rust/iii/README.md b/packages/rust/iii/README.md index ac404ba..4e740b1 100644 --- a/packages/rust/iii/README.md +++ b/packages/rust/iii/README.md @@ -65,10 +65,10 @@ Rust requires an explicit `iii.connect().await?` call. This starts a background ### Streams ```rust -let stream = iii.stream(); +use iii_sdk::Streams; -stream.set("room.123", json!({ "users": ["alice", "bob"] })).await?; -let state = stream.get("room.123").await?; +let streams = Streams::new(iii.clone()); +streams.set_field("room::123", "users", json!(["alice", "bob"])).await?; ``` ### OpenTelemetry From 274e36ef1ffe9a8e6b1cb76c1f2f6767fdc91200 Mon Sep 17 00:00:00 2001 From: Rohit Ghumare Date: Fri, 27 Feb 2026 18:56:25 +0530 Subject: [PATCH 03/10] fix: address review findings across READMEs - Python: add print(result), fix api_path consistency (remove leading slash) - Rust: use connect() instance method notation in Notes section - Root: add import asyncio and asyncio.run(main()) to Python snippet --- README.md | 3 +++ packages/python/iii/README.md | 3 ++- packages/rust/iii/README.md | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 143fb07..44e9429 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,7 @@ const result = await iii.trigger('greet', { name: 'world' }) ### Python ```python +import asyncio from iii import III iii = III("ws://localhost:49134") @@ -45,6 +46,8 @@ iii.register_function("greet", greet) async def main(): await iii.connect() result = await iii.trigger("greet", {"name": "world"}) + +asyncio.run(main()) ``` ### Rust diff --git a/packages/python/iii/README.md b/packages/python/iii/README.md index 36f9cc3..0ca542a 100644 --- a/packages/python/iii/README.md +++ b/packages/python/iii/README.md @@ -35,6 +35,7 @@ async def main(): ) result = await iii.trigger("greet", {"name": "world"}) + print(result) asyncio.run(main()) ``` @@ -74,7 +75,7 @@ async def main(): type="http", function_id="api.post.todo", config={ - "api_path": "/todo", + "api_path": "todo", "http_method": "POST", "description": "Create a new todo" } diff --git a/packages/rust/iii/README.md b/packages/rust/iii/README.md index 4e740b1..2bfbe0d 100644 --- a/packages/rust/iii/README.md +++ b/packages/rust/iii/README.md @@ -82,7 +82,7 @@ iii-sdk = { version = "0.3", features = ["otel"] } ## Notes -- `III::connect` starts a background task and handles reconnection automatically +- `connect()` starts a background task and handles reconnection automatically - `register_function` does not return a handle (unlike the Node.js and Python SDKs) - The engine protocol supports `registertriggertype` but does not include `unregistertriggertype`; `unregister_trigger_type` only removes local handlers From c9f24805573e12b6d8d07cfe97980c603c25f2fd Mon Sep 17 00:00:00 2001 From: Rohit Ghumare Date: Mon, 2 Mar 2026 12:59:44 +0530 Subject: [PATCH 04/10] docs: replace "callable" with "invoked by name" in Python and Rust API tables --- packages/python/iii/README.md | 2 +- packages/rust/iii/README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/python/iii/README.md b/packages/python/iii/README.md index 0ca542a..28ab322 100644 --- a/packages/python/iii/README.md +++ b/packages/python/iii/README.md @@ -46,7 +46,7 @@ asyncio.run(main()) |--------|-------------| | `III(url)` | Create an SDK instance | | `await iii.connect()` | Connect to the engine (sets up WebSocket + OTel) | -| `iii.register_function(id, handler)` | Register a callable function | +| `iii.register_function(id, handler)` | Register a function that can be invoked by name | | `iii.register_trigger(type, function_id, config)` | Bind a trigger to a function | | `await iii.trigger(id, data)` | Invoke a function and wait for the result | | `iii.trigger_void(id, data)` | Invoke a function without waiting (fire-and-forget) | diff --git a/packages/rust/iii/README.md b/packages/rust/iii/README.md index 2bfbe0d..96259cd 100644 --- a/packages/rust/iii/README.md +++ b/packages/rust/iii/README.md @@ -53,7 +53,7 @@ async fn main() -> Result<(), Box> { |--------|-------------| | `III::new(url)` | Create an SDK instance | | `iii.connect().await?` | Connect to the engine (sets up WebSocket + OTel) | -| `iii.register_function(id, \|input\| ...)` | Register a callable function | +| `iii.register_function(id, \|input\| ...)` | Register a function that can be invoked by name | | `iii.register_trigger(type, fn_id, config)?` | Bind a trigger to a function | | `iii.trigger(id, data).await?` | Invoke a function and wait for the result | | `iii.trigger_void(id, data)?` | Invoke a function without waiting (fire-and-forget) | From 032bd16017e2475b1942305bcb9c2f1e0e68b86d Mon Sep 17 00:00:00 2001 From: Rohit Ghumare Date: Mon, 2 Mar 2026 13:23:37 +0530 Subject: [PATCH 05/10] docs: align all SDK READMEs to identical structure - Python/Rust API tables now match Node.js (add register_trigger_type) - Fix Python version requirement 3.8+ to 3.10+ - Fix Rust MSRV 1.70+ to 1.85+ - Fix Python ApiResponse example (status/data to status_code/body) - Add Registering Functions/Triggers/Custom Trigger Types/Invoking sections to Python and Rust (matching Node.js) - Rust Deprecated section now includes call_void() --- README.md | 4 +-- packages/python/iii/README.md | 56 +++++++++++++++++++++++------------ packages/rust/iii/README.md | 44 ++++++++++++++++++++++----- 3 files changed, 75 insertions(+), 29 deletions(-) diff --git a/README.md b/README.md index 44e9429..3a0a53d 100644 --- a/README.md +++ b/README.md @@ -92,8 +92,8 @@ async fn main() -> Result<(), Box> { ### 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) +- Python 3.10+ and uv (for Python SDK) +- Rust 1.85+ and Cargo (for Rust SDK) - iii engine running on `ws://localhost:49134` ### Building diff --git a/packages/python/iii/README.md b/packages/python/iii/README.md index 28ab322..e432992 100644 --- a/packages/python/iii/README.md +++ b/packages/python/iii/README.md @@ -47,7 +47,8 @@ asyncio.run(main()) | `III(url)` | Create an SDK instance | | `await iii.connect()` | Connect to the engine (sets up WebSocket + OTel) | | `iii.register_function(id, handler)` | Register a function that can be invoked by name | -| `iii.register_trigger(type, function_id, config)` | Bind a trigger to a function | +| `iii.register_trigger(type, function_id, config)` | Bind a trigger (HTTP, cron, queue, etc.) to a function | +| `iii.register_trigger_type(id, description, handler)` | Register a custom trigger type | | `await iii.trigger(id, data)` | Invoke a function and wait for the result | | `iii.trigger_void(id, data)` | Invoke a function without waiting (fire-and-forget) | @@ -55,31 +56,48 @@ asyncio.run(main()) Python requires an explicit `await iii.connect()` call (no async constructors in Python). This sets up both the WebSocket connection and OpenTelemetry instrumentation. -### HTTP Trigger Example +### Registering Functions ```python -from iii import III, ApiRequest, ApiResponse - -iii = III("ws://localhost:49134") - async def create_todo(data): - req = ApiRequest(**data) - return ApiResponse(status=201, data={"id": "123", "title": req.body.get("title")}) + return {"status_code": 201, "body": {"id": "123", "title": data["body"]["title"]}} iii.register_function("api.post.todo", create_todo) +``` -async def main(): - await iii.connect() +### Registering Triggers - iii.register_trigger( - type="http", - function_id="api.post.todo", - config={ - "api_path": "todo", - "http_method": "POST", - "description": "Create a new todo" - } - ) +```python +iii.register_trigger( + type="http", + function_id="api.post.todo", + config={"api_path": "todo", "http_method": "POST"} +) +``` + +### Custom Trigger Types + +```python +from iii import III + +async def on_register(config): + pass # setup + +async def on_unregister(config): + pass # teardown + +iii.register_trigger_type("webhook", "External webhook trigger", { + "register_trigger": on_register, + "unregister_trigger": on_unregister, +}) +``` + +### Invoking Functions + +```python +result = await iii.trigger("api.post.todo", {"body": {"title": "Buy milk"}}) + +iii.trigger_void("analytics.track", {"event": "page_view"}) ``` ## Deprecated diff --git a/packages/rust/iii/README.md b/packages/rust/iii/README.md index 96259cd..657c275 100644 --- a/packages/rust/iii/README.md +++ b/packages/rust/iii/README.md @@ -54,7 +54,8 @@ async fn main() -> Result<(), Box> { | `III::new(url)` | Create an SDK instance | | `iii.connect().await?` | Connect to the engine (sets up WebSocket + OTel) | | `iii.register_function(id, \|input\| ...)` | Register a function that can be invoked by name | -| `iii.register_trigger(type, fn_id, config)?` | Bind a trigger to a function | +| `iii.register_trigger(type, fn_id, config)?` | Bind a trigger (HTTP, cron, queue, etc.) to a function | +| `iii.register_trigger_type(id, description, handler)` | Register a custom trigger type | | `iii.trigger(id, data).await?` | Invoke a function and wait for the result | | `iii.trigger_void(id, data)?` | Invoke a function without waiting (fire-and-forget) | @@ -62,6 +63,39 @@ async fn main() -> Result<(), Box> { Rust requires an explicit `iii.connect().await?` call. This starts a background task that handles WebSocket communication and automatic reconnection. It also sets up OpenTelemetry instrumentation. +### Registering Functions + +```rust +iii.register_function("math.add", |input| async move { + let a = input["a"].as_i64().unwrap_or(0); + let b = input["b"].as_i64().unwrap_or(0); + Ok(json!({ "sum": a + b })) +}); +``` + +### Registering Triggers + +```rust +iii.register_trigger("http", "math.add", json!({ + "api_path": "add", + "http_method": "POST" +}))?; +``` + +### Custom Trigger Types + +```rust +iii.register_trigger_type("webhook", "External webhook trigger", my_handler); +``` + +### Invoking Functions + +```rust +let result = iii.trigger("math.add", json!({ "a": 2, "b": 3 })).await?; + +iii.trigger_void("analytics.track", json!({ "event": "page_view" }))?; +``` + ### Streams ```rust @@ -80,15 +114,9 @@ Enable the `otel` feature for full tracing and metrics support: iii-sdk = { version = "0.3", features = ["otel"] } ``` -## Notes - -- `connect()` starts a background task and handles reconnection automatically -- `register_function` does not return a handle (unlike the Node.js and Python SDKs) -- The engine protocol supports `registertriggertype` but does not include `unregistertriggertype`; `unregister_trigger_type` only removes local handlers - ## Deprecated -`call()` is a deprecated alias for `trigger()`. It still works but will be removed in a future release. +`call()` and `call_void()` are deprecated aliases for `trigger()` and `trigger_void()`. They still work but will be removed in a future release. ## Resources From c071e8f1f3f06564bd013e590491d0793827b8fd Mon Sep 17 00:00:00 2001 From: Rohit Ghumare Date: Mon, 2 Mar 2026 13:25:45 +0530 Subject: [PATCH 06/10] docs: add connect() prerequisite notes to trigger and invoke examples --- packages/python/iii/README.md | 6 ++++-- packages/rust/iii/README.md | 4 ++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/python/iii/README.md b/packages/python/iii/README.md index e432992..3d06531 100644 --- a/packages/python/iii/README.md +++ b/packages/python/iii/README.md @@ -67,6 +67,8 @@ iii.register_function("api.post.todo", create_todo) ### Registering Triggers +Requires `await iii.connect()` first. + ```python iii.register_trigger( type="http", @@ -78,8 +80,6 @@ iii.register_trigger( ### Custom Trigger Types ```python -from iii import III - async def on_register(config): pass # setup @@ -94,6 +94,8 @@ iii.register_trigger_type("webhook", "External webhook trigger", { ### Invoking Functions +Requires `await iii.connect()` first. + ```python result = await iii.trigger("api.post.todo", {"body": {"title": "Buy milk"}}) diff --git a/packages/rust/iii/README.md b/packages/rust/iii/README.md index 657c275..1effa52 100644 --- a/packages/rust/iii/README.md +++ b/packages/rust/iii/README.md @@ -75,6 +75,8 @@ iii.register_function("math.add", |input| async move { ### Registering Triggers +Requires `iii.connect().await?` first. + ```rust iii.register_trigger("http", "math.add", json!({ "api_path": "add", @@ -90,6 +92,8 @@ iii.register_trigger_type("webhook", "External webhook trigger", my_handler); ### Invoking Functions +Requires `iii.connect().await?` first. + ```rust let result = iii.trigger("math.add", json!({ "a": 2, "b": 3 })).await?; From b7cb265e7c8d7fc3a97efd94f4f60a4a08cb9331 Mon Sep 17 00:00:00 2001 From: Rohit Ghumare Date: Mon, 2 Mar 2026 15:03:38 +0530 Subject: [PATCH 07/10] docs: add crates.io badge to root README --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 3a0a53d..1c378f1 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,7 @@ Official SDKs 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) [![PyPI](https://img.shields.io/pypi/v/iii-sdk)](https://pypi.org/project/iii-sdk/) +[![crates.io](https://img.shields.io/crates/v/iii-sdk)](https://crates.io/crates/iii-sdk) [![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](LICENSE) ## Packages From dae7a2668cc647d777311ba6228f03b02bff42dc Mon Sep 17 00:00:00 2001 From: Rohit Ghumare Date: Mon, 2 Mar 2026 15:10:03 +0530 Subject: [PATCH 08/10] docs: add TriggerHandler comment to Rust custom trigger type example --- packages/rust/iii/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/rust/iii/README.md b/packages/rust/iii/README.md index 1effa52..616d4f6 100644 --- a/packages/rust/iii/README.md +++ b/packages/rust/iii/README.md @@ -87,6 +87,7 @@ iii.register_trigger("http", "math.add", json!({ ### Custom Trigger Types ```rust +// handler must implement TriggerHandler (register_trigger + unregister_trigger) iii.register_trigger_type("webhook", "External webhook trigger", my_handler); ``` From 50743bb06c56a1941371cbc31df5e44ffb04897b Mon Sep 17 00:00:00 2001 From: anthonyiscoding <142696453+anthonyiscoding@users.noreply.github.com> Date: Mon, 2 Mar 2026 12:53:23 -0600 Subject: [PATCH 09/10] nit: small README text changes during review --- README.md | 44 +++++++++++++++++------------------ packages/node/iii/README.md | 40 +++++++++++++++++-------------- packages/python/iii/README.md | 20 ++++++++-------- packages/rust/iii/README.md | 20 ++++++++-------- 4 files changed, 64 insertions(+), 60 deletions(-) diff --git a/README.md b/README.md index 1c378f1..35e82c9 100644 --- a/README.md +++ b/README.md @@ -7,28 +7,28 @@ Official SDKs for the [iii engine](https://github.com/iii-hq/iii). [![crates.io](https://img.shields.io/crates/v/iii-sdk)](https://crates.io/crates/iii-sdk) [![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](LICENSE) -## Packages +## Installing Packages -| 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) | +| 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 +## Hello World ### Node.js ```javascript -import { init } from 'iii-sdk' +import { init } from 'iii-sdk'; -const iii = init('ws://localhost:49134') +const iii = init('ws://localhost:49134'); iii.registerFunction({ id: 'greet' }, async (input) => { - return { message: `Hello, ${input.name}!` } -}) + return { message: `Hello, ${input.name}!` }; +}); -const result = await iii.trigger('greet', { name: 'world' }) +const result = await iii.trigger('greet', { name: 'world' }); ``` ### Python @@ -75,18 +75,18 @@ async fn main() -> Result<(), Box> { } ``` -## API Surface +## API -| 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)?` | +| 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 (await) | `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)?` | -> `call()` and `callVoid()` / `call_void()` exist as deprecated aliases. Use `trigger()` and `triggerVoid()` / `trigger_void()`. +> `call()` and `callVoid()` / `call_void()` are deprecated and will be removed in a future release. Use `trigger()` and `triggerVoid()` / `trigger_void()`. ## Development diff --git a/packages/node/iii/README.md b/packages/node/iii/README.md index 935a79b..db29edc 100644 --- a/packages/node/iii/README.md +++ b/packages/node/iii/README.md @@ -11,7 +11,7 @@ Node.js / TypeScript SDK for the [iii engine](https://github.com/iii-hq/iii). npm install iii-sdk ``` -## Quick Start +## Hello World ```javascript import { init } from 'iii-sdk' @@ -33,14 +33,14 @@ const result = await iii.trigger('greet', { name: 'world' }) ## API -| 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) | +| 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 @@ -66,8 +66,12 @@ iii.registerTrigger({ iii.registerTriggerType( { id: 'webhook', description: 'External webhook trigger' }, { - registerTrigger: async (config) => { /* setup */ }, - unregisterTrigger: async (config) => { /* teardown */ }, + registerTrigger: async (config) => { + /* setup */ + }, + unregisterTrigger: async (config) => { + /* teardown */ + }, }, ) ``` @@ -80,14 +84,14 @@ const result = await iii.trigger('orders.create', { item: 'widget' }) iii.triggerVoid('analytics.track', { event: 'page_view' }) ``` -## Subpath Exports +## Node Modules -| 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 | +| 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 | ## Deprecated diff --git a/packages/python/iii/README.md b/packages/python/iii/README.md index 3d06531..d344d17 100644 --- a/packages/python/iii/README.md +++ b/packages/python/iii/README.md @@ -12,7 +12,7 @@ Python SDK for the [iii engine](https://github.com/iii-hq/iii). pip install iii-sdk ``` -## Quick Start +## Hello World ```python import asyncio @@ -42,15 +42,15 @@ asyncio.run(main()) ## API -| Method | Description | -|--------|-------------| -| `III(url)` | Create an SDK instance | -| `await iii.connect()` | Connect to the engine (sets up WebSocket + OTel) | -| `iii.register_function(id, handler)` | Register a function that can be invoked by name | -| `iii.register_trigger(type, function_id, config)` | Bind a trigger (HTTP, cron, queue, etc.) to a function | -| `iii.register_trigger_type(id, description, handler)` | Register a custom trigger type | -| `await iii.trigger(id, data)` | Invoke a function and wait for the result | -| `iii.trigger_void(id, data)` | Invoke a function without waiting (fire-and-forget) | +| Method | Description | +| ----------------------------------------------------- | ------------------------------------------------------ | +| `III(url)` | Create an SDK instance | +| `await iii.connect()` | Connect to the engine | +| `iii.register_function(id, handler)` | Register a function that can be invoked by name | +| `iii.register_trigger(type, function_id, config)` | Bind a trigger (HTTP, cron, queue, etc.) to a function | +| `iii.register_trigger_type(id, description, handler)` | Register a custom trigger type | +| `await iii.trigger(id, data)` | Invoke a function and wait for the result | +| `iii.trigger_void(id, data)` | Invoke a function without waiting (fire-and-forget) | ### Connection diff --git a/packages/rust/iii/README.md b/packages/rust/iii/README.md index 616d4f6..75bb086 100644 --- a/packages/rust/iii/README.md +++ b/packages/rust/iii/README.md @@ -17,7 +17,7 @@ serde_json = "1" tokio = { version = "1", features = ["full"] } ``` -## Quick Start +## Hello World ```rust use iii_sdk::III; @@ -49,15 +49,15 @@ async fn main() -> Result<(), Box> { ## API -| Method | Description | -|--------|-------------| -| `III::new(url)` | Create an SDK instance | -| `iii.connect().await?` | Connect to the engine (sets up WebSocket + OTel) | -| `iii.register_function(id, \|input\| ...)` | Register a function that can be invoked by name | -| `iii.register_trigger(type, fn_id, config)?` | Bind a trigger (HTTP, cron, queue, etc.) to a function | -| `iii.register_trigger_type(id, description, handler)` | Register a custom trigger type | -| `iii.trigger(id, data).await?` | Invoke a function and wait for the result | -| `iii.trigger_void(id, data)?` | Invoke a function without waiting (fire-and-forget) | +| Method | Description | +| ----------------------------------------------------- | ------------------------------------------------------ | +| `III::new(url)` | Create an SDK instance | +| `iii.connect().await?` | Connect to the engine | +| `iii.register_function(id, \|input\| ...)` | Register a function that can be invoked by name | +| `iii.register_trigger(type, fn_id, config)?` | Bind a trigger (HTTP, cron, queue, etc.) to a function | +| `iii.register_trigger_type(id, description, handler)` | Register a custom trigger type | +| `iii.trigger(id, data).await?` | Invoke a function and wait for the result | +| `iii.trigger_void(id, data)?` | Invoke a function without waiting (fire-and-forget) | ### Connection From 74f5010b61f6e0daa271d4023d2b4824327a6f0b Mon Sep 17 00:00:00 2001 From: Rohit Ghumare Date: Tue, 3 Mar 2026 13:34:14 +0530 Subject: [PATCH 10/10] docs: overhaul READMEs for consistency across all SDKs - Add registerTrigger/register_trigger to root Hello World examples - Add Description column to root API table - Replace iii-example links with Quickstart docs link - Align SDK API tables to Operation | Signature | Description format - Remove Custom Trigger Types sections and register_trigger_type from API tables - Fix all api_path values to include leading / - Align function/trigger examples to orders.create across all SDKs - Add Modules section to Python and Rust READMEs - Merge packages/python/README.md dev commands into Python SDK README - Delete redundant packages/python/README.md --- README.md | 38 +++++++++++++------ packages/node/iii/README.md | 35 +++++------------- packages/python/README.md | 48 ------------------------ packages/python/iii/README.md | 70 ++++++++++++++++++++--------------- packages/rust/iii/README.md | 47 ++++++++++++----------- 5 files changed, 100 insertions(+), 138 deletions(-) delete mode 100644 packages/python/README.md diff --git a/README.md b/README.md index 35e82c9..bc2c1b0 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,12 @@ iii.registerFunction({ id: 'greet' }, async (input) => { return { message: `Hello, ${input.name}!` }; }); +iii.registerTrigger({ + type: 'http', + function_id: 'greet', + config: { api_path: '/greet', http_method: 'POST' }, +}); + const result = await iii.trigger('greet', { name: 'world' }); ``` @@ -46,6 +52,13 @@ iii.register_function("greet", greet) async def main(): await iii.connect() + + iii.register_trigger( + type="http", + function_id="greet", + config={"api_path": "/greet", "http_method": "POST"} + ) + result = await iii.trigger("greet", {"name": "world"}) asyncio.run(main()) @@ -67,6 +80,11 @@ async fn main() -> Result<(), Box> { Ok(json!({ "message": format!("Hello, {name}!") })) }); + iii.register_trigger("http", "greet", json!({ + "api_path": "/greet", + "http_method": "POST" + }))?; + let result: serde_json::Value = iii .trigger("greet", json!({ "name": "world" })) .await?; @@ -77,14 +95,14 @@ async fn main() -> Result<(), Box> { ## API -| 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 (await) | `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)?` | +| Operation | Node.js | Python | Rust | Description | +| ------------------------ | ---------------------------------------------------- | ------------------------------------------- | -------------------------------------------- | ------------------------------------------------------ | +| Initialize | `init(url)` | `III(url)` | `III::new(url)` | Create an SDK instance and connect to the engine | +| Connect | Auto on `init()` | `await iii.connect()` | `iii.connect().await?` | Open the WebSocket connection | +| Register function | `iii.registerFunction({ id }, handler)` | `iii.register_function(id, handler)` | `iii.register_function(id, \|input\| ...)` | Register a function that can be invoked by name | +| Register trigger | `iii.registerTrigger({ type, function_id, config })` | `iii.register_trigger(type, fn_id, config)` | `iii.register_trigger(type, fn_id, config)?` | Bind a trigger (HTTP, cron, queue, etc.) to a function | +| Invoke (await) | `await iii.trigger(id, data)` | `await iii.trigger(id, data)` | `iii.trigger(id, data).await?` | Invoke a function and wait for the result | +| Invoke (fire-and-forget) | `iii.triggerVoid(id, data)` | `iii.trigger_void(id, data)` | `iii.trigger_void(id, data)?` | Invoke a function without waiting | > `call()` and `callVoid()` / `call_void()` are deprecated and will be removed in a future release. Use `trigger()` and `triggerVoid()` / `trigger_void()`. @@ -115,9 +133,7 @@ cd packages/rust/iii && cargo test ## Examples -- [Node.js Example](./packages/node/iii-example/) -- [Python Example](./packages/python/iii-example/) -- [Rust Example](./packages/rust/iii-example/) +See the [Quickstart guide](https://iii.dev/docs/quickstart) for step-by-step tutorials. ## Resources diff --git a/packages/node/iii/README.md b/packages/node/iii/README.md index db29edc..b42c200 100644 --- a/packages/node/iii/README.md +++ b/packages/node/iii/README.md @@ -25,7 +25,7 @@ iii.registerFunction({ id: 'greet' }, async (input) => { iii.registerTrigger({ type: 'http', function_id: 'greet', - config: { api_path: 'greet', http_method: 'POST' }, + config: { api_path: '/greet', http_method: 'POST' }, }) const result = await iii.trigger('greet', { name: 'world' }) @@ -33,14 +33,13 @@ const result = await iii.trigger('greet', { name: 'world' }) ## API -| 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) | +| Operation | Signature | Description | +| ------------------------ | ---------------------------------------------------- | ------------------------------------------------------------ | +| Initialize | `init(url, options?)` | Create and connect to the engine. Returns an `ISdk` instance | +| Register function | `iii.registerFunction({ id }, handler)` | Register a function that can be invoked by name | +| Register trigger | `iii.registerTrigger({ type, function_id, config })` | Bind a trigger (HTTP, cron, queue, etc.) to a function | +| Invoke (await) | `await iii.trigger(id, data, timeoutMs?)` | Invoke a function and wait for the result | +| Invoke (fire-and-forget) | `iii.triggerVoid(id, data)` | Invoke a function without waiting (fire-and-forget) | ### Registering Functions @@ -56,26 +55,10 @@ iii.registerFunction({ id: 'orders.create' }, async (input) => { iii.registerTrigger({ type: 'http', function_id: 'orders.create', - config: { api_path: 'orders', http_method: 'POST' }, + config: { api_path: '/orders', http_method: 'POST' }, }) ``` -### Custom Trigger Types - -```javascript -iii.registerTriggerType( - { id: 'webhook', description: 'External webhook trigger' }, - { - registerTrigger: async (config) => { - /* setup */ - }, - unregisterTrigger: async (config) => { - /* teardown */ - }, - }, -) -``` - ### Invoking Functions ```javascript diff --git a/packages/python/README.md b/packages/python/README.md deleted file mode 100644 index f51dafc..0000000 --- a/packages/python/README.md +++ /dev/null @@ -1,48 +0,0 @@ -# Python Packages - -This directory contains Python packages for the III Engine. - -## Packages - -### iii - -The core SDK for communicating with the III Engine via WebSocket. The package is installed as `iii-sdk`. - -```bash -cd iii -pip install -e . -``` - -## Examples - -### iii-example - -Basic example demonstrating the III SDK. - -```bash -cd iii-example -uv sync -uv run python -m src.main -``` - -Prerequisite: the worker expects a III engine at `III_BRIDGE_URL` (default `ws://localhost:49134`) and Redis for the stream/event modules configured in `iii-example/config.yaml`. - -## Development - -### Install package in development mode - -```bash -pip install -e iii -``` - -### Type checking - -```bash -cd iii && mypy src -``` - -### Linting - -```bash -cd iii && ruff check src -``` diff --git a/packages/python/iii/README.md b/packages/python/iii/README.md index d344d17..74ed9d1 100644 --- a/packages/python/iii/README.md +++ b/packages/python/iii/README.md @@ -31,7 +31,7 @@ async def main(): iii.register_trigger( type="http", function_id="greet", - config={"api_path": "greet", "http_method": "POST"} + config={"api_path": "/greet", "http_method": "POST"} ) result = await iii.trigger("greet", {"name": "world"}) @@ -42,15 +42,14 @@ asyncio.run(main()) ## API -| Method | Description | -| ----------------------------------------------------- | ------------------------------------------------------ | -| `III(url)` | Create an SDK instance | -| `await iii.connect()` | Connect to the engine | -| `iii.register_function(id, handler)` | Register a function that can be invoked by name | -| `iii.register_trigger(type, function_id, config)` | Bind a trigger (HTTP, cron, queue, etc.) to a function | -| `iii.register_trigger_type(id, description, handler)` | Register a custom trigger type | -| `await iii.trigger(id, data)` | Invoke a function and wait for the result | -| `iii.trigger_void(id, data)` | Invoke a function without waiting (fire-and-forget) | +| Operation | Signature | Description | +| ------------------------ | ------------------------------------------------- | ------------------------------------------------------ | +| Initialize | `III(url)` | Create an SDK instance | +| Connect | `await iii.connect()` | Connect to the engine | +| Register function | `iii.register_function(id, handler)` | Register a function that can be invoked by name | +| Register trigger | `iii.register_trigger(type, function_id, config)` | Bind a trigger (HTTP, cron, queue, etc.) to a function | +| Invoke (await) | `await iii.trigger(id, data)` | Invoke a function and wait for the result | +| Invoke (fire-and-forget) | `iii.trigger_void(id, data)` | Invoke a function without waiting (fire-and-forget) | ### Connection @@ -59,10 +58,10 @@ Python requires an explicit `await iii.connect()` call (no async constructors in ### Registering Functions ```python -async def create_todo(data): - return {"status_code": 201, "body": {"id": "123", "title": data["body"]["title"]}} +async def create_order(data): + return {"status_code": 201, "body": {"id": "123", "item": data["body"]["item"]}} -iii.register_function("api.post.todo", create_todo) +iii.register_function("orders.create", create_order) ``` ### Registering Triggers @@ -72,34 +71,47 @@ Requires `await iii.connect()` first. ```python iii.register_trigger( type="http", - function_id="api.post.todo", - config={"api_path": "todo", "http_method": "POST"} + function_id="orders.create", + config={"api_path": "/orders", "http_method": "POST"} ) ``` -### Custom Trigger Types +### Invoking Functions + +Requires `await iii.connect()` first. ```python -async def on_register(config): - pass # setup +result = await iii.trigger("orders.create", {"body": {"item": "widget"}}) + +iii.trigger_void("analytics.track", {"event": "page_view"}) +``` + +## Modules + +| Import | What it provides | +| --------------- | --------------------------------- | +| `iii` | Core SDK (`III`, types) | +| `iii.stream` | Stream client for real-time state | +| `iii.telemetry` | OpenTelemetry integration | + +## Development -async def on_unregister(config): - pass # teardown +### Install in development mode -iii.register_trigger_type("webhook", "External webhook trigger", { - "register_trigger": on_register, - "unregister_trigger": on_unregister, -}) +```bash +pip install -e . ``` -### Invoking Functions +### Type checking -Requires `await iii.connect()` first. +```bash +mypy src +``` -```python -result = await iii.trigger("api.post.todo", {"body": {"title": "Buy milk"}}) +### Linting -iii.trigger_void("analytics.track", {"event": "page_view"}) +```bash +ruff check src ``` ## Deprecated diff --git a/packages/rust/iii/README.md b/packages/rust/iii/README.md index 75bb086..e0a16e2 100644 --- a/packages/rust/iii/README.md +++ b/packages/rust/iii/README.md @@ -34,7 +34,7 @@ async fn main() -> Result<(), Box> { }); iii.register_trigger("http", "greet", json!({ - "api_path": "greet", + "api_path": "/greet", "http_method": "POST" }))?; @@ -49,15 +49,14 @@ async fn main() -> Result<(), Box> { ## API -| Method | Description | -| ----------------------------------------------------- | ------------------------------------------------------ | -| `III::new(url)` | Create an SDK instance | -| `iii.connect().await?` | Connect to the engine | -| `iii.register_function(id, \|input\| ...)` | Register a function that can be invoked by name | -| `iii.register_trigger(type, fn_id, config)?` | Bind a trigger (HTTP, cron, queue, etc.) to a function | -| `iii.register_trigger_type(id, description, handler)` | Register a custom trigger type | -| `iii.trigger(id, data).await?` | Invoke a function and wait for the result | -| `iii.trigger_void(id, data)?` | Invoke a function without waiting (fire-and-forget) | +| Operation | Signature | Description | +| ------------------------ | -------------------------------------------- | ------------------------------------------------------ | +| Initialize | `III::new(url)` | Create an SDK instance | +| Connect | `iii.connect().await?` | Connect to the engine | +| Register function | `iii.register_function(id, \|input\| ...)` | Register a function that can be invoked by name | +| Register trigger | `iii.register_trigger(type, fn_id, config)?` | Bind a trigger (HTTP, cron, queue, etc.) to a function | +| Invoke (await) | `iii.trigger(id, data).await?` | Invoke a function and wait for the result | +| Invoke (fire-and-forget) | `iii.trigger_void(id, data)?` | Invoke a function without waiting (fire-and-forget) | ### Connection @@ -66,10 +65,9 @@ Rust requires an explicit `iii.connect().await?` call. This starts a background ### Registering Functions ```rust -iii.register_function("math.add", |input| async move { - let a = input["a"].as_i64().unwrap_or(0); - let b = input["b"].as_i64().unwrap_or(0); - Ok(json!({ "sum": a + b })) +iii.register_function("orders.create", |input| async move { + let item = input["body"]["item"].as_str().unwrap_or(""); + Ok(json!({ "status_code": 201, "body": { "id": "123", "item": item } })) }); ``` @@ -78,25 +76,18 @@ iii.register_function("math.add", |input| async move { Requires `iii.connect().await?` first. ```rust -iii.register_trigger("http", "math.add", json!({ - "api_path": "add", +iii.register_trigger("http", "orders.create", json!({ + "api_path": "/orders", "http_method": "POST" }))?; ``` -### Custom Trigger Types - -```rust -// handler must implement TriggerHandler (register_trigger + unregister_trigger) -iii.register_trigger_type("webhook", "External webhook trigger", my_handler); -``` - ### Invoking Functions Requires `iii.connect().await?` first. ```rust -let result = iii.trigger("math.add", json!({ "a": 2, "b": 3 })).await?; +let result = iii.trigger("orders.create", json!({ "body": { "item": "widget" } })).await?; iii.trigger_void("analytics.track", json!({ "event": "page_view" }))?; ``` @@ -119,6 +110,14 @@ Enable the `otel` feature for full tracing and metrics support: iii-sdk = { version = "0.3", features = ["otel"] } ``` +## Modules + +| Import | What it provides | +| -------------------- | --------------------------------------------------- | +| `iii_sdk` | Core SDK (`III`, types) | +| `iii_sdk::stream` | Stream client (`Streams`, `UpdateBuilder`) | +| `iii_sdk::telemetry` | OpenTelemetry integration (requires `otel` feature) | + ## Deprecated `call()` and `call_void()` are deprecated aliases for `trigger()` and `trigger_void()`. They still work but will be removed in a future release.