Workflows SDK — Node / TypeScript
@ltinteg/workflows-sdk is the canonical typed client for the workflow engine. It is generated from the same catalog as reference.orkestia.dev: one start… binding per workflow, plus a small hand-written runtime for auth, retries, and SSE.
Requires Node ≥ 20. ESM only.
Install
npm i @ltinteg/workflows-sdk
Start a run
import { LtIntegWorkflowsClient, aws } from "@ltinteg/workflows-sdk"
const client = new LtIntegWorkflowsClient({
baseUrl: "https://workflow-api.orkestia.dev",
token: process.env.ORKESTIA_TOKEN, // org-member or end-user Bearer
})
// Optional: discover before you call
await client.catalog.listTypes({ prefix: "aws." })
await client.catalog.getSchema("aws.s3.create_bucket")
const run = await aws.s3.startCreateBucket(client, {
bucket: "my-app-assets",
connection_uuid: "…",
region: "us-east-1",
})
console.log(run.workflowId, run.stateName)
const output = await run.wait()
Do not pass organization_uuid. The server resolves it from the token.
aws.s3.create_bucket call above is illustrative. Resolve the live type name and input fields from the catalog or client.catalog.getSchema() before you ship.Stream transitions
run.events() opens GET /api/workflows/{id}/stream and yields typed events until the run is terminal.
for await (const evt of run.events({ streamTimeoutSecs: 600 })) {
if (evt.type === "transition") console.log(evt.from, "->", evt.to)
if (evt.type === "completed") break
if (evt.type === "failed") throw new Error(evt.error.message)
}
run.wait() (alias run.result()) consumes that stream and resolves to the terminal state_data, or throws WorkflowFailedError.
import { WorkflowFailedError } from "@ltinteg/workflows-sdk/errors"
try {
const output = await run.wait()
} catch (err) {
if (err instanceof WorkflowFailedError) console.error(err.failure)
}
AbortSignal is honored on start, get, and stream:
const ac = new AbortController()
setTimeout(() => ac.abort(), 5_000)
for await (const evt of run.events({ signal: ac.signal })) { /* … */ }
Catalog and lifecycle
| Call | REST equivalent | Purpose |
|---|---|---|
client.catalog.listTypes({ prefix }) | GET /api/workflows/types | Discover types |
client.catalog.getSchema(type) | GET /api/workflows/types/{type}/schema | Input / output + has_prerequisites |
client.catalog.getDefinition(type) | definition endpoint | Full registered definition |
client.workflows.get(id) | GET /api/workflows/{id} | Current state |
client.workflows.history(id) | GET /api/workflows/{id}/history | Event-sourced log |
client.workflows.retry(id) | POST /api/workflows/{id}/retry | Re-drive a FAILED run |
client.workflows.list({ workflowType }) | GET /api/workflows/find | Find runs of one type |
Generated bindings (aws.s3.startCreateBucket, github.startValidateToken, …) are thin wrappers over client.start(...) that add typed inputs and return a WorkflowRunHandle.
client.workflows.cancel() throws WorkflowNotImplementedError — the deployed API has no cancel endpoint. The method exists so call sites type-check.Errors
Every error extends WorkflowError (a real Error subclass, so instanceof works) and carries requestId when the server sent X-Request-Id.
| Class | When |
|---|---|
WorkflowStartError | Start rejected (validation, auth, prerequisites) |
WorkflowNotFoundError | Unknown workflow_id |
WorkflowTimeoutError | Stream / wait exceeded the timeout |
WorkflowFailedError | Run reached FAILED |
WorkflowStreamError | SSE transport failed |
WorkflowNotImplementedError | Called a method the API does not expose |
WorkflowCancelledError | Aborted via AbortSignal |
import { WorkflowStartError } from "@ltinteg/workflows-sdk/errors"
Auth
Pass either token kind into the client. For browser apps acting as an end-user, take the JWT from @orkestia/auth and do not embed an org-member token in the page.
import { createOrkestiaAuth } from "@orkestia/auth"
import { LtIntegWorkflowsClient } from "@ltinteg/workflows-sdk"
const auth = createOrkestiaAuth({ clientKey: "orkestia_…" })
const session = auth.getSession()
const client = new LtIntegWorkflowsClient({
baseUrl: "https://workflow-api.orkestia.dev",
token: session.token,
credentials: "include", // browsers only; omit in Node
})
See API & tooling for the two-token model.
