@multiplier-labs/stepflow 0.3.4 → 0.3.8

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.
Files changed (109) hide show
  1. package/README.md +9 -0
  2. package/dist/{chunk-5XJBAPXF.js → chunk-4IDPWWGS.js} +15 -4
  3. package/dist/chunk-4IDPWWGS.js.map +1 -0
  4. package/dist/{chunk-U3PCVK6O.js → chunk-T6GAZBTQ.js} +70 -38
  5. package/dist/chunk-T6GAZBTQ.js.map +1 -0
  6. package/dist/{chunk-FMPJBK2N.js → chunk-TVSADUYU.js} +3 -5
  7. package/dist/{chunk-FMPJBK2N.js.map → chunk-TVSADUYU.js.map} +1 -1
  8. package/dist/events/index.d.ts +43 -3
  9. package/dist/events/index.js +7 -3
  10. package/dist/{index-Cd0IZ40L.d.ts → index-CdXDv30T.d.ts} +10 -2
  11. package/dist/index.d.ts +5 -4
  12. package/dist/index.js +159 -46
  13. package/dist/index.js.map +1 -1
  14. package/dist/scheduler/index.d.ts +2 -2
  15. package/dist/scheduler/index.js +1 -1
  16. package/dist/storage/index.d.ts +6 -4
  17. package/dist/storage/index.js +1 -1
  18. package/dist/{types-DSEjiLMj.d.ts → types-BfWe5yP6.d.ts} +2 -0
  19. package/package.json +26 -14
  20. package/.codekin/reports/code-review/2026-04-11_code-review-daily.md +0 -146
  21. package/.codekin/reports/code-review/2026-04-13_code-review-daily.md +0 -74
  22. package/.codekin/reports/comments/2026-04-04_comment-assessment.md +0 -179
  23. package/.codekin/reports/comments/2026-04-11_comment-assessment.md +0 -161
  24. package/.codekin/reports/comments/2026-04-14_comment-assessment.md +0 -34
  25. package/.codekin/reports/complexity/2026-04-03_complexity-report.md +0 -152
  26. package/.codekin/reports/complexity/2026-04-11_complexity-report.md +0 -152
  27. package/.codekin/reports/complexity/2026-04-14_complexity-report.md +0 -34
  28. package/.codekin/reports/dependencies/2026-04-04_dependency-health.md +0 -94
  29. package/.codekin/reports/dependencies/2026-04-11_dependency-health.md +0 -93
  30. package/.codekin/reports/docs-audit/2026-04-04_docs-audit.md +0 -10
  31. package/.codekin/reports/docs-audit/2026-04-11_docs-audit.md +0 -138
  32. package/.codekin/reports/docs-audit/2026-04-13_docs-audit.md +0 -121
  33. package/.codekin/reports/security/2026-04-03_security-audit.md +0 -208
  34. package/.codekin/reports/security/2026-04-11_security-audit.md +0 -297
  35. package/.github/CODEOWNERS +0 -15
  36. package/.github/dependabot.yml +0 -23
  37. package/.github/workflows/ci.yml +0 -38
  38. package/.github/workflows/publish.yml +0 -42
  39. package/.github/workflows/security.yml +0 -29
  40. package/CHANGELOG.md +0 -34
  41. package/SECURITY.md +0 -40
  42. package/dist/chunk-5XJBAPXF.js.map +0 -1
  43. package/dist/chunk-U3PCVK6O.js.map +0 -1
  44. package/docs/github-packages-setup.md +0 -97
  45. package/docs/stepflow-api-reference.md +0 -1663
  46. package/src/core/engine/concurrency.ts +0 -229
  47. package/src/core/engine/lifecycle.ts +0 -176
  48. package/src/core/engine.test.ts +0 -1435
  49. package/src/core/engine.ts +0 -598
  50. package/src/core/index.ts +0 -7
  51. package/src/core/orchestrator/persistence.ts +0 -165
  52. package/src/core/orchestrator/plan-resolution.ts +0 -140
  53. package/src/core/orchestrator/state-transitions.ts +0 -109
  54. package/src/core/orchestrator/step-runner.ts +0 -427
  55. package/src/core/orchestrator.ts +0 -252
  56. package/src/core/types.ts +0 -220
  57. package/src/events/index.ts +0 -8
  58. package/src/events/memory.test.ts +0 -107
  59. package/src/events/memory.ts +0 -92
  60. package/src/events/socketio.test.ts +0 -378
  61. package/src/events/socketio.ts +0 -262
  62. package/src/events/types.ts +0 -118
  63. package/src/events/webhook.test.ts +0 -949
  64. package/src/events/webhook.ts +0 -807
  65. package/src/index.ts +0 -270
  66. package/src/planning/evaluate-condition.test.ts +0 -153
  67. package/src/planning/evaluate-condition.ts +0 -105
  68. package/src/planning/index.ts +0 -55
  69. package/src/planning/planner.ts +0 -494
  70. package/src/planning/planning.test.ts +0 -727
  71. package/src/planning/registry.test.ts +0 -398
  72. package/src/planning/registry.ts +0 -283
  73. package/src/planning/types.ts +0 -566
  74. package/src/scheduler/cron.test.ts +0 -479
  75. package/src/scheduler/cron.ts +0 -438
  76. package/src/scheduler/index.ts +0 -8
  77. package/src/scheduler/postgres-persistence.ts +0 -530
  78. package/src/scheduler/sqlite-persistence.test.ts +0 -235
  79. package/src/scheduler/sqlite-persistence.ts +0 -286
  80. package/src/scheduler/types.ts +0 -73
  81. package/src/storage/index.ts +0 -27
  82. package/src/storage/memory.test.ts +0 -349
  83. package/src/storage/memory.ts +0 -227
  84. package/src/storage/postgres-core.ts +0 -550
  85. package/src/storage/postgres-migration.test.ts +0 -69
  86. package/src/storage/postgres-transaction-pagination.test.ts +0 -107
  87. package/src/storage/postgres.ts +0 -835
  88. package/src/storage/sqlite-core.ts +0 -151
  89. package/src/storage/sqlite.test.ts +0 -642
  90. package/src/storage/sqlite.ts +0 -717
  91. package/src/storage/types.ts +0 -343
  92. package/src/utils/errors.test.ts +0 -150
  93. package/src/utils/errors.ts +0 -161
  94. package/src/utils/id.ts +0 -21
  95. package/src/utils/index.ts +0 -10
  96. package/src/utils/logger.test.ts +0 -121
  97. package/src/utils/logger.ts +0 -96
  98. package/src/utils/pinned-fetch.test.ts +0 -84
  99. package/src/utils/pinned-fetch.ts +0 -118
  100. package/src/utils/postgres-deps.ts +0 -79
  101. package/src/utils/retry.test.ts +0 -177
  102. package/src/utils/retry.ts +0 -121
  103. package/src/utils/safe-json.test.ts +0 -166
  104. package/src/utils/safe-json.ts +0 -107
  105. package/src/utils/webhook-signature.test.ts +0 -111
  106. package/src/utils/webhook-signature.ts +0 -74
  107. package/tsconfig.json +0 -21
  108. package/tsup.config.ts +0 -14
  109. package/vitest.config.ts +0 -9
