@rivetkit/workflow-engine 2.1.0-rc.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/LICENSE +203 -0
- package/dist/schemas/v1.ts +781 -0
- package/dist/tsup/chunk-GJ66YE5W.cjs +3441 -0
- package/dist/tsup/chunk-GJ66YE5W.cjs.map +1 -0
- package/dist/tsup/chunk-JWHWQBZP.js +3441 -0
- package/dist/tsup/chunk-JWHWQBZP.js.map +1 -0
- package/dist/tsup/index.cjs +93 -0
- package/dist/tsup/index.cjs.map +1 -0
- package/dist/tsup/index.d.cts +884 -0
- package/dist/tsup/index.d.ts +884 -0
- package/dist/tsup/index.js +93 -0
- package/dist/tsup/index.js.map +1 -0
- package/dist/tsup/testing.cjs +316 -0
- package/dist/tsup/testing.cjs.map +1 -0
- package/dist/tsup/testing.d.cts +52 -0
- package/dist/tsup/testing.d.ts +52 -0
- package/dist/tsup/testing.js +316 -0
- package/dist/tsup/testing.js.map +1 -0
- package/package.json +70 -0
- package/schemas/serde.ts +609 -0
- package/schemas/v1.bare +203 -0
- package/schemas/versioned.ts +107 -0
- package/src/context.ts +1845 -0
- package/src/driver.ts +103 -0
- package/src/errors.ts +170 -0
- package/src/index.ts +907 -0
- package/src/keys.ts +277 -0
- package/src/location.ts +168 -0
- package/src/storage.ts +364 -0
- package/src/testing.ts +292 -0
- package/src/types.ts +508 -0
- package/src/utils.ts +48 -0
package/src/types.ts
ADDED
|
@@ -0,0 +1,508 @@
|
|
|
1
|
+
import type { Logger } from "pino";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Index into the entry name registry.
|
|
5
|
+
* Names are stored once and referenced by this index to avoid repetition.
|
|
6
|
+
*/
|
|
7
|
+
export type NameIndex = number;
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* A segment in a location path.
|
|
11
|
+
* Either a name index (for named entries) or a loop iteration marker.
|
|
12
|
+
*/
|
|
13
|
+
export type PathSegment = NameIndex | LoopIterationMarker;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Marker for a loop iteration in a location path.
|
|
17
|
+
*/
|
|
18
|
+
export interface LoopIterationMarker {
|
|
19
|
+
loop: NameIndex;
|
|
20
|
+
iteration: number;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Location identifies where an entry exists in the workflow execution tree.
|
|
25
|
+
* It forms a path from the root through loops, joins, and branches.
|
|
26
|
+
*/
|
|
27
|
+
export type Location = PathSegment[];
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Current state of a sleep entry.
|
|
31
|
+
*/
|
|
32
|
+
export type SleepState = "pending" | "completed" | "interrupted";
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Status of an entry in the workflow.
|
|
36
|
+
*/
|
|
37
|
+
export type EntryStatus =
|
|
38
|
+
| "pending"
|
|
39
|
+
| "running"
|
|
40
|
+
| "completed"
|
|
41
|
+
| "failed"
|
|
42
|
+
| "exhausted";
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Status of a branch in join/race.
|
|
46
|
+
*/
|
|
47
|
+
export type BranchStatusType =
|
|
48
|
+
| "pending"
|
|
49
|
+
| "running"
|
|
50
|
+
| "completed"
|
|
51
|
+
| "failed"
|
|
52
|
+
| "cancelled";
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Current state of the workflow.
|
|
56
|
+
*/
|
|
57
|
+
export type WorkflowState =
|
|
58
|
+
| "pending"
|
|
59
|
+
| "running"
|
|
60
|
+
| "sleeping"
|
|
61
|
+
| "failed"
|
|
62
|
+
| "completed"
|
|
63
|
+
| "cancelled"
|
|
64
|
+
| "rolling_back";
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Step entry data.
|
|
68
|
+
*/
|
|
69
|
+
export interface StepEntry {
|
|
70
|
+
output?: unknown;
|
|
71
|
+
error?: string;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Loop entry data.
|
|
76
|
+
*/
|
|
77
|
+
export interface LoopEntry {
|
|
78
|
+
state: unknown;
|
|
79
|
+
iteration: number;
|
|
80
|
+
output?: unknown;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Sleep entry data.
|
|
85
|
+
*/
|
|
86
|
+
export interface SleepEntry {
|
|
87
|
+
deadline: number;
|
|
88
|
+
state: SleepState;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Message entry data.
|
|
93
|
+
*/
|
|
94
|
+
export interface MessageEntry {
|
|
95
|
+
name: string;
|
|
96
|
+
data: unknown;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Rollback checkpoint entry data.
|
|
101
|
+
*/
|
|
102
|
+
export interface RollbackCheckpointEntry {
|
|
103
|
+
name: string;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Branch status for join/race entries.
|
|
108
|
+
*/
|
|
109
|
+
export interface BranchStatus {
|
|
110
|
+
status: BranchStatusType;
|
|
111
|
+
output?: unknown;
|
|
112
|
+
error?: string;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Join entry data.
|
|
117
|
+
*/
|
|
118
|
+
export interface JoinEntry {
|
|
119
|
+
branches: Record<string, BranchStatus>;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Race entry data.
|
|
124
|
+
*/
|
|
125
|
+
export interface RaceEntry {
|
|
126
|
+
winner: string | null;
|
|
127
|
+
branches: Record<string, BranchStatus>;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Removed entry data - placeholder for removed steps in workflow migrations.
|
|
132
|
+
*/
|
|
133
|
+
export interface RemovedEntry {
|
|
134
|
+
originalType: EntryKindType;
|
|
135
|
+
originalName?: string;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* All possible entry kind types.
|
|
140
|
+
*/
|
|
141
|
+
export type EntryKindType =
|
|
142
|
+
| "step"
|
|
143
|
+
| "loop"
|
|
144
|
+
| "sleep"
|
|
145
|
+
| "message"
|
|
146
|
+
| "rollback_checkpoint"
|
|
147
|
+
| "join"
|
|
148
|
+
| "race"
|
|
149
|
+
| "removed";
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Type-specific entry data.
|
|
153
|
+
*/
|
|
154
|
+
export type EntryKind =
|
|
155
|
+
| { type: "step"; data: StepEntry }
|
|
156
|
+
| { type: "loop"; data: LoopEntry }
|
|
157
|
+
| { type: "sleep"; data: SleepEntry }
|
|
158
|
+
| { type: "message"; data: MessageEntry }
|
|
159
|
+
| { type: "rollback_checkpoint"; data: RollbackCheckpointEntry }
|
|
160
|
+
| { type: "join"; data: JoinEntry }
|
|
161
|
+
| { type: "race"; data: RaceEntry }
|
|
162
|
+
| { type: "removed"; data: RemovedEntry };
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* An entry in the workflow history.
|
|
166
|
+
*/
|
|
167
|
+
export interface Entry {
|
|
168
|
+
id: string;
|
|
169
|
+
location: Location;
|
|
170
|
+
kind: EntryKind;
|
|
171
|
+
dirty: boolean;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Metadata for an entry (stored separately, lazily loaded).
|
|
176
|
+
*/
|
|
177
|
+
export interface EntryMetadata {
|
|
178
|
+
status: EntryStatus;
|
|
179
|
+
error?: string;
|
|
180
|
+
attempts: number;
|
|
181
|
+
lastAttemptAt: number;
|
|
182
|
+
createdAt: number;
|
|
183
|
+
completedAt?: number;
|
|
184
|
+
rollbackCompletedAt?: number;
|
|
185
|
+
rollbackError?: string;
|
|
186
|
+
dirty: boolean;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* A message in the queue.
|
|
191
|
+
*/
|
|
192
|
+
export interface Message {
|
|
193
|
+
/** Unique message ID. */
|
|
194
|
+
id: string;
|
|
195
|
+
name: string;
|
|
196
|
+
data: unknown;
|
|
197
|
+
sentAt: number;
|
|
198
|
+
/**
|
|
199
|
+
* Optional completion callback for queue-backed drivers.
|
|
200
|
+
*
|
|
201
|
+
* This is runtime-only and is not persisted.
|
|
202
|
+
*/
|
|
203
|
+
complete?: (response?: unknown) => Promise<void>;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Options for receiving queue messages in workflows.
|
|
208
|
+
*/
|
|
209
|
+
export interface WorkflowQueueNextOptions {
|
|
210
|
+
/**
|
|
211
|
+
* Queue names to receive from.
|
|
212
|
+
* If omitted, receives from all queue names.
|
|
213
|
+
*/
|
|
214
|
+
names?: readonly string[];
|
|
215
|
+
/** Maximum number of messages to receive. Defaults to 1. */
|
|
216
|
+
count?: number;
|
|
217
|
+
/**
|
|
218
|
+
* Timeout in milliseconds.
|
|
219
|
+
* Omit to wait indefinitely.
|
|
220
|
+
*/
|
|
221
|
+
timeout?: number;
|
|
222
|
+
/** Whether returned messages must be manually completed. */
|
|
223
|
+
completable?: boolean;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Message returned by workflow queue operations.
|
|
228
|
+
*/
|
|
229
|
+
export interface WorkflowQueueMessage<TBody = unknown> {
|
|
230
|
+
id: string | bigint;
|
|
231
|
+
name: string;
|
|
232
|
+
body: TBody;
|
|
233
|
+
createdAt: number;
|
|
234
|
+
complete?(response?: unknown): Promise<void>;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Workflow queue interface.
|
|
239
|
+
*/
|
|
240
|
+
export interface WorkflowQueue {
|
|
241
|
+
next<TBody = unknown>(
|
|
242
|
+
name: string,
|
|
243
|
+
opts?: WorkflowQueueNextOptions,
|
|
244
|
+
): Promise<Array<WorkflowQueueMessage<TBody>>>;
|
|
245
|
+
send(name: string, body: unknown): Promise<void>;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Workflow history - maps location keys to entries.
|
|
250
|
+
*/
|
|
251
|
+
export interface History {
|
|
252
|
+
entries: Map<string, Entry>;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* History entry snapshot without internal dirty flags.
|
|
257
|
+
*/
|
|
258
|
+
export type WorkflowHistoryEntry = Omit<Entry, "dirty">;
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Entry metadata snapshot without internal dirty flags.
|
|
262
|
+
*/
|
|
263
|
+
export type WorkflowEntryMetadataSnapshot = Omit<EntryMetadata, "dirty">;
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Snapshot of workflow history for observers.
|
|
267
|
+
*/
|
|
268
|
+
export interface WorkflowHistorySnapshot {
|
|
269
|
+
nameRegistry: string[];
|
|
270
|
+
entries: WorkflowHistoryEntry[];
|
|
271
|
+
entryMetadata: ReadonlyMap<string, WorkflowEntryMetadataSnapshot>;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* Structured error information for workflow failures.
|
|
276
|
+
*/
|
|
277
|
+
export interface WorkflowError {
|
|
278
|
+
/** Error name/type (e.g., "TypeError", "CriticalError") */
|
|
279
|
+
name: string;
|
|
280
|
+
/** Error message */
|
|
281
|
+
message: string;
|
|
282
|
+
/** Stack trace if available */
|
|
283
|
+
stack?: string;
|
|
284
|
+
/** Custom error properties (for structured errors) */
|
|
285
|
+
metadata?: Record<string, unknown>;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* Complete storage state for a workflow.
|
|
290
|
+
*/
|
|
291
|
+
export interface Storage {
|
|
292
|
+
nameRegistry: string[];
|
|
293
|
+
flushedNameCount: number;
|
|
294
|
+
history: History;
|
|
295
|
+
entryMetadata: Map<string, EntryMetadata>;
|
|
296
|
+
output?: unknown;
|
|
297
|
+
state: WorkflowState;
|
|
298
|
+
flushedState?: WorkflowState;
|
|
299
|
+
error?: WorkflowError;
|
|
300
|
+
flushedError?: WorkflowError;
|
|
301
|
+
flushedOutput?: unknown;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* Driver interface for workflow message persistence.
|
|
306
|
+
*/
|
|
307
|
+
export interface WorkflowMessageDriver {
|
|
308
|
+
addMessage(message: Message): Promise<void>;
|
|
309
|
+
/**
|
|
310
|
+
* Receive messages directly from the host queue implementation.
|
|
311
|
+
* The operation must be non-blocking and return immediately.
|
|
312
|
+
*/
|
|
313
|
+
receiveMessages(opts: {
|
|
314
|
+
names?: readonly string[];
|
|
315
|
+
count: number;
|
|
316
|
+
completable: boolean;
|
|
317
|
+
}): Promise<Message[]>;
|
|
318
|
+
/**
|
|
319
|
+
* Complete a previously consumed message with an optional response payload.
|
|
320
|
+
*/
|
|
321
|
+
completeMessage(messageId: string, response?: unknown): Promise<void>;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
/**
|
|
325
|
+
* Context available to rollback handlers.
|
|
326
|
+
*/
|
|
327
|
+
export interface RollbackContextInterface {
|
|
328
|
+
readonly workflowId: string;
|
|
329
|
+
readonly abortSignal: AbortSignal;
|
|
330
|
+
isEvicted(): boolean;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
/**
|
|
334
|
+
* Configuration for a step.
|
|
335
|
+
*/
|
|
336
|
+
export interface StepConfig<T> {
|
|
337
|
+
name: string;
|
|
338
|
+
run: () => Promise<T>;
|
|
339
|
+
rollback?: (ctx: RollbackContextInterface, output: T) => Promise<void>;
|
|
340
|
+
/** If true, step result is not persisted (use for idempotent operations). */
|
|
341
|
+
ephemeral?: boolean;
|
|
342
|
+
/** Maximum number of retry attempts (default: 3). */
|
|
343
|
+
maxRetries?: number;
|
|
344
|
+
/** Base delay in ms for exponential backoff (default: 100). */
|
|
345
|
+
retryBackoffBase?: number;
|
|
346
|
+
/** Maximum delay in ms for exponential backoff (default: 30000). */
|
|
347
|
+
retryBackoffMax?: number;
|
|
348
|
+
/** Timeout in ms for step execution (default: 30000). Set to 0 to disable. */
|
|
349
|
+
timeout?: number;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
/**
|
|
353
|
+
* Result from a loop iteration.
|
|
354
|
+
*/
|
|
355
|
+
export type LoopResult<S, T> =
|
|
356
|
+
| { continue: true; state: S }
|
|
357
|
+
| { break: true; value: T };
|
|
358
|
+
|
|
359
|
+
/**
|
|
360
|
+
* Configuration for a loop.
|
|
361
|
+
*/
|
|
362
|
+
export interface LoopConfig<S, T> {
|
|
363
|
+
name: string;
|
|
364
|
+
state?: S;
|
|
365
|
+
run: (ctx: WorkflowContextInterface, state: S) => Promise<LoopResult<S, T>>;
|
|
366
|
+
commitInterval?: number;
|
|
367
|
+
/** Trim loop history every N iterations. Defaults to commitInterval or 20. */
|
|
368
|
+
historyEvery?: number;
|
|
369
|
+
/** Retain the last N iterations of history. Defaults to commitInterval or 20. */
|
|
370
|
+
historyKeep?: number;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
/**
|
|
374
|
+
* Configuration for a branch in join/race.
|
|
375
|
+
*/
|
|
376
|
+
export interface BranchConfig<T> {
|
|
377
|
+
run: (ctx: WorkflowContextInterface) => Promise<T>;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
/**
|
|
381
|
+
* Extract the output type from a BranchConfig.
|
|
382
|
+
*/
|
|
383
|
+
export type BranchOutput<T> = T extends BranchConfig<infer O> ? O : never;
|
|
384
|
+
|
|
385
|
+
/**
|
|
386
|
+
* The workflow context interface exposed to workflow functions.
|
|
387
|
+
*/
|
|
388
|
+
export interface WorkflowContextInterface {
|
|
389
|
+
readonly workflowId: string;
|
|
390
|
+
readonly abortSignal: AbortSignal;
|
|
391
|
+
readonly queue: WorkflowQueue;
|
|
392
|
+
|
|
393
|
+
step<T>(name: string, run: () => Promise<T>): Promise<T>;
|
|
394
|
+
step<T>(config: StepConfig<T>): Promise<T>;
|
|
395
|
+
|
|
396
|
+
loop<T>(
|
|
397
|
+
name: string,
|
|
398
|
+
run: (
|
|
399
|
+
ctx: WorkflowContextInterface,
|
|
400
|
+
) => Promise<LoopResult<undefined, T>>,
|
|
401
|
+
): Promise<T>;
|
|
402
|
+
loop<S, T>(config: LoopConfig<S, T>): Promise<T>;
|
|
403
|
+
|
|
404
|
+
sleep(name: string, durationMs: number): Promise<void>;
|
|
405
|
+
sleepUntil(name: string, timestampMs: number): Promise<void>;
|
|
406
|
+
|
|
407
|
+
rollbackCheckpoint(name: string): Promise<void>;
|
|
408
|
+
|
|
409
|
+
join<T extends Record<string, BranchConfig<unknown>>>(
|
|
410
|
+
name: string,
|
|
411
|
+
branches: T,
|
|
412
|
+
): Promise<{ [K in keyof T]: BranchOutput<T[K]> }>;
|
|
413
|
+
|
|
414
|
+
race<T>(
|
|
415
|
+
name: string,
|
|
416
|
+
branches: Array<{
|
|
417
|
+
name: string;
|
|
418
|
+
run: (ctx: WorkflowContextInterface) => Promise<T>;
|
|
419
|
+
}>,
|
|
420
|
+
): Promise<{ winner: string; value: T }>;
|
|
421
|
+
|
|
422
|
+
removed(name: string, originalType: EntryKindType): Promise<void>;
|
|
423
|
+
|
|
424
|
+
isEvicted(): boolean;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
/**
|
|
428
|
+
* Workflow function type.
|
|
429
|
+
*/
|
|
430
|
+
export type WorkflowRunMode = "yield" | "live";
|
|
431
|
+
|
|
432
|
+
export interface RunWorkflowOptions {
|
|
433
|
+
mode?: WorkflowRunMode;
|
|
434
|
+
logger?: Logger;
|
|
435
|
+
onHistoryUpdated?: (history: WorkflowHistorySnapshot) => void;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
export type WorkflowFunction<TInput = unknown, TOutput = unknown> = (
|
|
439
|
+
ctx: WorkflowContextInterface,
|
|
440
|
+
input: TInput,
|
|
441
|
+
) => Promise<TOutput>;
|
|
442
|
+
|
|
443
|
+
/**
|
|
444
|
+
* Result returned when a workflow run completes or yields.
|
|
445
|
+
*/
|
|
446
|
+
export interface WorkflowResult<TOutput = unknown> {
|
|
447
|
+
state: WorkflowState;
|
|
448
|
+
output?: TOutput;
|
|
449
|
+
sleepUntil?: number;
|
|
450
|
+
waitingForMessages?: string[];
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
/**
|
|
454
|
+
* Handle for managing a running workflow.
|
|
455
|
+
*
|
|
456
|
+
* Returned by `runWorkflow()`. The workflow starts executing immediately.
|
|
457
|
+
* Use `.result` to await completion, and other methods to interact with
|
|
458
|
+
* the running workflow.
|
|
459
|
+
*/
|
|
460
|
+
export interface WorkflowHandle<TOutput = unknown> {
|
|
461
|
+
readonly workflowId: string;
|
|
462
|
+
|
|
463
|
+
/**
|
|
464
|
+
* Promise that resolves when the workflow completes or yields.
|
|
465
|
+
*/
|
|
466
|
+
readonly result: Promise<WorkflowResult<TOutput>>;
|
|
467
|
+
|
|
468
|
+
/**
|
|
469
|
+
* Send a message to the workflow.
|
|
470
|
+
* The message is delegated to the runtime message driver.
|
|
471
|
+
* In live mode, this wakes workflows waiting on queue messages.
|
|
472
|
+
*/
|
|
473
|
+
message(name: string, data: unknown): Promise<void>;
|
|
474
|
+
|
|
475
|
+
/**
|
|
476
|
+
* Wake the workflow immediately by setting an alarm for now.
|
|
477
|
+
*/
|
|
478
|
+
wake(): Promise<void>;
|
|
479
|
+
|
|
480
|
+
/**
|
|
481
|
+
* Reset exhausted retries and schedule the workflow to run again.
|
|
482
|
+
*/
|
|
483
|
+
recover(): Promise<void>;
|
|
484
|
+
|
|
485
|
+
/**
|
|
486
|
+
* Request the workflow to stop gracefully.
|
|
487
|
+
* The workflow will throw EvictedError at its next yield point,
|
|
488
|
+
* flush its state, and resolve the result promise.
|
|
489
|
+
*/
|
|
490
|
+
evict(): void;
|
|
491
|
+
|
|
492
|
+
/**
|
|
493
|
+
* Cancel the workflow permanently.
|
|
494
|
+
* Sets the workflow state to "cancelled" and clears any pending alarms.
|
|
495
|
+
* Unlike evict(), this marks the workflow as permanently stopped.
|
|
496
|
+
*/
|
|
497
|
+
cancel(): Promise<void>;
|
|
498
|
+
|
|
499
|
+
/**
|
|
500
|
+
* Get the workflow output if completed.
|
|
501
|
+
*/
|
|
502
|
+
getOutput(): Promise<TOutput | undefined>;
|
|
503
|
+
|
|
504
|
+
/**
|
|
505
|
+
* Get the current workflow state.
|
|
506
|
+
*/
|
|
507
|
+
getState(): Promise<WorkflowState>;
|
|
508
|
+
}
|
package/src/utils.ts
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sleep for a given number of milliseconds.
|
|
3
|
+
*/
|
|
4
|
+
export function sleep(ms: number): Promise<void> {
|
|
5
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const TIMEOUT_MAX = 2147483647;
|
|
9
|
+
|
|
10
|
+
export type LongTimeoutHandle = { abort: () => void };
|
|
11
|
+
|
|
12
|
+
export function setLongTimeout(
|
|
13
|
+
listener: () => void,
|
|
14
|
+
after: number,
|
|
15
|
+
): LongTimeoutHandle {
|
|
16
|
+
let timeout: ReturnType<typeof setTimeout> | undefined;
|
|
17
|
+
|
|
18
|
+
function start(remaining: number) {
|
|
19
|
+
if (remaining <= TIMEOUT_MAX) {
|
|
20
|
+
timeout = setTimeout(listener, remaining);
|
|
21
|
+
} else {
|
|
22
|
+
timeout = setTimeout(() => {
|
|
23
|
+
start(remaining - TIMEOUT_MAX);
|
|
24
|
+
}, TIMEOUT_MAX);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
start(after);
|
|
29
|
+
|
|
30
|
+
return {
|
|
31
|
+
abort: () => {
|
|
32
|
+
if (timeout !== undefined) clearTimeout(timeout);
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Safely parse JSON with a meaningful error message.
|
|
39
|
+
*/
|
|
40
|
+
export function safeJsonParse<T>(value: string, context: string): T {
|
|
41
|
+
try {
|
|
42
|
+
return JSON.parse(value) as T;
|
|
43
|
+
} catch (error) {
|
|
44
|
+
throw new Error(
|
|
45
|
+
`Failed to parse ${context}: ${error instanceof Error ? error.message : String(error)}`,
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
}
|