Installation
Quick Start
import { init } from 'iii-sdk'
const iii = init('ws://localhost:49134')
iii.registerFunction({ id: 'myFunction' }, (req) => {
return { status_code: 200, body: { message: 'Hello, world!' } }
})
iii.registerTrigger({
type: 'http',
function_id: 'myFunction',
config: { api_path: '/hello', http_method: 'POST' },
})
const result = await iii.call('myFunction', { param: 'value' })
Initialization
init()
Initialize the III SDK and connect to the engine.
WebSocket address of the III Engine (e.g., ws://localhost:49134)
Optional configuration options
Custom worker name (defaults to hostname:pid)
Enable automatic metrics reporting to the engine
Default timeout for function invocations in milliseconds
WebSocket reconnection behavior configuration
Initial delay before first reconnection attempt
Maximum delay between reconnection attempts
Exponential backoff multiplier
Random jitter factor (0-1)
Maximum retry attempts (-1 for infinite)
OpenTelemetry configuration (enabled by default)
Enable OpenTelemetry (can also set via OTEL_ENABLED env var)
Service name for telemetry (defaults to worker name)
Enable metrics collection
Additional telemetry metadata
Project name for analytics
Framework name (e.g., “express”, “fastify”)
Amplitude API key for analytics
import { init } from 'iii-sdk'
const iii = init('ws://localhost:49134', {
workerName: 'my-worker',
invocationTimeoutMs: 60000,
reconnectionConfig: {
maxRetries: 10,
initialDelayMs: 2000,
},
otel: {
enabled: true,
serviceName: 'my-service',
},
})
Function Registration
registerFunction()
Register a function that can be invoked by other services or triggers.
Function registration metadata
Unique function identifier (use :: for namespacing, e.g., external::my_lambda)
Human-readable function description
JSON schema for request validation
JSON schema for response validation
Additional metadata for the function
handler
function | HttpInvocationConfig
required
Function handler (local function) or HTTP invocation config (external HTTP endpoint)Local Handler:(data: TInput) => Promise<TOutput>
HTTP Invocation Config:
HTTP method (GET, POST, PUT, PATCH, DELETE)
Request timeout in milliseconds
Authentication configuration (HMAC, Bearer, or API Key)
Function reference with id and unregister() method
// Local handler
const ref = iii.registerFunction({ id: 'myFunction' }, async (req) => {
return { status_code: 200, body: { message: 'Hello, world!' } }
})
// HTTP invocation (external endpoint)
iii.registerFunction(
{ id: 'external::lambda' },
{
url: 'https://my-lambda.example.com/invoke',
method: 'POST',
timeout_ms: 10000,
headers: { 'X-Custom-Header': 'value' },
auth: { type: 'bearer', token_key: 'MY_TOKEN_ENV_VAR' },
}
)
// Unregister later
ref.unregister()
Function Invocation
call()
Invoke a function synchronously and wait for the result.
ID of the function to invoke
Input data to pass to the function
Override the default invocation timeout
Promise that resolves with the function result
const result = await iii.call('myFunction', { param: 'value' })
console.log(result)
// With custom timeout
const result = await iii.call('slowFunction', { data: 'x' }, 60000)
callVoid()
Invoke a function asynchronously without waiting for a result (fire-and-forget).
ID of the function to invoke
Input data to pass to the function
iii.callVoid('myFunction', { param: 'value' })
// Function is invoked in the background, no result is returned
trigger()
Alias for call(). Invokes a function synchronously.
const result = await iii.trigger('myFunction', { param: 'value' })
triggerVoid()
Alias for callVoid(). Invokes a function asynchronously.
iii.triggerVoid('myFunction', { param: 'value' })
Trigger Management
registerTrigger()
Register a trigger to automatically invoke a function based on events.
Trigger type (e.g., http, schedule, custom types)
ID of the function to invoke when triggered
Trigger-specific configuration (depends on trigger type)
Trigger object with unregister() method
// HTTP trigger
const trigger = iii.registerTrigger({
type: 'http',
function_id: 'myFunction',
config: {
api_path: '/hello',
http_method: 'POST',
},
})
// Unregister later
trigger.unregister()
registerTriggerType()
Register a custom trigger type with custom logic.
Unique trigger type identifier
Human-readable description
Trigger type handler with registerTrigger and unregisterTrigger methods
iii.registerTriggerType(
{
id: 'myTriggerType',
description: 'My custom trigger type',
},
{
registerTrigger: async (config) => {
// Setup logic when a trigger of this type is registered
console.log('Trigger registered:', config)
},
unregisterTrigger: async (config) => {
// Cleanup logic when a trigger is unregistered
console.log('Trigger unregistered:', config)
},
}
)
unregisterTriggerType()
Unregister a custom trigger type.
Trigger type ID to unregister
iii.unregisterTriggerType({ id: 'myTriggerType' })
Service Registration
registerService()
Register a service for grouping related functions.
Parent service ID for hierarchical organization
iii.registerService({
id: 'my-service',
description: 'My service description',
})
Engine Functions
listFunctions()
List all registered functions in the engine.
Array of function information objects
const functions = await iii.listFunctions()
functions.forEach((fn) => {
console.log(fn.function_id, fn.description)
})
listWorkers()
List all connected workers in the engine.
Array of worker information objects
const workers = await iii.listWorkers()
workers.forEach((worker) => {
console.log(worker.name, worker.status, worker.function_count)
})
Channels
createChannel()
Create a streaming channel pair for worker-to-worker data transfer.
Optional buffer size for the channel
Channel object with writer, reader, writerRef, and readerRef
const channel = await iii.createChannel(128)
// Write data
await channel.writer.write({ data: 'hello' })
await channel.writer.close()
// Read data
for await (const item of channel.reader) {
console.log(item)
}
// Pass channel refs to other functions
await iii.call('processData', {
input: channel.readerRef,
output: channel.writerRef,
})
Event Listeners
onFunctionsAvailable()
Subscribe to function availability events.
Callback invoked when functions are registered/unregistered(functions: FunctionInfo[]) => void
const unsubscribe = iii.onFunctionsAvailable((functions) => {
console.log('Available functions:', functions.map((f) => f.function_id))
})
// Unsubscribe later
unsubscribe()
onLog()
Subscribe to OpenTelemetry log events from the engine.
Callback invoked when log events are received(log: OtelLogEvent) => void
Optional log filtering configuration
Minimum severity level: trace, debug, info, warn, error, fatal, all
const unsubscribe = iii.onLog(
(log) => {
console.log(`[${log.severity_text}] ${log.body}`, log.attributes)
},
{ level: 'warn' } // Only receive warnings and errors
)
// Unsubscribe later
unsubscribe()
onConnectionStateChange()
Monitor WebSocket connection state changes.
Callback invoked when connection state changes(state: 'disconnected' | 'connecting' | 'connected' | 'reconnecting' | 'failed') => void
const unsubscribe = iii.onConnectionStateChange((state) => {
console.log('Connection state:', state)
})
// Unsubscribe later
unsubscribe()
getConnectionState()
Get the current connection state.
Current state: disconnected, connecting, connected, reconnecting, or failed
const state = iii.getConnectionState()
console.log('Current state:', state)
Context & Logging
getContext()
Get the current execution context (available within function handlers).
Context object with logger and optionally trace (OpenTelemetry span)
import { getContext } from 'iii-sdk'
iii.registerFunction({ id: 'myFunction' }, async (req) => {
const { logger, trace } = getContext()
logger.info('Processing request', { input: req })
logger.warn('Something might be wrong')
logger.error('An error occurred', { error: 'details' })
if (trace) {
trace.setAttribute('custom.attribute', 'value')
}
return { result: 'success' }
})
withContext()
Run a function with a custom context.
Context to use during execution
import { withContext, Logger } from 'iii-sdk'
const logger = new Logger('trace-id', 'my-function')
const ctx = { logger }
await withContext(async () => {
const { logger } = getContext()
logger.info('Running with custom context')
}, ctx)
Lifecycle
shutdown()
Gracefully shut down the SDK, cleaning up all resources.
Promise that resolves when shutdown is complete
Types
FunctionInfo
type FunctionInfo = {
function_id: string
description?: string
request_format?: object
response_format?: object
metadata?: Record<string, unknown>
}
WorkerInfo
type WorkerInfo = {
id: string
name?: string
runtime?: string
version?: string
os?: string
ip_address?: string
status: 'connected' | 'available' | 'busy' | 'disconnected'
connected_at_ms: number
function_count: number
functions: string[]
active_invocations: number
}
ApiRequest / ApiResponse
type ApiRequest<TBody = unknown> = {
path_params: Record<string, string>
query_params: Record<string, string | string[]>
body: TBody
headers: Record<string, string | string[]>
method: string
request_body: ChannelReader
}
type ApiResponse<TStatus = number, TBody = any> = {
status_code: TStatus
headers?: Record<string, string>
body?: TBody
}
Examples
Basic HTTP API
import { init } from 'iii-sdk'
const iii = init('ws://localhost:49134')
iii.registerFunction({ id: 'api.hello' }, async (req) => {
return {
status_code: 200,
body: { message: 'Hello, world!' },
}
})
iii.registerTrigger({
type: 'http',
function_id: 'api.hello',
config: { api_path: '/hello', http_method: 'GET' },
})
Calling Other Functions
iii.registerFunction({ id: 'processOrder' }, async (order) => {
// Call payment service
const payment = await iii.call('payment.charge', {
amount: order.total,
customer: order.customerId,
})
// Notify warehouse asynchronously
iii.callVoid('warehouse.ship', { orderId: order.id })
return { success: true, paymentId: payment.id }
})
Streaming Data with Channels
iii.registerFunction({ id: 'processStream' }, async (req) => {
const channel = await iii.createChannel()
// Process in background
iii.callVoid('processData', { input: channel.readerRef })
// Write data
for (let i = 0; i < 100; i++) {
await channel.writer.write({ value: i })
}
await channel.writer.close()
return { status: 'processing' }
})