Skip to Content
SDKsTypeScript

TypeScript SDK

The TypeScript SDK ships as a single package with two modules:

ExportPurpose
createClientLow-level HTTP client — fetch-and-lock, complete, fail, extend lock
createWorker / subscribe / runWorkerWorker abstraction — polling loop, heartbeat, auto-complete

Installation

bun add @orrery/sdk

createClient

Creating a client

import { createClient } from "@orrery/sdk"; const client = createClient({ baseUrl: "http://localhost:3000" }); // baseUrl defaults to ORRERY_URL env var, then "http://localhost:3000"

Methods

// Fetch and lock tasks const tasks = await client.fetchAndLock({ workerId: "my-worker", subscriptions: [ { topic: "validatePayment" }, { topic: "chargeCard", processDefinitionIds: ["order-process"] }, ], maxTasks: 4, // default: 1 lockDurationMs: 30000, // default: 30 000 }); // Complete a task await client.completeTask(task.id, workerId, { approved: true }); // Fail a task await client.failTask(task.id, workerId, "payment declined", 2, 5000); // args: id, workerId, errorMessage, retries (default 0), retryTimeoutMs (default 0) // Extend the lock (heartbeat) await client.extendLock(task.id, workerId, 30000);

Errors are thrown as Error objects with message "HTTP {status}: {body}".

ExternalTask shape

interface ExternalTask { id: string; topic: string; processInstanceId: string; processDefinitionId: string; elementId: string; variables: Record<string, unknown>; workerId: string; lockedUntil: string; // ISO 8601 retryCount: number; maxRetries: number; createdAt: string; // ISO 8601 }

Worker

createWorker + subscribe + runWorker wrap the polling loop. The worker automatically extends locks (heartbeat at 50% of lockDurationMs), completes tasks on success, and fails them on error.

Minimal example

import { createWorker, subscribe, runWorker } from "@orrery/sdk"; let worker = createWorker({ baseUrl: "http://localhost:3000" }); worker = subscribe( worker, { topic: "validatePayment" }, async (task) => { const amount = task.variables.amount as number; return { valid: amount > 0 }; }, ); await runWorker(worker); // blocks until SIGINT / SIGTERM

subscribe is immutable — it returns a new worker with the handler registered.

Worker options

const worker = createWorker({ workerId: "payment-worker-1", // default: "worker-{timestamp}" baseUrl: "http://localhost:3000", lockDurationMs: 60000, // default: 30 000 requestTimeoutMs: 20000, // default: 20 000 concurrency: 8, // default: 4 });

If baseUrl is omitted, the worker reads ORRERY_URL from the environment and falls back to http://localhost:3000.

Multiple topics

worker = subscribe(worker, { topic: "validatePayment" }, async (task) => { return { valid: true }; }); worker = subscribe( worker, { topic: "chargeCard", processDefinitionIds: ["order-process"] }, async (task) => { return { chargeId: "ch_abc123" }; }, ); worker = subscribe(worker, { topic: "sendReceipt" }, async (task) => { return {}; });

processDefinitionIds filters tasks to only those definitions. Omit it (or pass an empty array) to receive tasks from any definition.

Error handling

Throw any error to fail the task. The error message is stored and the task is retried according to its retry configuration.

worker = subscribe(worker, { topic: "chargeCard" }, async (task) => { const amount = task.variables.amount as number; if (!amount) throw new Error("missing amount variable"); if (amount > 10_000) throw new Error("amount exceeds limit"); return { charged: true, amount }; });

Task context

The handler receives an ExternalTask with the full task context:

worker = subscribe(worker, { topic: "processOrder" }, async (task) => { console.log("task: ", task.id); console.log("topic: ", task.topic); console.log("instance: ", task.processInstanceId); console.log("definition:", task.processDefinitionId); console.log("retry: ", task.retryCount, "/", task.maxRetries); const orderId = task.variables.orderId; const amount = task.variables.amount as number; return { total: amount }; });

Source: sdks/typescript/ in the main repository.

Last updated on