package/src/core/types.ts DELETED
@@ -1,220 +0,0 @@
1
- /**
2
- * Core types for the workflow engine.
3
- * These are the foundational interfaces used throughout the system.
4
- */
5
-
6
- // ============================================================================
7
- // Basic Types
8
- // ============================================================================
9
-
10
- /**
11
- * Unique identifier for a workflow type.
12
- * Used to register and look up workflow definitions.
13
- */
14
- export type WorkflowKind = string;
15
-
16
- /**
17
- * Status of a workflow run.
18
- */
19
- export type RunStatus = 'queued' | 'running' | 'succeeded' | 'failed' | 'canceled';
20
-
21
- /**
22
- * Status of a workflow step.
23
- */
24
- export type StepStatus = 'pending' | 'running' | 'succeeded' | 'failed' | 'skipped' | 'canceled';
25
-
26
- /**
27
- * Error handling strategy for a step.
28
- * - 'fail': Stop the workflow immediately
29
- * - 'retry': Retry the step up to maxRetries times
30
- * - 'skip': Mark as skipped and continue to next step
31
- */
32
- export type StepErrorStrategy = 'fail' | 'retry' | 'skip';
33
-
34
- // ============================================================================
35
- // Error Types
36
- // ============================================================================
37
-
38
- /**
39
- * Structured error information stored with runs and steps.
40
- */
41
- export interface WorkflowError {
42
- code: string;
43
- message: string;
44
- stack?: string;
45
- details?: Record<string, unknown>;
46
- }
47
-
48
- /**
49
- * Result of a completed workflow run.
50
- */
51
- export interface RunResult {
52
- status: 'succeeded' | 'failed' | 'canceled';
53
- results: Record<string, unknown>;
54
- error?: WorkflowError;
55
- duration: number;
56
- }
57
-
58
- // ============================================================================
59
- // Logger Interface
60
- // ============================================================================
61
-
62
- /**
63
- * Minimal logger interface that consumers can implement.
64
- * Compatible with console, pino, winston, etc.
65
- */
66
- export interface Logger {
67
- debug(message: string, ...args: unknown[]): void;
68
- info(message: string, ...args: unknown[]): void;
69
- warn(message: string, ...args: unknown[]): void;
70
- error(message: string, ...args: unknown[]): void;
71
- }
72
-
73
- // ============================================================================
74
- // Spawn Child Options
75
- // ============================================================================
76
-
77
- /**
78
- * Options for spawning a child workflow from within a step handler.
79
- */
80
- export interface SpawnChildOptions {
81
- kind: WorkflowKind;
82
- input?: Record<string, unknown>;
83
- metadata?: Record<string, unknown>;
84
- }
85
-
86
- // ============================================================================
87
- // Workflow Context
88
- // ============================================================================
89
-
90
- /**
91
- * Runtime context passed to each step handler.
92
- * Contains all information a step needs to execute and interact with the engine.
93
- */
94
- export interface WorkflowContext<TInput = Record<string, unknown>> {
95
- /** Unique run identifier */
96
- runId: string;
97
-
98
- /** Current step identifier (for granular tracking, e.g., token usage) */
99
- stepId: string;
100
-
101
- /** Workflow type */
102
- kind: WorkflowKind;
103
-
104
- /** Input parameters passed when starting the run */
105
- input: TInput;
106
-
107
- /** Accumulated results from previous steps (keyed by step key) */
108
- results: Record<string, unknown>;
109
-
110
- /** Optional metadata (topicId, userId, etc.) */
111
- metadata: Record<string, unknown>;
112
-
113
- /** Current step key (set during execution) */
114
- currentStep?: string;
115
-
116
- /** Logger instance scoped to this run */
117
- logger: Logger;
118
-
119
- /** Abort signal for cancellation */
120
- signal: AbortSignal;
121
-
122
- /** Helper to spawn child workflows */
123
- spawnChild: (options: SpawnChildOptions) => Promise<string>;
124
-
125
- /** Helper to emit custom events */
126
- emit: (eventType: string, payload?: unknown) => void;
127
- }
128
-
129
- // ============================================================================
130
- // Workflow Step
131
- // ============================================================================
132
-
133
- /**
134
- * Definition of a single workflow step.
135
- * Steps are executed sequentially within a workflow.
136
- */
137
- export interface WorkflowStep<TInput = Record<string, unknown>> {
138
- /** Unique step identifier within the workflow */
139
- key: string;
140
-
141
- /** Human-readable step name */
142
- name: string;
143
-
144
- /** Async function that performs the step's work */
145
- handler: (ctx: WorkflowContext<TInput>) => Promise<unknown>;
146
-
147
- /** What to do when the step fails (default: 'fail') */
148
- onError?: StepErrorStrategy;
149
-
150
- /** Maximum retry attempts when onError is 'retry' @default 3 */
151
- maxRetries?: number;
152
-
153
- /** Delay between retries in ms @default 1000 */
154
- retryDelay?: number;
155
-
156
- /** Exponential backoff multiplier @default 2 */
157
- retryBackoff?: number;
158
-
159
- /** Timeout for this step in ms (optional) */
160
- timeout?: number;
161
-
162
- /** Condition to skip this step */
163
- skipIf?: (ctx: WorkflowContext<TInput>) => boolean | Promise<boolean>;
164
- }
165
-
166
- // ============================================================================
167
- // Workflow Hooks
168
- // ============================================================================
169
-
170
- /**
171
- * Lifecycle hooks for workflows.
172
- * Allow custom logic at key points in the workflow execution.
173
- */
174
- export interface WorkflowHooks<TInput = Record<string, unknown>> {
175
- /** Called before workflow starts */
176
- beforeRun?: (ctx: WorkflowContext<TInput>) => Promise<void>;
177
-
178
- /** Called after workflow completes (success or failure) */
179
- afterRun?: (ctx: WorkflowContext<TInput>, result: RunResult) => Promise<void>;
180
-
181
- /** Called before each step */
182
- beforeStep?: (ctx: WorkflowContext<TInput>, step: WorkflowStep<TInput>) => Promise<void>;
183
-
184
- /** Called after each step (success only) */
185
- afterStep?: (ctx: WorkflowContext<TInput>, step: WorkflowStep<TInput>, result: unknown) => Promise<void>;
186
-
187
- /** Called when a step fails */
188
- onStepError?: (ctx: WorkflowContext<TInput>, step: WorkflowStep<TInput>, error: Error) => Promise<void>;
189
- }
190
-
191
- // ============================================================================
192
- // Workflow Definition
193
- // ============================================================================
194
-
195
- /**
196
- * Complete workflow definition.
197
- * Registered with the engine to enable starting runs of this type.
198
- */
199
- export interface WorkflowDefinition<TInput = Record<string, unknown>> {
200
- /** Unique workflow type identifier */
201
- kind: WorkflowKind;
202
-
203
- /** Human-readable workflow name */
204
- name: string;
205
-
206
- /** Optional description */
207
- description?: string;
208
-
209
- /** Ordered list of steps to execute */
210
- steps: WorkflowStep<TInput>[];
211
-
212
- /** Default error strategy for all steps (default: 'fail') */
213
- defaultOnError?: StepErrorStrategy;
214
-
215
- /** Global timeout for the entire workflow in ms */
216
- timeout?: number;
217
-
218
- /** Hooks for workflow lifecycle */
219
- hooks?: WorkflowHooks<TInput>;
220
- }
@@ -1,8 +0,0 @@
1
- /**
2
- * Events module exports.
3
- */
4
-
5
- export * from './types';
6
- export * from './memory';
7
- export * from './socketio';
8
- export * from './webhook';
@@ -1,107 +0,0 @@
1
- import { describe, it, expect, beforeEach, vi } from 'vitest';
2
- import { MemoryEventTransport } from './memory';
3
- import type { WorkflowEvent, WorkflowEventType } from './types';
4
-
5
- function createTestEvent(overrides: Partial<WorkflowEvent> = {}): WorkflowEvent {
6
- return {
7
- eventType: 'run.started',
8
- runId: 'run-123',
9
- kind: 'test.workflow',
10
- timestamp: new Date('2024-01-01T12:00:00Z'),
11
- ...overrides,
12
- };
13
- }
14
-
15
- describe('MemoryEventTransport', () => {
16
- let transport: MemoryEventTransport;
17
-
18
- beforeEach(() => {
19
- transport = new MemoryEventTransport();
20
- });
21
-
22
- describe('subscribeToType', () => {
23
- it('should call callback when event of matching type is emitted', () => {
24
- const callback = vi.fn();
25
- transport.subscribeToType('run.completed', callback);
26
-
27
- const event = createTestEvent({ eventType: 'run.completed' });
28
- transport.emit(event);
29
-
30
- expect(callback).toHaveBeenCalledWith(event);
31
- });
32
-
33
- it('should not call callback for events of a different type', () => {
34
- const callback = vi.fn();
35
- transport.subscribeToType('run.completed', callback);
36
-
37
- transport.emit(createTestEvent({ eventType: 'run.started' }));
38
-
39
- expect(callback).not.toHaveBeenCalled();
40
- });
41
-
42
- it('should unsubscribe when calling the returned function', () => {
43
- const callback = vi.fn();
44
- const unsubscribe = transport.subscribeToType('run.completed', callback);
45
-
46
- // Emit once before unsubscribe
47
- transport.emit(createTestEvent({ eventType: 'run.completed' }));
48
- expect(callback).toHaveBeenCalledTimes(1);
49
-
50
- unsubscribe();
51
-
52
- // Emit again after unsubscribe
53
- transport.emit(createTestEvent({ eventType: 'run.completed' }));
54
- expect(callback).toHaveBeenCalledTimes(1);
55
- });
56
-
57
- it('should support multiple type subscriptions independently', () => {
58
- const completedCb = vi.fn();
59
- const failedCb = vi.fn();
60
- transport.subscribeToType('run.completed', completedCb);
61
- transport.subscribeToType('run.failed', failedCb);
62
-
63
- transport.emit(createTestEvent({ eventType: 'run.completed' }));
64
-
65
- expect(completedCb).toHaveBeenCalledTimes(1);
66
- expect(failedCb).not.toHaveBeenCalled();
67
- });
68
- });
69
-
70
- describe('getListenerCount', () => {
71
- it('should return 0 when no listeners are registered', () => {
72
- expect(transport.getListenerCount()).toBe(0);
73
- });
74
-
75
- it('should return global listener count when called without channel', () => {
76
- transport.subscribeAll(vi.fn());
77
- transport.subscribeAll(vi.fn());
78
-
79
- expect(transport.getListenerCount()).toBe(2);
80
- });
81
-
82
- it('should return channel-specific listener count when called with channel', () => {
83
- transport.subscribe('run-1', vi.fn());
84
- transport.subscribe('run-1', vi.fn());
85
- transport.subscribe('run-2', vi.fn());
86
-
87
- expect(transport.getListenerCount('run:run-1')).toBe(2);
88
- expect(transport.getListenerCount('run:run-2')).toBe(1);
89
- });
90
-
91
- it('should update count after subscribe and unsubscribe', () => {
92
- const unsub = transport.subscribeAll(vi.fn());
93
- expect(transport.getListenerCount()).toBe(1);
94
-
95
- unsub();
96
- expect(transport.getListenerCount()).toBe(0);
97
- });
98
-
99
- it('should return count for type-based channels', () => {
100
- transport.subscribeToType('step.completed', vi.fn());
101
- transport.subscribeToType('step.completed', vi.fn());
102
-
103
- expect(transport.getListenerCount('type:step.completed')).toBe(2);
104
- expect(transport.getListenerCount('type:step.failed')).toBe(0);
105
- });
106
- });
107
- });
@@ -1,92 +0,0 @@
1
- /**
2
- * In-memory event transport using Node.js EventEmitter.
3
- * Default transport for development and single-process deployments.
4
- *
5
- * NOTE: This adapter is intended for development and testing only. It stores
6
- * all state in-process with no persistence or multi-process safety guarantees.
7
- */
8
-
9
- import { EventEmitter } from 'events';
10
- import type {
11
- EventTransport,
12
- WorkflowEvent,
13
- WorkflowEventType,
14
- EventCallback,
15
- Unsubscribe,
16
- } from './types';
17
-
18
- /**
19
- * In-memory event transport implementation using EventEmitter.
20
- * Events are emitted to subscribers in the same process.
21
- */
22
- export class MemoryEventTransport implements EventTransport {
23
- private emitter = new EventEmitter();
24
-
25
- constructor() {
26
- // Increase max listeners to avoid warnings in workflows with many steps
27
- this.emitter.setMaxListeners(100);
28
- }
29
-
30
- /**
31
- * Emit an event to all subscribers.
32
- */
33
- emit(event: WorkflowEvent): void {
34
- // Emit to global subscribers
35
- this.emitter.emit('event', event);
36
-
37
- // Emit to run-specific subscribers
38
- this.emitter.emit(`run:${event.runId}`, event);
39
-
40
- // Emit to event-type subscribers
41
- this.emitter.emit(`type:${event.eventType}`, event);
42
- }
43
-
44
- /**
45
- * Subscribe to events for a specific run.
46
- */
47
- subscribe(runId: string, callback: EventCallback): Unsubscribe {
48
- const channel = `run:${runId}`;
49
- this.emitter.on(channel, callback);
50
- return () => {
51
- this.emitter.off(channel, callback);
52
- };
53
- }
54
-
55
- /**
56
- * Subscribe to all events.
57
- */
58
- subscribeAll(callback: EventCallback): Unsubscribe {
59
- this.emitter.on('event', callback);
60
- return () => {
61
- this.emitter.off('event', callback);
62
- };
63
- }
64
-
65
- /**
66
- * Subscribe to events of a specific type.
67
- */
68
- subscribeToType(eventType: WorkflowEventType, callback: EventCallback): Unsubscribe {
69
- const channel = `type:${eventType}`;
70
- this.emitter.on(channel, callback);
71
- return () => {
72
- this.emitter.off(channel, callback);
73
- };
74
- }
75
-
76
- /**
77
- * Close the transport and remove all listeners.
78
- */
79
- close(): void {
80
- this.emitter.removeAllListeners();
81
- }
82
-
83
- /**
84
- * Get the number of listeners for a channel (for testing).
85
- */
86
- getListenerCount(channel?: string): number {
87
- if (channel) {
88
- return this.emitter.listenerCount(channel);
89
- }
90
- return this.emitter.listenerCount('event');
91
- }
92
- }