API Reference
Complete reference for the Ablauf class and related types
API Reference
Complete reference for the Ablauf class, its methods, and related types.
Ablauf Class
The main API for creating and managing workflows.
Constructor
new Ablauf(binding: DurableObjectNamespace, config?: AblaufConfig)Parameters:
binding— TheWORKFLOW_RUNNERDurable Object namespace from your worker'senvconfig— Optional configuration object
Config Options:
Prop
Type
Example:
import { Ablauf } from '@der-ablauf/workflows';
import { env } from 'cloudflare:workers';
const ablauf = new Ablauf(env.WORKFLOW_RUNNER, {
workflows: [OrderWorkflow, [HighVolumeWorkflow, { shards: 8 }]],
observability: true,
});Methods
create()
Create and start a new workflow instance.
create<Payload, Result, Events extends object, Type extends string, SSEUpdates extends object>(
workflow: WorkflowClass<Payload, Result, Events, Type, SSEUpdates>,
props: { id: string; payload: Payload }
): Promise<WorkflowHandle<Payload, Result, Events, Type, SSEUpdates>>Parameters:
workflow— The workflow class to instantiateprops.id— Workflow instance IDprops.payload— Input payload (validated against workflow'sinputSchema)
Returns:
A WorkflowHandle for interacting with the workflow instance.
Throws:
PayloadValidationError— If payload validation failsWorkflowAlreadyExistsError— If a workflow with the given ID already exists
Example:
const order = await ablauf.create(OrderWorkflow, {
id: "order-123",
payload: { orderId: "123", items: [...] },
});
const status = await order.getStatus();get()
Get a handle for an existing workflow instance. This does not make a network call.
get<Payload, Result, Events extends object, Type extends string, SSEUpdates extends object>(
workflow: WorkflowClass<Payload, Result, Events, Type, SSEUpdates>,
props: { id: string }
): WorkflowHandle<Payload, Result, Events, Type, SSEUpdates>Parameters:
workflow— The workflow class (for type inference and event schema)props.id— Workflow instance ID
Returns:
A WorkflowHandle for interacting with the workflow instance.
Example:
const order = ablauf.get(OrderWorkflow, { id: 'order-123' });
const status = await order.getStatus();
await order.sendEvent({ event: 'payment', payload: { amount: 99 } });list()
List workflow instances of a specific type.
list(
type: string,
filters?: WorkflowIndexListFilters
): Promise<WorkflowIndexEntry[]>Parameters:
type— Workflow type (e.g.,"process-order")filters.status— Optional status filterfilters.limit— Optional result limit (sorted byupdatedAt, newest first)
Throws:
ObservabilityDisabledError— If observability is disabled
Example:
const running = await ablauf.list('process-order', { status: 'running' });
const recent = await ablauf.list('process-order', { limit: 10 });createWorkflowRunner()
Returns the Durable Object class to export from your worker.
createWorkflowRunner(overrides?: { binding?: string }): typeof WorkflowRunnerExample:
export const WorkflowRunner = ablauf.createWorkflowRunner();createHandlers()
Returns oRPC handlers for the dashboard API (both RPC and OpenAPI).
createHandlers(): { rpcHandler: RPCHandler; openApiHandler: OpenAPIHandler }Example:
const { rpcHandler, openApiHandler } = ablauf.createHandlers();
app.all('/__ablauf/*', async (c) => {
const { matched, response } = await openApiHandler.handle(c.req.raw, {
prefix: '/__ablauf',
context: ablauf.getDashboardContext(),
});
if (matched) return c.newResponse(response.body, response);
const { matched: matchedRpc, response: rpcResponse } = await rpcHandler.handle(c.req.raw, {
prefix: '/__ablauf',
context: ablauf.getDashboardContext(),
});
if (matchedRpc) return c.newResponse(rpcResponse.body, rpcResponse);
return new Response('Not Found', { status: 404 });
});WorkflowHandle
The WorkflowHandle is the primary interface for interacting with a specific workflow instance. You get a handle from ablauf.create() or ablauf.get().
getStatus()
Get the current status of this workflow instance.
getStatus(): Promise<WorkflowStatusResponseFor<Payload, Result, Type>>Returns: A typed status response with inferred payload, result, and type.
sendEvent()
Send a typed event to this workflow instance.
sendEvent(props: WorkflowEventProps<Events>): Promise<void>Parameters:
props.event— Event nameprops.payload— Event payload (validated against event schema)
Throws:
EventValidationError— If event payload validation failsWorkflowNotRunningError— If the workflow is not waiting for this event
Example:
const order = ablauf.get(OrderWorkflow, { id: 'order-123' });
await order.sendEvent({
event: 'payment-received',
payload: { amount: 99.99, transactionId: 'tx-456' },
});pause()
Pause this workflow. It will finish its current step, then suspend.
pause(): Promise<void>resume()
Resume this paused workflow. Replays execution history and continues from where it stopped.
resume(): Promise<void>terminate()
Permanently terminate this workflow. It cannot be resumed after termination.
terminate(): Promise<void>waitForUpdate()
Wait for a specific SSE update from this workflow.
waitForUpdate<K extends keyof SSEUpdates>(
props: { update: K; timeout?: string }
): Promise<SSEUpdates[K]>Parameters:
props.update— The SSE event name to wait forprops.timeout— Optional timeout as a duration string (e.g.,"30s","5m")
Throws:
UpdateTimeoutError— If the timeout expires before the update arrivesWorkflowNotRunningError— If the workflow completes or errors before the update
Example:
const order = ablauf.get(OrderWorkflow, { id: 'order-123' });
const progress = await order.waitForUpdate({
update: 'progress',
timeout: '30s',
});Types
Step
The step API available inside workflow run() functions.
Prop
Type
SSE
The Server-Sent Events API available inside workflow run() functions.
Prop
Type
RetryConfig
Prop
Type
StepDoOptions
Options for step.do():
Prop
Type
StepWaitOptions
Options for step.waitForEvent():
Prop
Type
WorkflowStatus
type WorkflowStatus =
| 'created' // Initial state after creation
| 'running' // Actively executing steps
| 'completed' // All steps finished successfully
| 'errored' // A step or validation error occurred
| 'paused' // Manually paused via pause()
| 'sleeping' // Waiting for a step.sleep() or step.sleepUntil() timer
| 'waiting' // Waiting for a step.waitForEvent() delivery
| 'terminated'; // Permanently stopped via terminate()WorkflowStatusResponse
Prop
Type
StepInfo
Prop
Type
WorkflowIndexEntry
Prop
Type
WorkflowIndexListFilters
Prop
Type
WorkflowShardConfig
Prop
Type
WorkflowClass
The interface that workflow definitions (both class-based and functional) must satisfy.
Prop
Type
Duration Strings
Ablauf uses human-readable duration strings in several places (e.g., step.sleep(), step.waitForEvent() timeout).
Supported Formats
| Format | Example | Description |
|---|---|---|
Nms | "500ms" | Milliseconds |
Ns | "30s" | Seconds |
Nm | "5m" | Minutes |
Nh | "1h" | Hours |
Nd | "7d" | Days |
Examples
await step.sleep('cooldown', '30s'); // 30 seconds
await step.sleep('backoff', '5m'); // 5 minutes
await step.sleep('daily', '1h'); // 1 hour
const result = await step.waitForEvent('payment-received', {
timeout: '10m', // 10 minutes
});Throws:
InvalidDurationError if the duration string is malformed.
Size Strings
Ablauf uses human-readable size strings for the resultSizeLimit.maxSize configuration.
Supported Formats
| Format | Example | Description |
|---|---|---|
Nb | "100b" | Bytes |
Nkb | "512kb" | Kilobytes |
Nmb | "64mb" | Megabytes |
Ngb | "1gb" | Gigabytes |
Throws:
InvalidSizeError if the size string is malformed.
ResultSizeLimitConfig
Prop
Type
Error Classes
Engine Errors
All engine errors extend WorkflowError (which extends Error). Every engine error has a code, status, source, and message.
| Error Class | Code | Status | Source |
|---|---|---|---|
WorkflowNotFoundError | WORKFLOW_NOT_FOUND | 404 | api |
ResourceNotFoundError | RESOURCE_NOT_FOUND | 404 | api |
WorkflowAlreadyExistsError | WORKFLOW_ALREADY_EXISTS | 409 | engine |
WorkflowTypeUnknownError | WORKFLOW_TYPE_UNKNOWN | 400 | api |
PayloadValidationError | VALIDATION_ERROR | 400 | validation |
EventValidationError | EVENT_INVALID | 400 | validation |
StepFailedError | STEP_FAILED | 500 | step |
StepRetryExhaustedError | STEP_RETRY_EXHAUSTED | 500 | step |
EventTimeoutError | EVENT_TIMEOUT | 408 | engine |
UpdateTimeoutError | UPDATE_TIMEOUT | 408 | engine |
WorkflowNotRunningError | WORKFLOW_NOT_RUNNING | 409 | engine |
DuplicateStepError | VALIDATION_ERROR | 400 | engine |
InvalidDurationError | VALIDATION_ERROR | 400 | validation |
InvalidSizeError | VALIDATION_ERROR | 400 | validation |
ObservabilityDisabledError | OBSERVABILITY_DISABLED | 400 | api |
InvalidSchemaError | INVALID_SCHEMA | 400 | validation |
InvalidSchemaError
Thrown when a workflow schema uses Zod types that are not compatible with SuperJSON serialization. This error is raised at workflow registration time (not at runtime), catching invalid schemas early.
// This throws InvalidSchemaError because z.function() is not serializable:
defineWorkflow((t) => ({
type: 'bad',
input: z.object({ cb: z.function() }), // bypassed t namespace
run: async () => ({}),
}));The error message includes the full path to the unsupported type (e.g., "Unsupported Zod type "function" at path "input.cb").
See Supported Transport Types for the full list of allowed types.
NonRetriableError
NonRetriableError extends plain Error (not WorkflowError). It is a user-facing error designed to be thrown inside step.do() callbacks to signal that a failure is permanent and the step should not be retried.
import { NonRetriableError } from '@der-ablauf/workflows';
await step.do('validate-user', async () => {
const user = await getUser(userId);
if (user.banned) {
throw new NonRetriableError('User is banned');
}
return user;
});When thrown:
- The step is immediately marked as
failed— no retries are attempted, regardless of retry configuration - The error is recorded in the step's retry history
- The workflow transitions to
errored
Use NonRetriableError for permanent failures where retrying would be wasteful: business rule violations, authorization failures, invalid data, or deleted resources.
See Skipping Retries with NonRetriableError for more details and examples.
Error JSON Shape
All WorkflowError instances serialize to:
{
"error": {
"code": "WORKFLOW_NOT_FOUND",
"message": "Workflow \"order-123\" not found",
"status": 404,
"source": "api"
}
}Discriminating Errors
Across Durable Object RPC boundaries, errors lose their class identity. Use err.code to discriminate:
try {
const order = ablauf.get(OrderWorkflow, { id: 'order-123' });
await order.getStatus();
} catch (e) {
if (e instanceof WorkflowError && e.code === 'WORKFLOW_NOT_FOUND') {
// handle not found
}
}Transport Schema
The t namespace is a constrained subset of Zod that only exposes types compatible with SuperJSON serialization. It's provided as the parameter in defineWorkflow() callbacks and can be imported directly for BaseWorkflow usage.
import { t } from '@der-ablauf/workflows';For wrapping pre-existing Zod schemas, use serializable():
import { serializable } from '@der-ablauf/workflows';
import { z } from 'zod';
const mySchema = serializable(z.object({ name: z.string() }));
// Throws InvalidSchemaError if schema uses unsupported typesSee Supported Transport Types for the complete list of available types, excluded types, and migration guide.