@stepflowjs/core 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,155 @@
1
+ type Duration = number | `${number}ms` | `${number}s` | `${number}m` | `${number}h` | `${number}d`;
2
+ type ExecutionStatus = "pending" | "running" | "completed" | "failed" | "waiting" | "sleeping" | "cancelled";
3
+ interface WorkflowEvent<TData = unknown> {
4
+ id: string;
5
+ name: string;
6
+ data: TData;
7
+ timestamp: Date;
8
+ metadata: Record<string, unknown>;
9
+ }
10
+ type WorkflowEventMap = Record<string, {
11
+ data: unknown;
12
+ }>;
13
+ interface Execution<TPayload = unknown, TResult = unknown> {
14
+ id: string;
15
+ runId: string;
16
+ workflowId: string;
17
+ workflowVersion?: string;
18
+ eventName: string;
19
+ payload: TPayload;
20
+ status: ExecutionStatus;
21
+ result?: TResult;
22
+ error?: ExecutionError;
23
+ steps: StepExecution[];
24
+ metadata: Record<string, unknown>;
25
+ attempt: number;
26
+ startedAt: Date;
27
+ completedAt?: Date;
28
+ timeline: TimelineEvent[];
29
+ }
30
+ interface ExecutionError {
31
+ name: string;
32
+ message: string;
33
+ stack?: string;
34
+ code?: string;
35
+ }
36
+ interface StepExecution {
37
+ name: string;
38
+ status: "pending" | "running" | "completed" | "failed" | "cached";
39
+ result?: unknown;
40
+ error?: ExecutionError;
41
+ startedAt?: Date;
42
+ completedAt?: Date;
43
+ durationMs?: number;
44
+ }
45
+ interface StepResult<T = unknown> {
46
+ data: T;
47
+ startedAt: Date;
48
+ completedAt: Date;
49
+ durationMs: number;
50
+ }
51
+ type TimelineEventType = "execution:start" | "execution:complete" | "execution:failed" | "step:start" | "step:complete" | "step:failed" | "step:cached" | "invoke:start" | "sleep:start" | "sleep:complete" | "event:wait" | "event:received" | "event:timeout" | "log:info" | "log:warn" | "log:error" | "log:debug" | "metadata:update";
52
+ interface TimelineEvent {
53
+ id: string;
54
+ type: TimelineEventType;
55
+ timestamp: Date;
56
+ data: unknown;
57
+ stepName?: string;
58
+ metadata?: Record<string, unknown>;
59
+ }
60
+ interface QueueJob {
61
+ id: string;
62
+ workflowId: string;
63
+ eventName: string;
64
+ payload: unknown;
65
+ metadata: Record<string, unknown>;
66
+ priority: number;
67
+ attempts: number;
68
+ maxAttempts: number;
69
+ scheduledFor?: Date;
70
+ createdAt: Date;
71
+ }
72
+ interface PopOptions {
73
+ workerId?: string;
74
+ lockDuration?: number;
75
+ }
76
+ interface NackOptions {
77
+ delay?: number;
78
+ requeue?: boolean;
79
+ }
80
+ interface TriggerEvent {
81
+ id: string;
82
+ type: string;
83
+ source: string;
84
+ data: unknown;
85
+ metadata: Record<string, unknown>;
86
+ timestamp: Date;
87
+ }
88
+ type TriggerHandler = (event: TriggerEvent) => Promise<void>;
89
+ interface Trigger<TConfig = unknown> {
90
+ readonly type: string;
91
+ readonly config: TConfig;
92
+ start(handler: TriggerHandler): Promise<void>;
93
+ stop(): Promise<void>;
94
+ healthCheck(): Promise<boolean>;
95
+ }
96
+ interface WorkflowConfig {
97
+ id: string;
98
+ version?: string;
99
+ retries?: number;
100
+ retryDelay?: Duration;
101
+ timeout?: Duration;
102
+ cron?: string;
103
+ }
104
+ interface InvokeOptions {
105
+ timeout?: Duration;
106
+ metadata?: Record<string, unknown>;
107
+ }
108
+ interface WaitForEventOptions {
109
+ timeout?: Duration;
110
+ }
111
+ interface WaitForEventResult<T = unknown> {
112
+ eventData: T;
113
+ timeout: boolean;
114
+ }
115
+ interface StepOptions {
116
+ /** Timeout for this step */
117
+ timeout?: Duration;
118
+ /** Custom cache key for this step (for idempotency) */
119
+ idempotencyKey?: string;
120
+ }
121
+ interface ListOptions {
122
+ workflowId?: string;
123
+ status?: ExecutionStatus;
124
+ runId?: string;
125
+ limit?: number;
126
+ offset?: number;
127
+ }
128
+ interface EventWaiter {
129
+ executionId: string;
130
+ timeoutAt?: Date;
131
+ }
132
+ interface TriggerResult {
133
+ runId: string;
134
+ executionId: string;
135
+ publicAccessToken: string;
136
+ /** True if this trigger returned an existing execution (deduplicated) */
137
+ deduplicated?: boolean;
138
+ }
139
+ interface NotifyResult {
140
+ waiters: number;
141
+ executions: string[];
142
+ }
143
+ interface SubscribeOptions<TPayload = unknown, TResult = unknown> {
144
+ accessToken?: string;
145
+ throttleMs?: number;
146
+ onUpdate?: (run: Execution<TPayload, TResult>) => void;
147
+ onStepComplete?: (step: StepExecution) => void;
148
+ onComplete?: (result: TResult) => void;
149
+ onError?: (error: Error) => void;
150
+ onConnect?: () => void;
151
+ onDisconnect?: () => void;
152
+ }
153
+ type Unsubscribe = () => void;
154
+
155
+ export type { Duration as D, Execution as E, InvokeOptions as I, ListOptions as L, NotifyResult as N, PopOptions as P, QueueJob as Q, StepOptions as S, TimelineEvent as T, Unsubscribe as U, WorkflowEvent as W, WaitForEventOptions as a, WaitForEventResult as b, WorkflowConfig as c, Trigger as d, TriggerResult as e, ExecutionStatus as f, WorkflowEventMap as g, ExecutionError as h, StepExecution as i, StepResult as j, TimelineEventType as k, NackOptions as l, TriggerEvent as m, TriggerHandler as n, EventWaiter as o, SubscribeOptions as p };
@@ -0,0 +1,466 @@
1
+ import { EventEmitter } from 'events';
2
+ import { StorageAdapter } from './storage/index.js';
3
+ import { W as WorkflowEvent, S as StepOptions, I as InvokeOptions, D as Duration, a as WaitForEventOptions, b as WaitForEventResult, T as TimelineEvent, c as WorkflowConfig, d as Trigger, e as TriggerResult, E as Execution, L as ListOptions, N as NotifyResult } from './index-D_2FGtKL.js';
4
+ export { o as EventWaiter, h as ExecutionError, f as ExecutionStatus, l as NackOptions, P as PopOptions, Q as QueueJob, i as StepExecution, j as StepResult, p as SubscribeOptions, k as TimelineEventType, m as TriggerEvent, n as TriggerHandler, U as Unsubscribe, g as WorkflowEventMap } from './index-D_2FGtKL.js';
5
+
6
+ interface WorkflowContext<TPayload = unknown> {
7
+ /**
8
+ * The event that triggered this workflow
9
+ */
10
+ readonly event: WorkflowEvent<TPayload>;
11
+ /**
12
+ * Execution metadata
13
+ */
14
+ readonly execution: {
15
+ readonly id: string;
16
+ readonly runId: string;
17
+ readonly attempt: number;
18
+ readonly startedAt: Date;
19
+ };
20
+ /**
21
+ * Step execution methods (checkpointed, never re-execute on retry)
22
+ */
23
+ readonly step: StepContext;
24
+ /**
25
+ * Sleep for a duration (durable - survives restarts)
26
+ */
27
+ sleep(name: string, duration: Duration): Promise<void>;
28
+ /**
29
+ * Sleep until a specific timestamp
30
+ */
31
+ sleepUntil(name: string, timestamp: Date): Promise<void>;
32
+ /**
33
+ * Wait for an external event
34
+ */
35
+ waitForEvent<T = unknown>(name: string, eventId: string, options?: WaitForEventOptions): Promise<WaitForEventResult<T>>;
36
+ /**
37
+ * Structured logging (captured in timeline)
38
+ */
39
+ readonly log: LogContext;
40
+ /**
41
+ * Update metadata (visible to subscribers)
42
+ */
43
+ setMetadata(key: string, value: unknown): Promise<void>;
44
+ /**
45
+ * Get metadata value
46
+ */
47
+ getMetadata<T = unknown>(key: string): T | undefined;
48
+ }
49
+ interface StepContext {
50
+ /**
51
+ * Run a step with automatic checkpointing
52
+ * If the workflow retries, completed steps are not re-executed
53
+ */
54
+ run<T>(name: string, fn: () => Promise<T> | T, options?: StepOptions): Promise<T>;
55
+ /**
56
+ * Run multiple steps in parallel
57
+ */
58
+ parallel<T extends readonly unknown[]>(name: string, fns: {
59
+ [K in keyof T]: () => Promise<T[K]>;
60
+ }, options?: StepOptions): Promise<T>;
61
+ /**
62
+ * Invoke another workflow
63
+ */
64
+ invoke<TResult = unknown>(workflowId: string, payload: unknown, options?: InvokeOptions): Promise<TResult>;
65
+ /**
66
+ * Send an event (for waitForEvent in other workflows)
67
+ */
68
+ sendEvent(eventId: string, data: unknown): Promise<void>;
69
+ }
70
+ interface LogContext {
71
+ info(message: string, data?: Record<string, unknown>): void;
72
+ warn(message: string, data?: Record<string, unknown>): void;
73
+ error(message: string, data?: Record<string, unknown>): void;
74
+ debug(message: string, data?: Record<string, unknown>): void;
75
+ }
76
+ interface CreateContextOptions<TPayload> {
77
+ event: WorkflowEvent<TPayload>;
78
+ executionId: string;
79
+ runId: string;
80
+ attempt: number;
81
+ startedAt: Date;
82
+ storage: StorageAdapter;
83
+ onTimelineEvent?: (event: TimelineEvent) => void;
84
+ }
85
+ declare function createContext<TPayload>(options: CreateContextOptions<TPayload>): WorkflowContext<TPayload>;
86
+ declare class StepTimeoutError extends Error {
87
+ readonly stepName: string;
88
+ readonly timeoutMs: number;
89
+ constructor(stepName: string, timeoutMs: number);
90
+ }
91
+ declare class SleepInterrupt extends Error {
92
+ readonly stepName: string;
93
+ readonly wakeAt: Date;
94
+ constructor(stepName: string, wakeAt: Date);
95
+ }
96
+ declare class WaitForEventInterrupt extends Error {
97
+ readonly stepName: string;
98
+ readonly eventId: string;
99
+ readonly timeoutAt: Date;
100
+ constructor(stepName: string, eventId: string, timeoutAt: Date);
101
+ }
102
+ declare class InvokeInterrupt extends Error {
103
+ readonly stepName: string;
104
+ readonly workflowId: string;
105
+ readonly payload: unknown;
106
+ readonly childExecutionId: string;
107
+ readonly options?: InvokeOptions | undefined;
108
+ constructor(stepName: string, workflowId: string, payload: unknown, childExecutionId: string, options?: InvokeOptions | undefined);
109
+ }
110
+
111
+ type WorkflowHandler<TInput = unknown, TResult = unknown> = (context: WorkflowContext<TInput>) => Promise<TResult>;
112
+ interface WorkflowDefinition<TInput = unknown, TResult = unknown> {
113
+ readonly id: string;
114
+ readonly config: WorkflowConfig;
115
+ readonly handler: WorkflowHandler<TInput, TResult>;
116
+ }
117
+ interface CreateWorkflowOptions extends Partial<WorkflowConfig> {
118
+ id: string;
119
+ }
120
+ /**
121
+ * Create a new workflow definition
122
+ *
123
+ * @example
124
+ * ```typescript
125
+ * // Simple usage with input type
126
+ * const processOrder = createWorkflow<{ orderId: string }>({
127
+ * id: 'process-order',
128
+ * retries: 3,
129
+ * }, async ({ event, step, sleep }) => {
130
+ * const order = await step.run('validate', async () => {
131
+ * return validateOrder(event.data.orderId); // orderId is typed
132
+ * });
133
+ *
134
+ * await sleep('wait-before-shipping', '1h');
135
+ *
136
+ * await step.run('ship', async () => {
137
+ * return shipOrder(order);
138
+ * });
139
+ *
140
+ * return { status: 'completed' };
141
+ * });
142
+ *
143
+ * // With explicit result type
144
+ * const workflow = createWorkflow<{ userId: string }, { status: string }>({
145
+ * id: 'my-workflow',
146
+ * }, async ({ event }) => {
147
+ * return { status: 'done' }; // result type is enforced
148
+ * });
149
+ * ```
150
+ */
151
+ declare function createWorkflow<TInput = unknown, TResult = unknown>(options: CreateWorkflowOptions, handler: WorkflowHandler<TInput, TResult>): WorkflowDefinition<TInput, TResult>;
152
+ declare class WorkflowRegistry {
153
+ private workflows;
154
+ /**
155
+ * Register a workflow
156
+ */
157
+ register(workflow: WorkflowDefinition<any, any>): void;
158
+ /**
159
+ * Get a workflow by ID and optional version
160
+ */
161
+ get(id: string, version?: string): WorkflowDefinition<any, any> | undefined;
162
+ /**
163
+ * Get the latest version of a workflow
164
+ */
165
+ getLatest(id: string): WorkflowDefinition<any, any> | undefined;
166
+ /**
167
+ * Compare semantic versions
168
+ */
169
+ private compareVersions;
170
+ /**
171
+ * Check if a workflow exists
172
+ */
173
+ has(id: string): boolean;
174
+ /**
175
+ * Get all registered workflows (latest version of each)
176
+ */
177
+ all(): WorkflowDefinition<any, any>[];
178
+ /**
179
+ * Get all versions of a workflow
180
+ */
181
+ allVersions(id: string): WorkflowDefinition<any, any>[];
182
+ /**
183
+ * Get all workflows with cron schedules
184
+ */
185
+ scheduled(): WorkflowDefinition<any, any>[];
186
+ /**
187
+ * Unregister a workflow or specific version
188
+ */
189
+ unregister(id: string, version?: string): boolean;
190
+ /**
191
+ * Clear all workflows
192
+ */
193
+ clear(): void;
194
+ }
195
+
196
+ interface StepflowOptions {
197
+ /**
198
+ * Storage adapter for persistence
199
+ */
200
+ storage: StorageAdapter;
201
+ /**
202
+ * Number of worker concurrency
203
+ * @default 1
204
+ */
205
+ concurrency?: number;
206
+ /**
207
+ * Enable logging
208
+ * @default false
209
+ */
210
+ logging?: boolean;
211
+ /**
212
+ * Secret for signing access tokens
213
+ */
214
+ tokenSecret?: string;
215
+ /**
216
+ * Access token expiry in seconds
217
+ * @default 3600 (1 hour)
218
+ */
219
+ tokenExpiry?: number;
220
+ }
221
+ declare class Stepflow extends EventEmitter {
222
+ private storage;
223
+ private registry;
224
+ private worker;
225
+ private triggers;
226
+ private logging;
227
+ private tokenSecret;
228
+ private tokenExpiry;
229
+ constructor(options: StepflowOptions);
230
+ /**
231
+ * Register a workflow
232
+ */
233
+ register(workflow: WorkflowDefinition<any, any>): this;
234
+ /**
235
+ * Register multiple workflows
236
+ */
237
+ registerAll(workflows: WorkflowDefinition<any, any>[]): this;
238
+ /**
239
+ * Add a trigger
240
+ */
241
+ addTrigger(name: string, trigger: Trigger): this;
242
+ /**
243
+ * Start the orchestrator
244
+ */
245
+ start(): Promise<void>;
246
+ /**
247
+ * Stop the orchestrator
248
+ */
249
+ stop(): Promise<void>;
250
+ /**
251
+ * Trigger a workflow execution
252
+ */
253
+ trigger<TPayload = unknown>(workflowId: string, payload: TPayload, options?: {
254
+ runId?: string;
255
+ metadata?: Record<string, unknown>;
256
+ delay?: number;
257
+ idempotencyKey?: string;
258
+ }): Promise<TriggerResult>;
259
+ /**
260
+ * Get a run by ID
261
+ */
262
+ getRun(runId: string, options?: {
263
+ accessToken?: string;
264
+ }): Promise<Execution | null>;
265
+ /**
266
+ * Get execution by ID
267
+ */
268
+ getExecution(executionId: string): Promise<Execution | null>;
269
+ /**
270
+ * List executions
271
+ */
272
+ listRuns(options?: ListOptions): Promise<Execution[]>;
273
+ /**
274
+ * Notify an event (for waitForEvent)
275
+ */
276
+ notify(eventId: string, data: unknown): Promise<NotifyResult>;
277
+ /**
278
+ * Create a public access token for a run
279
+ */
280
+ createPublicToken(runId: string, executionId?: string): string;
281
+ /**
282
+ * Subscribe to run updates
283
+ */
284
+ subscribeToRun(runId: string, callback: (execution: Execution) => void): () => void;
285
+ /**
286
+ * Subscribe to execution updates
287
+ */
288
+ subscribeToExecution(executionId: string, callback: (event: unknown) => void): () => void;
289
+ /**
290
+ * Handle trigger events
291
+ */
292
+ private handleTrigger;
293
+ /**
294
+ * Get a trigger by name
295
+ */
296
+ getTrigger(type: string, ...args: unknown[]): Trigger | undefined;
297
+ /**
298
+ * Health check
299
+ */
300
+ healthCheck(): Promise<boolean>;
301
+ /**
302
+ * Get workflow registry
303
+ */
304
+ getRegistry(): WorkflowRegistry;
305
+ /**
306
+ * Log helper
307
+ */
308
+ private log;
309
+ }
310
+
311
+ interface WorkerEvents {
312
+ "execution:start": {
313
+ executionId: string;
314
+ workflowId: string;
315
+ eventName: string;
316
+ };
317
+ "execution:complete": {
318
+ executionId: string;
319
+ result: unknown;
320
+ };
321
+ "execution:failed": {
322
+ executionId: string;
323
+ error: Error;
324
+ willRetry: boolean;
325
+ };
326
+ "execution:sleeping": {
327
+ executionId: string;
328
+ wakeAt: Date;
329
+ };
330
+ "execution:waiting": {
331
+ executionId: string;
332
+ eventId: string;
333
+ timeoutAt: Date;
334
+ };
335
+ "execution:invoking": {
336
+ executionId: string;
337
+ childExecutionId: string;
338
+ childWorkflowId: string;
339
+ };
340
+ "step:complete": {
341
+ executionId: string;
342
+ stepName: string;
343
+ result: unknown;
344
+ };
345
+ "step:failed": {
346
+ executionId: string;
347
+ stepName: string;
348
+ error: Error;
349
+ };
350
+ error: {
351
+ error: Error;
352
+ };
353
+ }
354
+ interface WorkerOptions {
355
+ /**
356
+ * Storage adapter for persistence
357
+ */
358
+ storage: StorageAdapter;
359
+ /**
360
+ * Workflow registry
361
+ */
362
+ registry: WorkflowRegistry;
363
+ /**
364
+ * Number of concurrent jobs to process
365
+ * @default 1
366
+ */
367
+ concurrency?: number;
368
+ /**
369
+ * Interval in ms to poll for jobs when queue is empty
370
+ * @default 1000
371
+ */
372
+ pollInterval?: number;
373
+ /**
374
+ * Worker ID (for debugging/logging)
375
+ */
376
+ workerId?: string;
377
+ /**
378
+ * Enable logging
379
+ * @default false
380
+ */
381
+ logging?: boolean;
382
+ }
383
+ declare class Worker extends EventEmitter {
384
+ private storage;
385
+ private registry;
386
+ private concurrency;
387
+ private pollInterval;
388
+ private workerId;
389
+ private logging;
390
+ private running;
391
+ private activeJobs;
392
+ private pollTimeout?;
393
+ constructor(options: WorkerOptions);
394
+ /**
395
+ * Start the worker
396
+ */
397
+ start(): Promise<void>;
398
+ /**
399
+ * Stop the worker gracefully
400
+ */
401
+ stop(): Promise<void>;
402
+ /**
403
+ * Poll for jobs
404
+ */
405
+ private poll;
406
+ /**
407
+ * Process a single job
408
+ */
409
+ private processJob;
410
+ /**
411
+ * Execute a workflow
412
+ */
413
+ private executeWorkflow;
414
+ /**
415
+ * Handle resume from sleep
416
+ */
417
+ private handleResume;
418
+ /**
419
+ * Handle event timeout
420
+ */
421
+ private handleTimeout;
422
+ /**
423
+ * Handle child workflow completion
424
+ */
425
+ private handleInvokeComplete;
426
+ /**
427
+ * Handle timeline events
428
+ */
429
+ private handleTimelineEvent;
430
+ /**
431
+ * Log helper
432
+ */
433
+ private log;
434
+ }
435
+
436
+ /**
437
+ * Parse a duration value to milliseconds
438
+ *
439
+ * Supports:
440
+ * - Number: treated as milliseconds
441
+ * - String: parsed with ms library (e.g., "1d", "2h", "30m", "10s", "500ms")
442
+ */
443
+ declare function parseDuration(duration: Duration): number;
444
+ /**
445
+ * Format milliseconds as a human-readable duration string
446
+ */
447
+ declare function formatDuration(ms: number): string;
448
+
449
+ interface TokenPayload {
450
+ runId: string;
451
+ executionId?: string;
452
+ exp: number;
453
+ }
454
+ /**
455
+ * Create a simple signed access token
456
+ */
457
+ declare function createAccessToken(data: {
458
+ runId: string;
459
+ executionId?: string;
460
+ }, secret: string, expirySeconds: number): string;
461
+ /**
462
+ * Verify and decode an access token
463
+ */
464
+ declare function verifyAccessToken(token: string, secret: string): TokenPayload | null;
465
+
466
+ export { type CreateContextOptions, type CreateWorkflowOptions, Duration, Execution, InvokeInterrupt, InvokeOptions, ListOptions, type LogContext, NotifyResult, SleepInterrupt, type StepContext, StepOptions, StepTimeoutError, Stepflow, type StepflowOptions, TimelineEvent, Trigger, TriggerResult, WaitForEventInterrupt, WaitForEventOptions, WaitForEventResult, Worker, type WorkerEvents, type WorkerOptions, WorkflowConfig, type WorkflowContext, type WorkflowDefinition, WorkflowEvent, type WorkflowHandler, WorkflowRegistry, createAccessToken, createContext, createWorkflow, formatDuration, parseDuration, verifyAccessToken };