@multiplier-labs/stepflow 0.3.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.
- package/.github/workflows/publish.yml +30 -0
- package/README.md +408 -0
- package/dist/chunk-FQCT3I2A.js +1512 -0
- package/dist/chunk-FQCT3I2A.js.map +1 -0
- package/dist/chunk-GXY66V7Q.js +111 -0
- package/dist/chunk-GXY66V7Q.js.map +1 -0
- package/dist/chunk-U5QGN3RT.js +715 -0
- package/dist/chunk-U5QGN3RT.js.map +1 -0
- package/dist/chunk-XCF4PLN7.js +575 -0
- package/dist/chunk-XCF4PLN7.js.map +1 -0
- package/dist/events/index.d.ts +346 -0
- package/dist/events/index.js +11 -0
- package/dist/events/index.js.map +1 -0
- package/dist/index-CPfGsmrp.d.ts +567 -0
- package/dist/index.d.ts +748 -0
- package/dist/index.js +1707 -0
- package/dist/index.js.map +1 -0
- package/dist/scheduler/index.d.ts +6 -0
- package/dist/scheduler/index.js +12 -0
- package/dist/scheduler/index.js.map +1 -0
- package/dist/storage/index.d.ts +402 -0
- package/dist/storage/index.js +13 -0
- package/dist/storage/index.js.map +1 -0
- package/dist/types-BVShq7zT.d.ts +150 -0
- package/dist/types-BlwFEGzj.d.ts +276 -0
- package/dist/types-DzkEqnQJ.d.ts +75 -0
- package/docs/github-packages-setup.md +97 -0
- package/docs/stepflow-api-reference.md +1662 -0
- package/package.json +85 -0
- package/src/core/engine.test.ts +1421 -0
- package/src/core/engine.ts +717 -0
- package/src/core/index.ts +7 -0
- package/src/core/orchestrator.ts +590 -0
- package/src/core/types.ts +242 -0
- package/src/events/index.ts +8 -0
- package/src/events/memory.test.ts +109 -0
- package/src/events/memory.ts +95 -0
- package/src/events/socketio.test.ts +428 -0
- package/src/events/socketio.ts +269 -0
- package/src/events/types.ts +121 -0
- package/src/events/webhook.test.ts +695 -0
- package/src/events/webhook.ts +591 -0
- package/src/index.ts +270 -0
- package/src/planning/index.ts +52 -0
- package/src/planning/planner.ts +601 -0
- package/src/planning/planning.test.ts +790 -0
- package/src/planning/registry.test.ts +445 -0
- package/src/planning/registry.ts +369 -0
- package/src/planning/types.ts +570 -0
- package/src/scheduler/cron.test.ts +480 -0
- package/src/scheduler/cron.ts +449 -0
- package/src/scheduler/index.ts +18 -0
- package/src/scheduler/postgres-persistence.test.ts +906 -0
- package/src/scheduler/postgres-persistence.ts +546 -0
- package/src/scheduler/sqlite-persistence.test.ts +235 -0
- package/src/scheduler/sqlite-persistence.ts +268 -0
- package/src/scheduler/types.ts +78 -0
- package/src/storage/index.ts +27 -0
- package/src/storage/memory.test.ts +399 -0
- package/src/storage/memory.ts +248 -0
- package/src/storage/postgres.ts +1550 -0
- package/src/storage/sqlite.test.ts +593 -0
- package/src/storage/sqlite.ts +662 -0
- package/src/storage/types.ts +368 -0
- package/src/utils/errors.test.ts +152 -0
- package/src/utils/errors.ts +191 -0
- package/src/utils/id.ts +21 -0
- package/src/utils/index.ts +8 -0
- package/src/utils/logger.test.ts +127 -0
- package/src/utils/logger.ts +96 -0
- package/src/utils/postgres-deps.ts +63 -0
- package/src/utils/retry.test.ts +197 -0
- package/src/utils/retry.ts +121 -0
- package/tsconfig.json +21 -0
- package/tsup.config.ts +14 -0
- package/vitest.config.ts +9 -0
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
import { a as EventTransport, W as WorkflowEvent, E as EventCallback, U as Unsubscribe, b as WorkflowEventType } from '../types-DzkEqnQJ.js';
|
|
2
|
+
export { B as BuiltInEventType } from '../types-DzkEqnQJ.js';
|
|
3
|
+
import { L as Logger } from '../types-BVShq7zT.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* In-memory event transport using Node.js EventEmitter.
|
|
7
|
+
* Default transport for development and single-process deployments.
|
|
8
|
+
*
|
|
9
|
+
* NOTE: This adapter is intended for development and testing only. It stores
|
|
10
|
+
* all state in-process with no persistence or multi-process safety guarantees.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* In-memory event transport implementation using EventEmitter.
|
|
15
|
+
* Events are emitted to subscribers in the same process.
|
|
16
|
+
*/
|
|
17
|
+
declare class MemoryEventTransport implements EventTransport {
|
|
18
|
+
private emitter;
|
|
19
|
+
constructor();
|
|
20
|
+
/**
|
|
21
|
+
* Emit an event to all subscribers.
|
|
22
|
+
*/
|
|
23
|
+
emit(event: WorkflowEvent): void;
|
|
24
|
+
/**
|
|
25
|
+
* Subscribe to events for a specific run.
|
|
26
|
+
*/
|
|
27
|
+
subscribe(runId: string, callback: EventCallback): Unsubscribe;
|
|
28
|
+
/**
|
|
29
|
+
* Subscribe to all events.
|
|
30
|
+
*/
|
|
31
|
+
subscribeAll(callback: EventCallback): Unsubscribe;
|
|
32
|
+
/**
|
|
33
|
+
* Subscribe to events of a specific type.
|
|
34
|
+
*/
|
|
35
|
+
subscribeToType(eventType: WorkflowEventType, callback: EventCallback): Unsubscribe;
|
|
36
|
+
/**
|
|
37
|
+
* Close the transport and remove all listeners.
|
|
38
|
+
*/
|
|
39
|
+
close(): void;
|
|
40
|
+
/**
|
|
41
|
+
* Get the number of listeners for a channel (for testing).
|
|
42
|
+
*/
|
|
43
|
+
getListenerCount(channel?: string): number;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Socket.IO Event Transport
|
|
48
|
+
*
|
|
49
|
+
* Broadcasts workflow events to connected clients via Socket.IO.
|
|
50
|
+
* Clients can subscribe to specific run IDs or receive all events.
|
|
51
|
+
*/
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Minimal Socket.IO Server interface.
|
|
55
|
+
* This allows using the adapter without a direct dependency on socket.io.
|
|
56
|
+
*/
|
|
57
|
+
interface SocketIOServer {
|
|
58
|
+
to(room: string): {
|
|
59
|
+
emit(event: string, ...args: unknown[]): void;
|
|
60
|
+
};
|
|
61
|
+
emit(event: string, ...args: unknown[]): void;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Minimal Socket.IO Socket interface.
|
|
65
|
+
*/
|
|
66
|
+
interface SocketIOSocket {
|
|
67
|
+
join(room: string): void;
|
|
68
|
+
leave(room: string): void;
|
|
69
|
+
on(event: string, callback: (...args: unknown[]) => void): void;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Authorization callback for Socket.IO run subscriptions.
|
|
73
|
+
* Return true to allow the subscription, false to deny it.
|
|
74
|
+
*/
|
|
75
|
+
type SocketIOAuthorizeFn = (runId: string, socket: SocketIOSocket) => boolean | Promise<boolean>;
|
|
76
|
+
/**
|
|
77
|
+
* Configuration for SocketIOEventTransport.
|
|
78
|
+
*/
|
|
79
|
+
interface SocketIOEventTransportConfig {
|
|
80
|
+
/** Socket.IO server instance */
|
|
81
|
+
io: SocketIOServer;
|
|
82
|
+
/** Event name to use for workflow events (default: 'workflow:event') */
|
|
83
|
+
eventName?: string;
|
|
84
|
+
/** Room prefix for run-specific subscriptions (default: 'run:') */
|
|
85
|
+
roomPrefix?: string;
|
|
86
|
+
/** Whether to also broadcast to a global room (default: true) */
|
|
87
|
+
broadcastGlobal?: boolean;
|
|
88
|
+
/** Global room name (default: 'workflow:all') */
|
|
89
|
+
globalRoom?: string;
|
|
90
|
+
/** Logger for transport errors (default: console-based) */
|
|
91
|
+
logger?: Logger;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Socket.IO-based event transport for real-time workflow events.
|
|
95
|
+
*
|
|
96
|
+
* @example
|
|
97
|
+
* ```typescript
|
|
98
|
+
* import { Server } from 'socket.io';
|
|
99
|
+
* import { SocketIOEventTransport } from 'stepflow';
|
|
100
|
+
*
|
|
101
|
+
* const io = new Server(httpServer);
|
|
102
|
+
* const eventTransport = new SocketIOEventTransport({ io });
|
|
103
|
+
*
|
|
104
|
+
* const engine = new WorkflowEngine({
|
|
105
|
+
* storage,
|
|
106
|
+
* events: eventTransport,
|
|
107
|
+
* });
|
|
108
|
+
*
|
|
109
|
+
* // Client-side:
|
|
110
|
+
* // socket.emit('workflow:subscribe', runId);
|
|
111
|
+
* // socket.on('workflow:event', (event) => console.log(event));
|
|
112
|
+
* ```
|
|
113
|
+
*/
|
|
114
|
+
declare class SocketIOEventTransport implements EventTransport {
|
|
115
|
+
private io;
|
|
116
|
+
private eventName;
|
|
117
|
+
private roomPrefix;
|
|
118
|
+
private broadcastGlobal;
|
|
119
|
+
private globalRoom;
|
|
120
|
+
private logger;
|
|
121
|
+
private runSubscribers;
|
|
122
|
+
private globalSubscribers;
|
|
123
|
+
constructor(config: SocketIOEventTransportConfig);
|
|
124
|
+
/**
|
|
125
|
+
* Emit an event to Socket.IO clients and local subscribers.
|
|
126
|
+
*/
|
|
127
|
+
emit(event: WorkflowEvent): void;
|
|
128
|
+
/**
|
|
129
|
+
* Subscribe to events for a specific run (server-side).
|
|
130
|
+
*/
|
|
131
|
+
subscribe(runId: string, callback: EventCallback): Unsubscribe;
|
|
132
|
+
/**
|
|
133
|
+
* Subscribe to all events (server-side).
|
|
134
|
+
*/
|
|
135
|
+
subscribeAll(callback: EventCallback): Unsubscribe;
|
|
136
|
+
/**
|
|
137
|
+
* Set up client subscription handlers on a socket.
|
|
138
|
+
* Call this when a client connects to enable subscription commands.
|
|
139
|
+
*
|
|
140
|
+
* An `authorize` callback is required to prevent unauthorized access to run events.
|
|
141
|
+
* The callback receives the run ID (or `'*'` for global subscriptions) and the socket,
|
|
142
|
+
* and must return `true` to allow or `false` to deny the subscription.
|
|
143
|
+
*
|
|
144
|
+
* @param socket - The Socket.IO socket to set up handlers on
|
|
145
|
+
* @param authorize - Callback to check if a socket can access a run.
|
|
146
|
+
*
|
|
147
|
+
* @example
|
|
148
|
+
* ```typescript
|
|
149
|
+
* io.on('connection', (socket) => {
|
|
150
|
+
* eventTransport.setupClientHandlers(socket, async (runId, sock) => {
|
|
151
|
+
* // Check if the authenticated user owns this run
|
|
152
|
+
* const userId = sock.data?.userId;
|
|
153
|
+
* return userId ? await canUserAccessRun(userId, runId) : false;
|
|
154
|
+
* });
|
|
155
|
+
* });
|
|
156
|
+
* ```
|
|
157
|
+
*/
|
|
158
|
+
setupClientHandlers(socket: SocketIOSocket, authorize: SocketIOAuthorizeFn): void;
|
|
159
|
+
/**
|
|
160
|
+
* Clear all in-process server-side subscribers.
|
|
161
|
+
* The underlying Socket.IO server socket is not closed here — manage its lifecycle externally.
|
|
162
|
+
*/
|
|
163
|
+
close(): void;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Webhook endpoint configuration.
|
|
168
|
+
*/
|
|
169
|
+
interface WebhookEndpoint {
|
|
170
|
+
/** Unique identifier for this endpoint */
|
|
171
|
+
id: string;
|
|
172
|
+
/** URL to POST events to */
|
|
173
|
+
url: string;
|
|
174
|
+
/** Optional secret for signing payloads (HMAC-SHA256) */
|
|
175
|
+
secret?: string;
|
|
176
|
+
/** Optional filter for specific event types (empty = all events) */
|
|
177
|
+
eventTypes?: WorkflowEventType[];
|
|
178
|
+
/** Optional filter for specific workflow kinds (empty = all kinds) */
|
|
179
|
+
workflowKinds?: string[];
|
|
180
|
+
/** Optional custom headers to include */
|
|
181
|
+
headers?: Record<string, string>;
|
|
182
|
+
/** Whether this endpoint is enabled (default: true) */
|
|
183
|
+
enabled?: boolean;
|
|
184
|
+
/** Timeout in milliseconds (default: 5000) */
|
|
185
|
+
timeout?: number;
|
|
186
|
+
/** Number of retry attempts on failure (default: 3) */
|
|
187
|
+
retries?: number;
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Configuration for WebhookEventTransport.
|
|
191
|
+
*/
|
|
192
|
+
interface WebhookEventTransportConfig {
|
|
193
|
+
/** Initial webhook endpoints */
|
|
194
|
+
endpoints?: WebhookEndpoint[];
|
|
195
|
+
/** Default timeout for all webhooks in ms (default: 5000) */
|
|
196
|
+
defaultTimeout?: number;
|
|
197
|
+
/** Default retry attempts (default: 3) */
|
|
198
|
+
defaultRetries?: number;
|
|
199
|
+
/** Retry delay in ms (default: 1000) */
|
|
200
|
+
retryDelay?: number;
|
|
201
|
+
/** Custom fetch function (for testing or custom HTTP clients) */
|
|
202
|
+
fetchFn?: typeof fetch;
|
|
203
|
+
/**
|
|
204
|
+
* Whether to allow non-HTTPS URLs (default: false).
|
|
205
|
+
* Set to true only in development environments.
|
|
206
|
+
*/
|
|
207
|
+
allowInsecureUrls?: boolean;
|
|
208
|
+
/**
|
|
209
|
+
* Maximum payload size in bytes (default: 1048576 = 1 MB).
|
|
210
|
+
* Payloads exceeding this limit will be rejected.
|
|
211
|
+
*/
|
|
212
|
+
maxPayloadBytes?: number;
|
|
213
|
+
/**
|
|
214
|
+
* Maximum concurrent webhook requests across all endpoints (default: 50).
|
|
215
|
+
* Requests beyond this limit are queued.
|
|
216
|
+
*/
|
|
217
|
+
maxConcurrentRequests?: number;
|
|
218
|
+
/** Logger for webhook transport errors (default: console-based) */
|
|
219
|
+
logger?: Logger;
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Webhook payload structure sent to external endpoints.
|
|
223
|
+
*/
|
|
224
|
+
interface WebhookPayload {
|
|
225
|
+
/**
|
|
226
|
+
* The workflow event with `timestamp` serialized as an ISO 8601 string.
|
|
227
|
+
* The `Date` is converted to a string before delivery so that JSON consumers
|
|
228
|
+
* receive a portable, timezone-aware representation without needing Date parsing.
|
|
229
|
+
*/
|
|
230
|
+
event: Omit<WorkflowEvent, "timestamp"> & {
|
|
231
|
+
timestamp: string;
|
|
232
|
+
};
|
|
233
|
+
/** ISO 8601 timestamp of when this payload was delivered. */
|
|
234
|
+
deliveredAt: string;
|
|
235
|
+
/** ID of the webhook endpoint that received this delivery. */
|
|
236
|
+
webhookId: string;
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Webhook-based event transport for integrating with external systems.
|
|
240
|
+
*
|
|
241
|
+
* @example
|
|
242
|
+
* ```typescript
|
|
243
|
+
* const webhookTransport = new WebhookEventTransport({
|
|
244
|
+
* endpoints: [
|
|
245
|
+
* {
|
|
246
|
+
* id: 'slack-notifications',
|
|
247
|
+
* url: 'https://hooks.slack.com/...',
|
|
248
|
+
* eventTypes: ['run.completed', 'run.failed'],
|
|
249
|
+
* },
|
|
250
|
+
* {
|
|
251
|
+
* id: 'analytics',
|
|
252
|
+
* url: 'https://api.analytics.com/events',
|
|
253
|
+
* secret: process.env.WEBHOOK_SECRET, // Use a cryptographically random secret (≥ 32 bytes)
|
|
254
|
+
* },
|
|
255
|
+
* ],
|
|
256
|
+
* });
|
|
257
|
+
*
|
|
258
|
+
* const engine = new WorkflowEngine({
|
|
259
|
+
* storage,
|
|
260
|
+
* events: webhookTransport,
|
|
261
|
+
* });
|
|
262
|
+
* ```
|
|
263
|
+
*/
|
|
264
|
+
declare class WebhookEventTransport implements EventTransport {
|
|
265
|
+
private endpoints;
|
|
266
|
+
private defaultTimeout;
|
|
267
|
+
private defaultRetries;
|
|
268
|
+
private retryDelay;
|
|
269
|
+
private fetchFn;
|
|
270
|
+
private allowInsecureUrls;
|
|
271
|
+
private maxPayloadBytes;
|
|
272
|
+
private maxConcurrentRequests;
|
|
273
|
+
private activeRequests;
|
|
274
|
+
private requestQueue;
|
|
275
|
+
private logger;
|
|
276
|
+
private runSubscribers;
|
|
277
|
+
private globalSubscribers;
|
|
278
|
+
constructor(config?: WebhookEventTransportConfig);
|
|
279
|
+
/**
|
|
280
|
+
* Add a webhook endpoint.
|
|
281
|
+
* Validates the URL to prevent SSRF attacks.
|
|
282
|
+
* @throws Error if the URL scheme is not allowed
|
|
283
|
+
*/
|
|
284
|
+
addEndpoint(endpoint: WebhookEndpoint): void;
|
|
285
|
+
/**
|
|
286
|
+
* Remove a webhook endpoint.
|
|
287
|
+
*/
|
|
288
|
+
removeEndpoint(id: string): boolean;
|
|
289
|
+
/**
|
|
290
|
+
* Get all registered endpoints.
|
|
291
|
+
*/
|
|
292
|
+
getEndpoints(): WebhookEndpoint[];
|
|
293
|
+
/**
|
|
294
|
+
* Enable or disable an endpoint.
|
|
295
|
+
*/
|
|
296
|
+
setEndpointEnabled(id: string, enabled: boolean): void;
|
|
297
|
+
/**
|
|
298
|
+
* Emit an event to all matching webhook endpoints.
|
|
299
|
+
*/
|
|
300
|
+
emit(event: WorkflowEvent): void;
|
|
301
|
+
/**
|
|
302
|
+
* Subscribe to events for a specific run (server-side).
|
|
303
|
+
*/
|
|
304
|
+
subscribe(runId: string, callback: EventCallback): Unsubscribe;
|
|
305
|
+
/**
|
|
306
|
+
* Subscribe to all events (server-side).
|
|
307
|
+
*/
|
|
308
|
+
subscribeAll(callback: EventCallback): Unsubscribe;
|
|
309
|
+
/**
|
|
310
|
+
* Close the transport.
|
|
311
|
+
*/
|
|
312
|
+
close(): void;
|
|
313
|
+
/**
|
|
314
|
+
* Check if an event matches an endpoint's filters.
|
|
315
|
+
*/
|
|
316
|
+
private matchesFilter;
|
|
317
|
+
/**
|
|
318
|
+
* Send a webhook with retry support.
|
|
319
|
+
*/
|
|
320
|
+
private sendWebhook;
|
|
321
|
+
/**
|
|
322
|
+
* Sign a payload using HMAC-SHA256.
|
|
323
|
+
*/
|
|
324
|
+
private signPayload;
|
|
325
|
+
/**
|
|
326
|
+
* Sleep helper.
|
|
327
|
+
*/
|
|
328
|
+
private sleep;
|
|
329
|
+
/**
|
|
330
|
+
* Resolve the hostname from a URL and verify the resolved IP is not private/reserved.
|
|
331
|
+
* Prevents DNS rebinding attacks where a public hostname resolves to a private IP at send time.
|
|
332
|
+
*/
|
|
333
|
+
private validateResolvedHost;
|
|
334
|
+
/**
|
|
335
|
+
* Validate a webhook URL to prevent SSRF attacks.
|
|
336
|
+
* Blocks non-HTTPS schemes (unless allowInsecureUrls is set),
|
|
337
|
+
* and rejects private/reserved IP ranges and cloud metadata endpoints.
|
|
338
|
+
*/
|
|
339
|
+
private validateWebhookUrl;
|
|
340
|
+
/**
|
|
341
|
+
* Enqueue a webhook request with concurrency limiting.
|
|
342
|
+
*/
|
|
343
|
+
private enqueueRequest;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
export { EventCallback, EventTransport, MemoryEventTransport, type SocketIOAuthorizeFn, SocketIOEventTransport, type SocketIOEventTransportConfig, type SocketIOServer, type SocketIOSocket, Unsubscribe, type WebhookEndpoint, WebhookEventTransport, type WebhookEventTransportConfig, type WebhookPayload, WorkflowEvent, WorkflowEventType };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|