@rivetkit/workflow-engine 0.0.0-pr.4600.8dee603

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,4180 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { newObj[key] = obj[key]; } } } newObj.default = obj; return newObj; } } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } var _class;// src/error-utils.ts
2
+ var WORKFLOW_ERROR_REPORTED_SYMBOL = /* @__PURE__ */ Symbol("workflow.error.reported");
3
+ function extractErrorInfo(error) {
4
+ if (error instanceof Error) {
5
+ const result = {
6
+ name: error.name,
7
+ message: error.message,
8
+ stack: error.stack
9
+ };
10
+ const metadata = {};
11
+ for (const key of Object.keys(error)) {
12
+ if (key !== "name" && key !== "message" && key !== "stack") {
13
+ const value = error[key];
14
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean" || value === null) {
15
+ metadata[key] = value;
16
+ }
17
+ }
18
+ }
19
+ if (Object.keys(metadata).length > 0) {
20
+ result.metadata = metadata;
21
+ }
22
+ return result;
23
+ }
24
+ return {
25
+ name: "Error",
26
+ message: String(error)
27
+ };
28
+ }
29
+ function markErrorReported(error) {
30
+ error[WORKFLOW_ERROR_REPORTED_SYMBOL] = true;
31
+ return error;
32
+ }
33
+ function isErrorReported(error) {
34
+ if (!(error instanceof Error)) {
35
+ return false;
36
+ }
37
+ return Boolean(
38
+ error[WORKFLOW_ERROR_REPORTED_SYMBOL]
39
+ );
40
+ }
41
+ function getErrorEventTag(event) {
42
+ if ("step" in event) {
43
+ return "step";
44
+ }
45
+ if ("rollback" in event) {
46
+ return "rollback";
47
+ }
48
+ return "workflow";
49
+ }
50
+
51
+ // src/errors.ts
52
+ var CriticalError = class extends Error {
53
+ constructor(message) {
54
+ super(message);
55
+ this.name = "CriticalError";
56
+ }
57
+ };
58
+ var RollbackError = class extends Error {
59
+ constructor(message) {
60
+ super(message);
61
+ this.name = "RollbackError";
62
+ }
63
+ };
64
+ var RollbackCheckpointError = class extends Error {
65
+ constructor() {
66
+ super("Rollback requires a checkpoint before any rollback step");
67
+ this.name = "RollbackCheckpointError";
68
+ }
69
+ };
70
+ var SleepError = class extends Error {
71
+ constructor(deadline, messageNames) {
72
+ super(
73
+ messageNames && messageNames.length > 0 ? `Sleeping until ${deadline} or messages: ${messageNames.join(", ")}` : `Sleeping until ${deadline}`
74
+ );
75
+ this.deadline = deadline;
76
+ this.messageNames = messageNames;
77
+ this.name = "SleepError";
78
+ }
79
+ };
80
+ var MessageWaitError = class extends Error {
81
+ constructor(messageNames) {
82
+ super(`Waiting for messages: ${messageNames.join(", ")}`);
83
+ this.messageNames = messageNames;
84
+ this.name = "MessageWaitError";
85
+ }
86
+ };
87
+ var EvictedError = class extends Error {
88
+ constructor() {
89
+ super("Workflow evicted");
90
+ this.name = "EvictedError";
91
+ }
92
+ };
93
+ var RollbackStopError = class extends Error {
94
+ constructor() {
95
+ super("Rollback traversal halted");
96
+ this.name = "RollbackStopError";
97
+ }
98
+ };
99
+ var HistoryDivergedError = class extends Error {
100
+ constructor(message) {
101
+ super(message);
102
+ this.name = "HistoryDivergedError";
103
+ }
104
+ };
105
+ var StepExhaustedError = class extends Error {
106
+ constructor(stepName, lastError) {
107
+ super(
108
+ `Step "${stepName}" exhausted retries: ${_nullishCoalesce(lastError, () => ( "unknown error"))}`
109
+ );
110
+ this.stepName = stepName;
111
+ this.lastError = lastError;
112
+ this.name = "StepExhaustedError";
113
+ }
114
+ };
115
+ var StepFailedError = class extends Error {
116
+ constructor(stepName, originalError, attempts, retryAt) {
117
+ super(`Step "${stepName}" failed (attempt ${attempts})`);
118
+ this.stepName = stepName;
119
+ this.originalError = originalError;
120
+ this.attempts = attempts;
121
+ this.retryAt = retryAt;
122
+ this.name = "StepFailedError";
123
+ this.cause = originalError;
124
+ }
125
+ };
126
+ var JoinError = class extends Error {
127
+ constructor(errors) {
128
+ super(`Join failed: ${Object.keys(errors).join(", ")}`);
129
+ this.errors = errors;
130
+ this.name = "JoinError";
131
+ }
132
+ };
133
+ var RaceError = class extends Error {
134
+ constructor(message, errors) {
135
+ super(message);
136
+ this.errors = errors;
137
+ this.name = "RaceError";
138
+ }
139
+ };
140
+ var CancelledError = class extends Error {
141
+ constructor() {
142
+ super("Branch cancelled");
143
+ this.name = "CancelledError";
144
+ }
145
+ };
146
+ var EntryInProgressError = class extends Error {
147
+ constructor() {
148
+ super(
149
+ "Cannot start a new workflow entry while another is in progress. Did you forget to await the previous step/loop/sleep?"
150
+ );
151
+ this.name = "EntryInProgressError";
152
+ }
153
+ };
154
+
155
+ // src/keys.ts
156
+ var _fdbtuple = require('fdb-tuple'); var tuple = _interopRequireWildcard(_fdbtuple);
157
+ var KEY_PREFIX = {
158
+ NAMES: 1,
159
+ // Name registry: [1, index]
160
+ HISTORY: 2,
161
+ // History entries: [2, ...locationSegments]
162
+ WORKFLOW: 3,
163
+ // Workflow metadata: [3, field]
164
+ ENTRY_METADATA: 4
165
+ // Entry metadata: [4, entryId]
166
+ };
167
+ var WORKFLOW_FIELD = {
168
+ STATE: 1,
169
+ OUTPUT: 2,
170
+ ERROR: 3,
171
+ INPUT: 4
172
+ };
173
+ function segmentToTuple(segment) {
174
+ if (typeof segment === "number") {
175
+ return segment;
176
+ }
177
+ return [segment.loop, segment.iteration];
178
+ }
179
+ function locationToTupleElements(location) {
180
+ return location.map(segmentToTuple);
181
+ }
182
+ function bufferToUint8Array(buf) {
183
+ return new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength);
184
+ }
185
+ function uint8ArrayToBuffer(arr) {
186
+ return Buffer.from(arr.buffer, arr.byteOffset, arr.byteLength);
187
+ }
188
+ function pack2(items) {
189
+ const buf = tuple.pack(items);
190
+ return bufferToUint8Array(buf);
191
+ }
192
+ function unpack2(data) {
193
+ const buf = uint8ArrayToBuffer(data);
194
+ return tuple.unpack(buf);
195
+ }
196
+ function buildNameKey(index) {
197
+ return pack2([KEY_PREFIX.NAMES, index]);
198
+ }
199
+ function buildNamePrefix() {
200
+ return pack2([KEY_PREFIX.NAMES]);
201
+ }
202
+ function buildHistoryKey(location) {
203
+ return pack2([KEY_PREFIX.HISTORY, ...locationToTupleElements(location)]);
204
+ }
205
+ function buildHistoryPrefix(location) {
206
+ return pack2([KEY_PREFIX.HISTORY, ...locationToTupleElements(location)]);
207
+ }
208
+ function buildLoopIterationRange(loopLocation, loopSegment, fromIteration, toIteration) {
209
+ const loopLocationSegments = locationToTupleElements(loopLocation);
210
+ return {
211
+ start: pack2([
212
+ KEY_PREFIX.HISTORY,
213
+ ...loopLocationSegments,
214
+ [loopSegment, fromIteration]
215
+ ]),
216
+ end: pack2([
217
+ KEY_PREFIX.HISTORY,
218
+ ...loopLocationSegments,
219
+ [loopSegment, toIteration]
220
+ ])
221
+ };
222
+ }
223
+ function buildHistoryPrefixAll() {
224
+ return pack2([KEY_PREFIX.HISTORY]);
225
+ }
226
+ function buildWorkflowStateKey() {
227
+ return pack2([KEY_PREFIX.WORKFLOW, WORKFLOW_FIELD.STATE]);
228
+ }
229
+ function buildWorkflowOutputKey() {
230
+ return pack2([KEY_PREFIX.WORKFLOW, WORKFLOW_FIELD.OUTPUT]);
231
+ }
232
+ function buildWorkflowErrorKey() {
233
+ return pack2([KEY_PREFIX.WORKFLOW, WORKFLOW_FIELD.ERROR]);
234
+ }
235
+ function buildWorkflowInputKey() {
236
+ return pack2([KEY_PREFIX.WORKFLOW, WORKFLOW_FIELD.INPUT]);
237
+ }
238
+ function buildEntryMetadataKey(entryId) {
239
+ return pack2([KEY_PREFIX.ENTRY_METADATA, entryId]);
240
+ }
241
+ function buildEntryMetadataPrefix() {
242
+ return pack2([KEY_PREFIX.ENTRY_METADATA]);
243
+ }
244
+ function parseNameKey(key) {
245
+ const elements = unpack2(key);
246
+ if (elements.length !== 2 || elements[0] !== KEY_PREFIX.NAMES) {
247
+ throw new Error("Invalid name key");
248
+ }
249
+ return elements[1];
250
+ }
251
+ function parseEntryMetadataKey(key) {
252
+ const elements = unpack2(key);
253
+ if (elements.length !== 2 || elements[0] !== KEY_PREFIX.ENTRY_METADATA) {
254
+ throw new Error("Invalid entry metadata key");
255
+ }
256
+ return elements[1];
257
+ }
258
+ function keyStartsWith(key, prefix) {
259
+ if (key.length < prefix.length) {
260
+ return false;
261
+ }
262
+ for (let i = 0; i < prefix.length; i++) {
263
+ if (key[i] !== prefix[i]) {
264
+ return false;
265
+ }
266
+ }
267
+ return true;
268
+ }
269
+ function compareKeys(a, b) {
270
+ const minLen = Math.min(a.length, b.length);
271
+ for (let i = 0; i < minLen; i++) {
272
+ if (a[i] !== b[i]) {
273
+ return a[i] - b[i];
274
+ }
275
+ }
276
+ return a.length - b.length;
277
+ }
278
+ function keyToHex(key) {
279
+ return Array.from(key).map((b) => b.toString(16).padStart(2, "0")).join("");
280
+ }
281
+
282
+ // src/location.ts
283
+ function isLoopIterationMarker(segment) {
284
+ return typeof segment === "object" && "loop" in segment;
285
+ }
286
+ function registerName(storage, name) {
287
+ const existing = storage.nameRegistry.indexOf(name);
288
+ if (existing !== -1) {
289
+ return existing;
290
+ }
291
+ storage.nameRegistry.push(name);
292
+ return storage.nameRegistry.length - 1;
293
+ }
294
+ function resolveName(storage, index) {
295
+ const name = storage.nameRegistry[index];
296
+ if (name === void 0) {
297
+ throw new Error(`Name index ${index} not found in registry`);
298
+ }
299
+ return name;
300
+ }
301
+ function locationToKey(storage, location) {
302
+ return location.map((segment) => {
303
+ if (typeof segment === "number") {
304
+ return resolveName(storage, segment);
305
+ }
306
+ return `~${segment.iteration}`;
307
+ }).join("/");
308
+ }
309
+ function appendName(storage, location, name) {
310
+ const nameIndex = registerName(storage, name);
311
+ return [...location, nameIndex];
312
+ }
313
+ function appendLoopIteration(storage, location, loopName, iteration) {
314
+ const loopIndex = registerName(storage, loopName);
315
+ return [...location, { loop: loopIndex, iteration }];
316
+ }
317
+ function emptyLocation() {
318
+ return [];
319
+ }
320
+ function parentLocation(location) {
321
+ return location.slice(0, -1);
322
+ }
323
+ function isLocationPrefix(prefix, location) {
324
+ if (prefix.length > location.length) {
325
+ return false;
326
+ }
327
+ for (let i = 0; i < prefix.length; i++) {
328
+ const prefixSegment = prefix[i];
329
+ const locationSegment = location[i];
330
+ if (typeof prefixSegment === "number" && typeof locationSegment === "number") {
331
+ if (prefixSegment !== locationSegment) {
332
+ return false;
333
+ }
334
+ } else if (isLoopIterationMarker(prefixSegment) && isLoopIterationMarker(locationSegment)) {
335
+ if (prefixSegment.loop !== locationSegment.loop || prefixSegment.iteration !== locationSegment.iteration) {
336
+ return false;
337
+ }
338
+ } else {
339
+ return false;
340
+ }
341
+ }
342
+ return true;
343
+ }
344
+ function locationsEqual(a, b) {
345
+ if (a.length !== b.length) {
346
+ return false;
347
+ }
348
+ return isLocationPrefix(a, b);
349
+ }
350
+
351
+ // schemas/serde.ts
352
+ var _cborx = require('cbor-x'); var cbor = _interopRequireWildcard(_cborx);
353
+
354
+ // dist/schemas/v1.ts
355
+ var _barets = require('@rivetkit/bare-ts'); var bare = _interopRequireWildcard(_barets);
356
+ var config = /* @__PURE__ */ bare.Config({});
357
+ function readCbor(bc) {
358
+ return bare.readData(bc);
359
+ }
360
+ function writeCbor(bc, x) {
361
+ bare.writeData(bc, x);
362
+ }
363
+ function readNameIndex(bc) {
364
+ return bare.readU32(bc);
365
+ }
366
+ function writeNameIndex(bc, x) {
367
+ bare.writeU32(bc, x);
368
+ }
369
+ function readLoopIterationMarker(bc) {
370
+ return {
371
+ loop: readNameIndex(bc),
372
+ iteration: bare.readU32(bc)
373
+ };
374
+ }
375
+ function writeLoopIterationMarker(bc, x) {
376
+ writeNameIndex(bc, x.loop);
377
+ bare.writeU32(bc, x.iteration);
378
+ }
379
+ function readPathSegment(bc) {
380
+ const offset = bc.offset;
381
+ const tag = bare.readU8(bc);
382
+ switch (tag) {
383
+ case 0:
384
+ return { tag: "NameIndex", val: readNameIndex(bc) };
385
+ case 1:
386
+ return { tag: "LoopIterationMarker", val: readLoopIterationMarker(bc) };
387
+ default: {
388
+ bc.offset = offset;
389
+ throw new bare.BareError(offset, "invalid tag");
390
+ }
391
+ }
392
+ }
393
+ function writePathSegment(bc, x) {
394
+ switch (x.tag) {
395
+ case "NameIndex": {
396
+ bare.writeU8(bc, 0);
397
+ writeNameIndex(bc, x.val);
398
+ break;
399
+ }
400
+ case "LoopIterationMarker": {
401
+ bare.writeU8(bc, 1);
402
+ writeLoopIterationMarker(bc, x.val);
403
+ break;
404
+ }
405
+ }
406
+ }
407
+ function readLocation(bc) {
408
+ const len = bare.readUintSafe(bc);
409
+ if (len === 0) {
410
+ return [];
411
+ }
412
+ const result = [readPathSegment(bc)];
413
+ for (let i = 1; i < len; i++) {
414
+ result[i] = readPathSegment(bc);
415
+ }
416
+ return result;
417
+ }
418
+ function writeLocation(bc, x) {
419
+ bare.writeUintSafe(bc, x.length);
420
+ for (let i = 0; i < x.length; i++) {
421
+ writePathSegment(bc, x[i]);
422
+ }
423
+ }
424
+ function readEntryStatus(bc) {
425
+ const offset = bc.offset;
426
+ const tag = bare.readU8(bc);
427
+ switch (tag) {
428
+ case 0:
429
+ return "PENDING" /* PENDING */;
430
+ case 1:
431
+ return "RUNNING" /* RUNNING */;
432
+ case 2:
433
+ return "COMPLETED" /* COMPLETED */;
434
+ case 3:
435
+ return "FAILED" /* FAILED */;
436
+ case 4:
437
+ return "EXHAUSTED" /* EXHAUSTED */;
438
+ default: {
439
+ bc.offset = offset;
440
+ throw new bare.BareError(offset, "invalid tag");
441
+ }
442
+ }
443
+ }
444
+ function writeEntryStatus(bc, x) {
445
+ switch (x) {
446
+ case "PENDING" /* PENDING */: {
447
+ bare.writeU8(bc, 0);
448
+ break;
449
+ }
450
+ case "RUNNING" /* RUNNING */: {
451
+ bare.writeU8(bc, 1);
452
+ break;
453
+ }
454
+ case "COMPLETED" /* COMPLETED */: {
455
+ bare.writeU8(bc, 2);
456
+ break;
457
+ }
458
+ case "FAILED" /* FAILED */: {
459
+ bare.writeU8(bc, 3);
460
+ break;
461
+ }
462
+ case "EXHAUSTED" /* EXHAUSTED */: {
463
+ bare.writeU8(bc, 4);
464
+ break;
465
+ }
466
+ }
467
+ }
468
+ function readSleepState(bc) {
469
+ const offset = bc.offset;
470
+ const tag = bare.readU8(bc);
471
+ switch (tag) {
472
+ case 0:
473
+ return "PENDING" /* PENDING */;
474
+ case 1:
475
+ return "COMPLETED" /* COMPLETED */;
476
+ case 2:
477
+ return "INTERRUPTED" /* INTERRUPTED */;
478
+ default: {
479
+ bc.offset = offset;
480
+ throw new bare.BareError(offset, "invalid tag");
481
+ }
482
+ }
483
+ }
484
+ function writeSleepState(bc, x) {
485
+ switch (x) {
486
+ case "PENDING" /* PENDING */: {
487
+ bare.writeU8(bc, 0);
488
+ break;
489
+ }
490
+ case "COMPLETED" /* COMPLETED */: {
491
+ bare.writeU8(bc, 1);
492
+ break;
493
+ }
494
+ case "INTERRUPTED" /* INTERRUPTED */: {
495
+ bare.writeU8(bc, 2);
496
+ break;
497
+ }
498
+ }
499
+ }
500
+ function readBranchStatusType(bc) {
501
+ const offset = bc.offset;
502
+ const tag = bare.readU8(bc);
503
+ switch (tag) {
504
+ case 0:
505
+ return "PENDING" /* PENDING */;
506
+ case 1:
507
+ return "RUNNING" /* RUNNING */;
508
+ case 2:
509
+ return "COMPLETED" /* COMPLETED */;
510
+ case 3:
511
+ return "FAILED" /* FAILED */;
512
+ case 4:
513
+ return "CANCELLED" /* CANCELLED */;
514
+ default: {
515
+ bc.offset = offset;
516
+ throw new bare.BareError(offset, "invalid tag");
517
+ }
518
+ }
519
+ }
520
+ function writeBranchStatusType(bc, x) {
521
+ switch (x) {
522
+ case "PENDING" /* PENDING */: {
523
+ bare.writeU8(bc, 0);
524
+ break;
525
+ }
526
+ case "RUNNING" /* RUNNING */: {
527
+ bare.writeU8(bc, 1);
528
+ break;
529
+ }
530
+ case "COMPLETED" /* COMPLETED */: {
531
+ bare.writeU8(bc, 2);
532
+ break;
533
+ }
534
+ case "FAILED" /* FAILED */: {
535
+ bare.writeU8(bc, 3);
536
+ break;
537
+ }
538
+ case "CANCELLED" /* CANCELLED */: {
539
+ bare.writeU8(bc, 4);
540
+ break;
541
+ }
542
+ }
543
+ }
544
+ function read0(bc) {
545
+ return bare.readBool(bc) ? readCbor(bc) : null;
546
+ }
547
+ function write0(bc, x) {
548
+ bare.writeBool(bc, x !== null);
549
+ if (x !== null) {
550
+ writeCbor(bc, x);
551
+ }
552
+ }
553
+ function read1(bc) {
554
+ return bare.readBool(bc) ? bare.readString(bc) : null;
555
+ }
556
+ function write1(bc, x) {
557
+ bare.writeBool(bc, x !== null);
558
+ if (x !== null) {
559
+ bare.writeString(bc, x);
560
+ }
561
+ }
562
+ function readStepEntry(bc) {
563
+ return {
564
+ output: read0(bc),
565
+ error: read1(bc)
566
+ };
567
+ }
568
+ function writeStepEntry(bc, x) {
569
+ write0(bc, x.output);
570
+ write1(bc, x.error);
571
+ }
572
+ function readLoopEntry(bc) {
573
+ return {
574
+ state: readCbor(bc),
575
+ iteration: bare.readU32(bc),
576
+ output: read0(bc)
577
+ };
578
+ }
579
+ function writeLoopEntry(bc, x) {
580
+ writeCbor(bc, x.state);
581
+ bare.writeU32(bc, x.iteration);
582
+ write0(bc, x.output);
583
+ }
584
+ function readSleepEntry(bc) {
585
+ return {
586
+ deadline: bare.readU64(bc),
587
+ state: readSleepState(bc)
588
+ };
589
+ }
590
+ function writeSleepEntry(bc, x) {
591
+ bare.writeU64(bc, x.deadline);
592
+ writeSleepState(bc, x.state);
593
+ }
594
+ function readMessageEntry(bc) {
595
+ return {
596
+ name: bare.readString(bc),
597
+ messageData: readCbor(bc)
598
+ };
599
+ }
600
+ function writeMessageEntry(bc, x) {
601
+ bare.writeString(bc, x.name);
602
+ writeCbor(bc, x.messageData);
603
+ }
604
+ function readRollbackCheckpointEntry(bc) {
605
+ return {
606
+ name: bare.readString(bc)
607
+ };
608
+ }
609
+ function writeRollbackCheckpointEntry(bc, x) {
610
+ bare.writeString(bc, x.name);
611
+ }
612
+ function readBranchStatus(bc) {
613
+ return {
614
+ status: readBranchStatusType(bc),
615
+ output: read0(bc),
616
+ error: read1(bc)
617
+ };
618
+ }
619
+ function writeBranchStatus(bc, x) {
620
+ writeBranchStatusType(bc, x.status);
621
+ write0(bc, x.output);
622
+ write1(bc, x.error);
623
+ }
624
+ function read2(bc) {
625
+ const len = bare.readUintSafe(bc);
626
+ const result = /* @__PURE__ */ new Map();
627
+ for (let i = 0; i < len; i++) {
628
+ const offset = bc.offset;
629
+ const key = bare.readString(bc);
630
+ if (result.has(key)) {
631
+ bc.offset = offset;
632
+ throw new bare.BareError(offset, "duplicated key");
633
+ }
634
+ result.set(key, readBranchStatus(bc));
635
+ }
636
+ return result;
637
+ }
638
+ function write2(bc, x) {
639
+ bare.writeUintSafe(bc, x.size);
640
+ for (const kv of x) {
641
+ bare.writeString(bc, kv[0]);
642
+ writeBranchStatus(bc, kv[1]);
643
+ }
644
+ }
645
+ function readJoinEntry(bc) {
646
+ return {
647
+ branches: read2(bc)
648
+ };
649
+ }
650
+ function writeJoinEntry(bc, x) {
651
+ write2(bc, x.branches);
652
+ }
653
+ function readRaceEntry(bc) {
654
+ return {
655
+ winner: read1(bc),
656
+ branches: read2(bc)
657
+ };
658
+ }
659
+ function writeRaceEntry(bc, x) {
660
+ write1(bc, x.winner);
661
+ write2(bc, x.branches);
662
+ }
663
+ function readRemovedEntry(bc) {
664
+ return {
665
+ originalType: bare.readString(bc),
666
+ originalName: read1(bc)
667
+ };
668
+ }
669
+ function writeRemovedEntry(bc, x) {
670
+ bare.writeString(bc, x.originalType);
671
+ write1(bc, x.originalName);
672
+ }
673
+ function readEntryKind(bc) {
674
+ const offset = bc.offset;
675
+ const tag = bare.readU8(bc);
676
+ switch (tag) {
677
+ case 0:
678
+ return { tag: "StepEntry", val: readStepEntry(bc) };
679
+ case 1:
680
+ return { tag: "LoopEntry", val: readLoopEntry(bc) };
681
+ case 2:
682
+ return { tag: "SleepEntry", val: readSleepEntry(bc) };
683
+ case 3:
684
+ return { tag: "MessageEntry", val: readMessageEntry(bc) };
685
+ case 4:
686
+ return { tag: "RollbackCheckpointEntry", val: readRollbackCheckpointEntry(bc) };
687
+ case 5:
688
+ return { tag: "JoinEntry", val: readJoinEntry(bc) };
689
+ case 6:
690
+ return { tag: "RaceEntry", val: readRaceEntry(bc) };
691
+ case 7:
692
+ return { tag: "RemovedEntry", val: readRemovedEntry(bc) };
693
+ default: {
694
+ bc.offset = offset;
695
+ throw new bare.BareError(offset, "invalid tag");
696
+ }
697
+ }
698
+ }
699
+ function writeEntryKind(bc, x) {
700
+ switch (x.tag) {
701
+ case "StepEntry": {
702
+ bare.writeU8(bc, 0);
703
+ writeStepEntry(bc, x.val);
704
+ break;
705
+ }
706
+ case "LoopEntry": {
707
+ bare.writeU8(bc, 1);
708
+ writeLoopEntry(bc, x.val);
709
+ break;
710
+ }
711
+ case "SleepEntry": {
712
+ bare.writeU8(bc, 2);
713
+ writeSleepEntry(bc, x.val);
714
+ break;
715
+ }
716
+ case "MessageEntry": {
717
+ bare.writeU8(bc, 3);
718
+ writeMessageEntry(bc, x.val);
719
+ break;
720
+ }
721
+ case "RollbackCheckpointEntry": {
722
+ bare.writeU8(bc, 4);
723
+ writeRollbackCheckpointEntry(bc, x.val);
724
+ break;
725
+ }
726
+ case "JoinEntry": {
727
+ bare.writeU8(bc, 5);
728
+ writeJoinEntry(bc, x.val);
729
+ break;
730
+ }
731
+ case "RaceEntry": {
732
+ bare.writeU8(bc, 6);
733
+ writeRaceEntry(bc, x.val);
734
+ break;
735
+ }
736
+ case "RemovedEntry": {
737
+ bare.writeU8(bc, 7);
738
+ writeRemovedEntry(bc, x.val);
739
+ break;
740
+ }
741
+ }
742
+ }
743
+ function readEntry(bc) {
744
+ return {
745
+ id: bare.readString(bc),
746
+ location: readLocation(bc),
747
+ kind: readEntryKind(bc)
748
+ };
749
+ }
750
+ function writeEntry(bc, x) {
751
+ bare.writeString(bc, x.id);
752
+ writeLocation(bc, x.location);
753
+ writeEntryKind(bc, x.kind);
754
+ }
755
+ function encodeEntry(x) {
756
+ const bc = new bare.ByteCursor(
757
+ new Uint8Array(config.initialBufferLength),
758
+ config
759
+ );
760
+ writeEntry(bc, x);
761
+ return new Uint8Array(bc.view.buffer, bc.view.byteOffset, bc.offset);
762
+ }
763
+ function decodeEntry(bytes) {
764
+ const bc = new bare.ByteCursor(bytes, config);
765
+ const result = readEntry(bc);
766
+ if (bc.offset < bc.view.byteLength) {
767
+ throw new bare.BareError(bc.offset, "remaining bytes");
768
+ }
769
+ return result;
770
+ }
771
+ function read3(bc) {
772
+ return bare.readBool(bc) ? bare.readU64(bc) : null;
773
+ }
774
+ function write3(bc, x) {
775
+ bare.writeBool(bc, x !== null);
776
+ if (x !== null) {
777
+ bare.writeU64(bc, x);
778
+ }
779
+ }
780
+ function readEntryMetadata(bc) {
781
+ return {
782
+ status: readEntryStatus(bc),
783
+ error: read1(bc),
784
+ attempts: bare.readU32(bc),
785
+ lastAttemptAt: bare.readU64(bc),
786
+ createdAt: bare.readU64(bc),
787
+ completedAt: read3(bc),
788
+ rollbackCompletedAt: read3(bc),
789
+ rollbackError: read1(bc)
790
+ };
791
+ }
792
+ function writeEntryMetadata(bc, x) {
793
+ writeEntryStatus(bc, x.status);
794
+ write1(bc, x.error);
795
+ bare.writeU32(bc, x.attempts);
796
+ bare.writeU64(bc, x.lastAttemptAt);
797
+ bare.writeU64(bc, x.createdAt);
798
+ write3(bc, x.completedAt);
799
+ write3(bc, x.rollbackCompletedAt);
800
+ write1(bc, x.rollbackError);
801
+ }
802
+ function encodeEntryMetadata(x) {
803
+ const bc = new bare.ByteCursor(
804
+ new Uint8Array(config.initialBufferLength),
805
+ config
806
+ );
807
+ writeEntryMetadata(bc, x);
808
+ return new Uint8Array(bc.view.buffer, bc.view.byteOffset, bc.offset);
809
+ }
810
+ function decodeEntryMetadata(bytes) {
811
+ const bc = new bare.ByteCursor(bytes, config);
812
+ const result = readEntryMetadata(bc);
813
+ if (bc.offset < bc.view.byteLength) {
814
+ throw new bare.BareError(bc.offset, "remaining bytes");
815
+ }
816
+ return result;
817
+ }
818
+ function readWorkflowState(bc) {
819
+ const offset = bc.offset;
820
+ const tag = bare.readU8(bc);
821
+ switch (tag) {
822
+ case 0:
823
+ return "PENDING" /* PENDING */;
824
+ case 1:
825
+ return "RUNNING" /* RUNNING */;
826
+ case 2:
827
+ return "SLEEPING" /* SLEEPING */;
828
+ case 3:
829
+ return "FAILED" /* FAILED */;
830
+ case 4:
831
+ return "COMPLETED" /* COMPLETED */;
832
+ case 5:
833
+ return "ROLLING_BACK" /* ROLLING_BACK */;
834
+ default: {
835
+ bc.offset = offset;
836
+ throw new bare.BareError(offset, "invalid tag");
837
+ }
838
+ }
839
+ }
840
+ function writeWorkflowState(bc, x) {
841
+ switch (x) {
842
+ case "PENDING" /* PENDING */: {
843
+ bare.writeU8(bc, 0);
844
+ break;
845
+ }
846
+ case "RUNNING" /* RUNNING */: {
847
+ bare.writeU8(bc, 1);
848
+ break;
849
+ }
850
+ case "SLEEPING" /* SLEEPING */: {
851
+ bare.writeU8(bc, 2);
852
+ break;
853
+ }
854
+ case "FAILED" /* FAILED */: {
855
+ bare.writeU8(bc, 3);
856
+ break;
857
+ }
858
+ case "COMPLETED" /* COMPLETED */: {
859
+ bare.writeU8(bc, 4);
860
+ break;
861
+ }
862
+ case "ROLLING_BACK" /* ROLLING_BACK */: {
863
+ bare.writeU8(bc, 5);
864
+ break;
865
+ }
866
+ }
867
+ }
868
+ function readWorkflowMetadata(bc) {
869
+ return {
870
+ state: readWorkflowState(bc),
871
+ output: read0(bc),
872
+ error: read1(bc),
873
+ version: read1(bc)
874
+ };
875
+ }
876
+ function writeWorkflowMetadata(bc, x) {
877
+ writeWorkflowState(bc, x.state);
878
+ write0(bc, x.output);
879
+ write1(bc, x.error);
880
+ write1(bc, x.version);
881
+ }
882
+ function encodeWorkflowMetadata(x) {
883
+ const bc = new bare.ByteCursor(
884
+ new Uint8Array(config.initialBufferLength),
885
+ config
886
+ );
887
+ writeWorkflowMetadata(bc, x);
888
+ return new Uint8Array(bc.view.buffer, bc.view.byteOffset, bc.offset);
889
+ }
890
+ function decodeWorkflowMetadata(bytes) {
891
+ const bc = new bare.ByteCursor(bytes, config);
892
+ const result = readWorkflowMetadata(bc);
893
+ if (bc.offset < bc.view.byteLength) {
894
+ throw new bare.BareError(bc.offset, "remaining bytes");
895
+ }
896
+ return result;
897
+ }
898
+
899
+ // schemas/versioned.ts
900
+ var _vbare = require('vbare');
901
+ var CURRENT_VERSION = 1;
902
+ var ENTRY_VERSIONED = _vbare.createVersionedDataHandler.call(void 0, {
903
+ deserializeVersion: (bytes, version) => {
904
+ switch (version) {
905
+ case 1:
906
+ return decodeEntry(bytes);
907
+ default:
908
+ throw new Error(`Unknown Entry version ${version}`);
909
+ }
910
+ },
911
+ serializeVersion: (data, version) => {
912
+ switch (version) {
913
+ case 1:
914
+ return encodeEntry(data);
915
+ default:
916
+ throw new Error(`Unknown Entry version ${version}`);
917
+ }
918
+ },
919
+ deserializeConverters: () => [],
920
+ serializeConverters: () => []
921
+ });
922
+ var ENTRY_METADATA_VERSIONED = _vbare.createVersionedDataHandler.call(void 0, {
923
+ deserializeVersion: (bytes, version) => {
924
+ switch (version) {
925
+ case 1:
926
+ return decodeEntryMetadata(bytes);
927
+ default:
928
+ throw new Error(`Unknown EntryMetadata version ${version}`);
929
+ }
930
+ },
931
+ serializeVersion: (data, version) => {
932
+ switch (version) {
933
+ case 1:
934
+ return encodeEntryMetadata(data);
935
+ default:
936
+ throw new Error(`Unknown EntryMetadata version ${version}`);
937
+ }
938
+ },
939
+ deserializeConverters: () => [],
940
+ serializeConverters: () => []
941
+ });
942
+ var WORKFLOW_METADATA_VERSIONED = _vbare.createVersionedDataHandler.call(void 0, {
943
+ deserializeVersion: (bytes, version) => {
944
+ switch (version) {
945
+ case 1:
946
+ return decodeWorkflowMetadata(bytes);
947
+ default:
948
+ throw new Error(
949
+ `Unknown WorkflowMetadata version ${version}`
950
+ );
951
+ }
952
+ },
953
+ serializeVersion: (data, version) => {
954
+ switch (version) {
955
+ case 1:
956
+ return encodeWorkflowMetadata(
957
+ data
958
+ );
959
+ default:
960
+ throw new Error(
961
+ `Unknown WorkflowMetadata version ${version}`
962
+ );
963
+ }
964
+ },
965
+ deserializeConverters: () => [],
966
+ serializeConverters: () => []
967
+ });
968
+
969
+ // schemas/serde.ts
970
+ function bufferToArrayBuffer(buf) {
971
+ const arrayBuffer = new ArrayBuffer(buf.byteLength);
972
+ new Uint8Array(arrayBuffer).set(buf);
973
+ return arrayBuffer;
974
+ }
975
+ function encodeCbor(value) {
976
+ return bufferToArrayBuffer(cbor.encode(value));
977
+ }
978
+ function decodeCbor(data) {
979
+ return cbor.decode(new Uint8Array(data));
980
+ }
981
+ function assertObject(value, context) {
982
+ if (typeof value !== "object" || value === null) {
983
+ throw new Error(`${context}: expected object, got ${typeof value}`);
984
+ }
985
+ }
986
+ function assertString(value, context) {
987
+ if (typeof value !== "string") {
988
+ throw new Error(`${context}: expected string, got ${typeof value}`);
989
+ }
990
+ }
991
+ function entryStatusToBare(status) {
992
+ switch (status) {
993
+ case "pending":
994
+ return "PENDING" /* PENDING */;
995
+ case "running":
996
+ return "RUNNING" /* RUNNING */;
997
+ case "completed":
998
+ return "COMPLETED" /* COMPLETED */;
999
+ case "failed":
1000
+ return "FAILED" /* FAILED */;
1001
+ case "exhausted":
1002
+ return "EXHAUSTED" /* EXHAUSTED */;
1003
+ }
1004
+ }
1005
+ function entryStatusFromBare(status) {
1006
+ switch (status) {
1007
+ case "PENDING" /* PENDING */:
1008
+ return "pending";
1009
+ case "RUNNING" /* RUNNING */:
1010
+ return "running";
1011
+ case "COMPLETED" /* COMPLETED */:
1012
+ return "completed";
1013
+ case "FAILED" /* FAILED */:
1014
+ return "failed";
1015
+ case "EXHAUSTED" /* EXHAUSTED */:
1016
+ return "exhausted";
1017
+ }
1018
+ }
1019
+ function sleepStateToBare(state) {
1020
+ switch (state) {
1021
+ case "pending":
1022
+ return "PENDING" /* PENDING */;
1023
+ case "completed":
1024
+ return "COMPLETED" /* COMPLETED */;
1025
+ case "interrupted":
1026
+ return "INTERRUPTED" /* INTERRUPTED */;
1027
+ }
1028
+ }
1029
+ function sleepStateFromBare(state) {
1030
+ switch (state) {
1031
+ case "PENDING" /* PENDING */:
1032
+ return "pending";
1033
+ case "COMPLETED" /* COMPLETED */:
1034
+ return "completed";
1035
+ case "INTERRUPTED" /* INTERRUPTED */:
1036
+ return "interrupted";
1037
+ }
1038
+ }
1039
+ function branchStatusTypeToBare(status) {
1040
+ switch (status) {
1041
+ case "pending":
1042
+ return "PENDING" /* PENDING */;
1043
+ case "running":
1044
+ return "RUNNING" /* RUNNING */;
1045
+ case "completed":
1046
+ return "COMPLETED" /* COMPLETED */;
1047
+ case "failed":
1048
+ return "FAILED" /* FAILED */;
1049
+ case "cancelled":
1050
+ return "CANCELLED" /* CANCELLED */;
1051
+ }
1052
+ }
1053
+ function branchStatusTypeFromBare(status) {
1054
+ switch (status) {
1055
+ case "PENDING" /* PENDING */:
1056
+ return "pending";
1057
+ case "RUNNING" /* RUNNING */:
1058
+ return "running";
1059
+ case "COMPLETED" /* COMPLETED */:
1060
+ return "completed";
1061
+ case "FAILED" /* FAILED */:
1062
+ return "failed";
1063
+ case "CANCELLED" /* CANCELLED */:
1064
+ return "cancelled";
1065
+ }
1066
+ }
1067
+ function locationToBare(location) {
1068
+ return location.map((segment) => {
1069
+ if (typeof segment === "number") {
1070
+ return { tag: "NameIndex", val: segment };
1071
+ }
1072
+ return {
1073
+ tag: "LoopIterationMarker",
1074
+ val: {
1075
+ loop: segment.loop,
1076
+ iteration: segment.iteration
1077
+ }
1078
+ };
1079
+ });
1080
+ }
1081
+ function locationFromBare(location) {
1082
+ return location.map((segment) => {
1083
+ if (segment.tag === "NameIndex") {
1084
+ return segment.val;
1085
+ }
1086
+ return {
1087
+ loop: segment.val.loop,
1088
+ iteration: segment.val.iteration
1089
+ };
1090
+ });
1091
+ }
1092
+ function branchStatusToBare(status) {
1093
+ return {
1094
+ status: branchStatusTypeToBare(status.status),
1095
+ output: status.output !== void 0 ? encodeCbor(status.output) : null,
1096
+ error: _nullishCoalesce(status.error, () => ( null))
1097
+ };
1098
+ }
1099
+ function branchStatusFromBare(status) {
1100
+ return {
1101
+ status: branchStatusTypeFromBare(status.status),
1102
+ output: status.output !== null ? decodeCbor(status.output) : void 0,
1103
+ error: _nullishCoalesce(status.error, () => ( void 0))
1104
+ };
1105
+ }
1106
+ function entryKindToBare(kind) {
1107
+ switch (kind.type) {
1108
+ case "step":
1109
+ return {
1110
+ tag: "StepEntry",
1111
+ val: {
1112
+ output: kind.data.output !== void 0 ? encodeCbor(kind.data.output) : null,
1113
+ error: _nullishCoalesce(kind.data.error, () => ( null))
1114
+ }
1115
+ };
1116
+ case "loop":
1117
+ return {
1118
+ tag: "LoopEntry",
1119
+ val: {
1120
+ state: encodeCbor(kind.data.state),
1121
+ iteration: kind.data.iteration,
1122
+ output: kind.data.output !== void 0 ? encodeCbor(kind.data.output) : null
1123
+ }
1124
+ };
1125
+ case "sleep":
1126
+ return {
1127
+ tag: "SleepEntry",
1128
+ val: {
1129
+ deadline: BigInt(kind.data.deadline),
1130
+ state: sleepStateToBare(kind.data.state)
1131
+ }
1132
+ };
1133
+ case "message":
1134
+ return {
1135
+ tag: "MessageEntry",
1136
+ val: {
1137
+ name: kind.data.name,
1138
+ messageData: encodeCbor(kind.data.data)
1139
+ }
1140
+ };
1141
+ case "rollback_checkpoint":
1142
+ return {
1143
+ tag: "RollbackCheckpointEntry",
1144
+ val: {
1145
+ name: kind.data.name
1146
+ }
1147
+ };
1148
+ case "join":
1149
+ return {
1150
+ tag: "JoinEntry",
1151
+ val: {
1152
+ branches: new Map(
1153
+ Object.entries(kind.data.branches).map(
1154
+ ([name, status]) => [
1155
+ name,
1156
+ branchStatusToBare(status)
1157
+ ]
1158
+ )
1159
+ )
1160
+ }
1161
+ };
1162
+ case "race":
1163
+ return {
1164
+ tag: "RaceEntry",
1165
+ val: {
1166
+ winner: kind.data.winner,
1167
+ branches: new Map(
1168
+ Object.entries(kind.data.branches).map(
1169
+ ([name, status]) => [
1170
+ name,
1171
+ branchStatusToBare(status)
1172
+ ]
1173
+ )
1174
+ )
1175
+ }
1176
+ };
1177
+ case "removed":
1178
+ return {
1179
+ tag: "RemovedEntry",
1180
+ val: {
1181
+ originalType: kind.data.originalType,
1182
+ originalName: _nullishCoalesce(kind.data.originalName, () => ( null))
1183
+ }
1184
+ };
1185
+ }
1186
+ }
1187
+ function entryKindFromBare(kind) {
1188
+ switch (kind.tag) {
1189
+ case "StepEntry":
1190
+ return {
1191
+ type: "step",
1192
+ data: {
1193
+ output: kind.val.output !== null ? decodeCbor(kind.val.output) : void 0,
1194
+ error: _nullishCoalesce(kind.val.error, () => ( void 0))
1195
+ }
1196
+ };
1197
+ case "LoopEntry":
1198
+ return {
1199
+ type: "loop",
1200
+ data: {
1201
+ state: decodeCbor(kind.val.state),
1202
+ iteration: kind.val.iteration,
1203
+ output: kind.val.output !== null ? decodeCbor(kind.val.output) : void 0
1204
+ }
1205
+ };
1206
+ case "SleepEntry":
1207
+ return {
1208
+ type: "sleep",
1209
+ data: {
1210
+ deadline: Number(kind.val.deadline),
1211
+ state: sleepStateFromBare(kind.val.state)
1212
+ }
1213
+ };
1214
+ case "MessageEntry":
1215
+ return {
1216
+ type: "message",
1217
+ data: {
1218
+ name: kind.val.name,
1219
+ data: decodeCbor(kind.val.messageData)
1220
+ }
1221
+ };
1222
+ case "RollbackCheckpointEntry":
1223
+ return {
1224
+ type: "rollback_checkpoint",
1225
+ data: {
1226
+ name: kind.val.name
1227
+ }
1228
+ };
1229
+ case "JoinEntry":
1230
+ return {
1231
+ type: "join",
1232
+ data: {
1233
+ branches: Object.fromEntries(
1234
+ Array.from(kind.val.branches.entries()).map(
1235
+ ([name, status]) => [
1236
+ name,
1237
+ branchStatusFromBare(status)
1238
+ ]
1239
+ )
1240
+ )
1241
+ }
1242
+ };
1243
+ case "RaceEntry":
1244
+ return {
1245
+ type: "race",
1246
+ data: {
1247
+ winner: kind.val.winner,
1248
+ branches: Object.fromEntries(
1249
+ Array.from(kind.val.branches.entries()).map(
1250
+ ([name, status]) => [
1251
+ name,
1252
+ branchStatusFromBare(status)
1253
+ ]
1254
+ )
1255
+ )
1256
+ }
1257
+ };
1258
+ case "RemovedEntry":
1259
+ return {
1260
+ type: "removed",
1261
+ data: {
1262
+ originalType: kind.val.originalType,
1263
+ originalName: _nullishCoalesce(kind.val.originalName, () => ( void 0))
1264
+ }
1265
+ };
1266
+ default:
1267
+ throw new Error(
1268
+ `Unknown entry kind: ${kind.tag}`
1269
+ );
1270
+ }
1271
+ }
1272
+ function entryToBare(entry) {
1273
+ return {
1274
+ id: entry.id,
1275
+ location: locationToBare(entry.location),
1276
+ kind: entryKindToBare(entry.kind)
1277
+ };
1278
+ }
1279
+ function entryFromBare(bareEntry) {
1280
+ return {
1281
+ id: bareEntry.id,
1282
+ location: locationFromBare(bareEntry.location),
1283
+ kind: entryKindFromBare(bareEntry.kind),
1284
+ dirty: false
1285
+ };
1286
+ }
1287
+ function serializeEntry(entry) {
1288
+ const bareEntry = entryToBare(entry);
1289
+ return ENTRY_VERSIONED.serializeWithEmbeddedVersion(
1290
+ bareEntry,
1291
+ CURRENT_VERSION
1292
+ );
1293
+ }
1294
+ function deserializeEntry(bytes) {
1295
+ const bareEntry = ENTRY_VERSIONED.deserializeWithEmbeddedVersion(bytes);
1296
+ return entryFromBare(bareEntry);
1297
+ }
1298
+ function entryMetadataToBare(metadata) {
1299
+ return {
1300
+ status: entryStatusToBare(metadata.status),
1301
+ error: _nullishCoalesce(metadata.error, () => ( null)),
1302
+ attempts: metadata.attempts,
1303
+ lastAttemptAt: BigInt(metadata.lastAttemptAt),
1304
+ createdAt: BigInt(metadata.createdAt),
1305
+ completedAt: metadata.completedAt !== void 0 ? BigInt(metadata.completedAt) : null,
1306
+ rollbackCompletedAt: metadata.rollbackCompletedAt !== void 0 ? BigInt(metadata.rollbackCompletedAt) : null,
1307
+ rollbackError: _nullishCoalesce(metadata.rollbackError, () => ( null))
1308
+ };
1309
+ }
1310
+ function entryMetadataFromBare(bareMetadata) {
1311
+ return {
1312
+ status: entryStatusFromBare(bareMetadata.status),
1313
+ error: _nullishCoalesce(bareMetadata.error, () => ( void 0)),
1314
+ attempts: bareMetadata.attempts,
1315
+ lastAttemptAt: Number(bareMetadata.lastAttemptAt),
1316
+ createdAt: Number(bareMetadata.createdAt),
1317
+ completedAt: bareMetadata.completedAt !== null ? Number(bareMetadata.completedAt) : void 0,
1318
+ rollbackCompletedAt: bareMetadata.rollbackCompletedAt !== null ? Number(bareMetadata.rollbackCompletedAt) : void 0,
1319
+ rollbackError: _nullishCoalesce(bareMetadata.rollbackError, () => ( void 0)),
1320
+ dirty: false
1321
+ };
1322
+ }
1323
+ function serializeEntryMetadata(metadata) {
1324
+ const bareMetadata = entryMetadataToBare(metadata);
1325
+ return ENTRY_METADATA_VERSIONED.serializeWithEmbeddedVersion(
1326
+ bareMetadata,
1327
+ CURRENT_VERSION
1328
+ );
1329
+ }
1330
+ function deserializeEntryMetadata(bytes) {
1331
+ const bareMetadata = ENTRY_METADATA_VERSIONED.deserializeWithEmbeddedVersion(bytes);
1332
+ return entryMetadataFromBare(bareMetadata);
1333
+ }
1334
+ function serializeWorkflowState(state) {
1335
+ const encoder = new TextEncoder();
1336
+ return encoder.encode(state);
1337
+ }
1338
+ function deserializeWorkflowState(bytes) {
1339
+ const decoder = new TextDecoder();
1340
+ const state = decoder.decode(bytes);
1341
+ const validStates = [
1342
+ "pending",
1343
+ "running",
1344
+ "sleeping",
1345
+ "failed",
1346
+ "completed",
1347
+ "cancelled",
1348
+ "rolling_back"
1349
+ ];
1350
+ if (!validStates.includes(state)) {
1351
+ throw new Error(`Invalid workflow state: ${state}`);
1352
+ }
1353
+ return state;
1354
+ }
1355
+ function serializeWorkflowOutput(output) {
1356
+ return cbor.encode(output);
1357
+ }
1358
+ function deserializeWorkflowOutput(bytes) {
1359
+ try {
1360
+ return cbor.decode(bytes);
1361
+ } catch (error) {
1362
+ throw new Error(
1363
+ `Failed to deserialize workflow output: ${error instanceof Error ? error.message : String(error)}`
1364
+ );
1365
+ }
1366
+ }
1367
+ function serializeWorkflowError(error) {
1368
+ return cbor.encode(error);
1369
+ }
1370
+ function deserializeWorkflowError(bytes) {
1371
+ const decoded = cbor.decode(bytes);
1372
+ assertObject(decoded, "WorkflowError");
1373
+ const obj = decoded;
1374
+ assertString(obj.name, "WorkflowError.name");
1375
+ assertString(obj.message, "WorkflowError.message");
1376
+ return {
1377
+ name: obj.name,
1378
+ message: obj.message,
1379
+ stack: typeof obj.stack === "string" ? obj.stack : void 0,
1380
+ metadata: typeof obj.metadata === "object" && obj.metadata !== null ? obj.metadata : void 0
1381
+ };
1382
+ }
1383
+ function serializeWorkflowInput(input) {
1384
+ return cbor.encode(input);
1385
+ }
1386
+ function deserializeWorkflowInput(bytes) {
1387
+ try {
1388
+ return cbor.decode(bytes);
1389
+ } catch (error) {
1390
+ throw new Error(
1391
+ `Failed to deserialize workflow input: ${error instanceof Error ? error.message : String(error)}`
1392
+ );
1393
+ }
1394
+ }
1395
+ function serializeName(name) {
1396
+ const encoder = new TextEncoder();
1397
+ return encoder.encode(name);
1398
+ }
1399
+ function deserializeName(bytes) {
1400
+ const decoder = new TextDecoder();
1401
+ return decoder.decode(bytes);
1402
+ }
1403
+
1404
+ // src/storage.ts
1405
+ function createStorage() {
1406
+ return {
1407
+ nameRegistry: [],
1408
+ flushedNameCount: 0,
1409
+ history: { entries: /* @__PURE__ */ new Map() },
1410
+ entryMetadata: /* @__PURE__ */ new Map(),
1411
+ output: void 0,
1412
+ state: "pending",
1413
+ flushedState: void 0,
1414
+ error: void 0,
1415
+ flushedError: void 0,
1416
+ flushedOutput: void 0
1417
+ };
1418
+ }
1419
+ function createHistorySnapshot(storage) {
1420
+ const entryMetadata = /* @__PURE__ */ new Map();
1421
+ for (const [id, metadata] of storage.entryMetadata) {
1422
+ const { dirty, ...rest } = metadata;
1423
+ entryMetadata.set(id, rest);
1424
+ }
1425
+ const entries = [];
1426
+ const entryKeys = Array.from(storage.history.entries.keys()).sort();
1427
+ for (const key of entryKeys) {
1428
+ const entry = storage.history.entries.get(key);
1429
+ if (!entry) continue;
1430
+ const { dirty, ...rest } = entry;
1431
+ entries.push(rest);
1432
+ }
1433
+ return {
1434
+ nameRegistry: [...storage.nameRegistry],
1435
+ entries,
1436
+ entryMetadata
1437
+ };
1438
+ }
1439
+ function generateId() {
1440
+ return crypto.randomUUID();
1441
+ }
1442
+ function createEntry(location, kind) {
1443
+ return {
1444
+ id: generateId(),
1445
+ location,
1446
+ kind,
1447
+ dirty: true
1448
+ };
1449
+ }
1450
+ function getOrCreateMetadata(storage, entryId) {
1451
+ let metadata = storage.entryMetadata.get(entryId);
1452
+ if (!metadata) {
1453
+ metadata = {
1454
+ status: "pending",
1455
+ attempts: 0,
1456
+ lastAttemptAt: 0,
1457
+ createdAt: Date.now(),
1458
+ rollbackCompletedAt: void 0,
1459
+ rollbackError: void 0,
1460
+ dirty: true
1461
+ };
1462
+ storage.entryMetadata.set(entryId, metadata);
1463
+ }
1464
+ return metadata;
1465
+ }
1466
+ async function loadStorage(driver) {
1467
+ const storage = createStorage();
1468
+ const nameEntries = await driver.list(buildNamePrefix());
1469
+ nameEntries.sort((a, b) => compareKeys(a.key, b.key));
1470
+ for (const entry of nameEntries) {
1471
+ const index = parseNameKey(entry.key);
1472
+ storage.nameRegistry[index] = deserializeName(entry.value);
1473
+ }
1474
+ storage.flushedNameCount = storage.nameRegistry.length;
1475
+ const historyEntries = await driver.list(buildHistoryPrefixAll());
1476
+ for (const entry of historyEntries) {
1477
+ const parsed = deserializeEntry(entry.value);
1478
+ parsed.dirty = false;
1479
+ const key = locationToKey(storage, parsed.location);
1480
+ storage.history.entries.set(key, parsed);
1481
+ }
1482
+ const metadataEntries = await driver.list(buildEntryMetadataPrefix());
1483
+ for (const entry of metadataEntries) {
1484
+ const entryId = parseEntryMetadataKey(entry.key);
1485
+ const metadata = deserializeEntryMetadata(entry.value);
1486
+ metadata.dirty = false;
1487
+ storage.entryMetadata.set(entryId, metadata);
1488
+ }
1489
+ const stateValue = await driver.get(buildWorkflowStateKey());
1490
+ if (stateValue) {
1491
+ storage.state = deserializeWorkflowState(stateValue);
1492
+ storage.flushedState = storage.state;
1493
+ }
1494
+ const outputValue = await driver.get(buildWorkflowOutputKey());
1495
+ if (outputValue) {
1496
+ storage.output = deserializeWorkflowOutput(outputValue);
1497
+ storage.flushedOutput = storage.output;
1498
+ }
1499
+ const errorValue = await driver.get(buildWorkflowErrorKey());
1500
+ if (errorValue) {
1501
+ storage.error = deserializeWorkflowError(errorValue);
1502
+ storage.flushedError = storage.error;
1503
+ }
1504
+ return storage;
1505
+ }
1506
+ async function loadMetadata(storage, driver, entryId) {
1507
+ const existing = storage.entryMetadata.get(entryId);
1508
+ if (existing) {
1509
+ return existing;
1510
+ }
1511
+ const value = await driver.get(buildEntryMetadataKey(entryId));
1512
+ if (value) {
1513
+ const metadata = deserializeEntryMetadata(value);
1514
+ metadata.dirty = false;
1515
+ storage.entryMetadata.set(entryId, metadata);
1516
+ return metadata;
1517
+ }
1518
+ return getOrCreateMetadata(storage, entryId);
1519
+ }
1520
+ async function flush(storage, driver, onHistoryUpdated, pendingDeletions) {
1521
+ const writes = [];
1522
+ let historyUpdated = false;
1523
+ for (let i = storage.flushedNameCount; i < storage.nameRegistry.length; i++) {
1524
+ const name = storage.nameRegistry[i];
1525
+ if (name !== void 0) {
1526
+ writes.push({
1527
+ key: buildNameKey(i),
1528
+ value: serializeName(name)
1529
+ });
1530
+ historyUpdated = true;
1531
+ }
1532
+ }
1533
+ for (const [, entry] of storage.history.entries) {
1534
+ if (entry.dirty) {
1535
+ writes.push({
1536
+ key: buildHistoryKey(entry.location),
1537
+ value: serializeEntry(entry)
1538
+ });
1539
+ entry.dirty = false;
1540
+ historyUpdated = true;
1541
+ }
1542
+ }
1543
+ for (const [id, metadata] of storage.entryMetadata) {
1544
+ if (metadata.dirty) {
1545
+ writes.push({
1546
+ key: buildEntryMetadataKey(id),
1547
+ value: serializeEntryMetadata(metadata)
1548
+ });
1549
+ metadata.dirty = false;
1550
+ historyUpdated = true;
1551
+ }
1552
+ }
1553
+ if (storage.state !== storage.flushedState) {
1554
+ writes.push({
1555
+ key: buildWorkflowStateKey(),
1556
+ value: serializeWorkflowState(storage.state)
1557
+ });
1558
+ }
1559
+ if (storage.output !== void 0 && storage.output !== storage.flushedOutput) {
1560
+ writes.push({
1561
+ key: buildWorkflowOutputKey(),
1562
+ value: serializeWorkflowOutput(storage.output)
1563
+ });
1564
+ }
1565
+ const errorChanged = storage.error !== void 0 && (storage.flushedError === void 0 || storage.error.name !== storage.flushedError.name || storage.error.message !== storage.flushedError.message);
1566
+ if (errorChanged) {
1567
+ writes.push({
1568
+ key: buildWorkflowErrorKey(),
1569
+ value: serializeWorkflowError(storage.error)
1570
+ });
1571
+ }
1572
+ if (writes.length > 0) {
1573
+ await driver.batch(writes);
1574
+ }
1575
+ if (pendingDeletions) {
1576
+ const deleteOps = [];
1577
+ for (const prefix of pendingDeletions.prefixes) {
1578
+ deleteOps.push(driver.deletePrefix(prefix));
1579
+ }
1580
+ for (const range of pendingDeletions.ranges) {
1581
+ deleteOps.push(driver.deleteRange(range.start, range.end));
1582
+ }
1583
+ for (const key of pendingDeletions.keys) {
1584
+ deleteOps.push(driver.delete(key));
1585
+ }
1586
+ if (deleteOps.length > 0) {
1587
+ await Promise.all(deleteOps);
1588
+ historyUpdated = true;
1589
+ }
1590
+ }
1591
+ storage.flushedNameCount = storage.nameRegistry.length;
1592
+ storage.flushedState = storage.state;
1593
+ storage.flushedOutput = storage.output;
1594
+ storage.flushedError = storage.error;
1595
+ if (historyUpdated && onHistoryUpdated) {
1596
+ onHistoryUpdated();
1597
+ }
1598
+ }
1599
+ async function deleteEntriesWithPrefix(storage, driver, prefixLocation, onHistoryUpdated) {
1600
+ const deletions = collectDeletionsForPrefix(storage, prefixLocation);
1601
+ await driver.deletePrefix(deletions.prefixes[0]);
1602
+ await Promise.all(deletions.keys.map((key) => driver.delete(key)));
1603
+ if (deletions.keys.length > 0 && onHistoryUpdated) {
1604
+ onHistoryUpdated();
1605
+ }
1606
+ }
1607
+ function collectDeletionsForPrefix(storage, prefixLocation) {
1608
+ const pending = {
1609
+ prefixes: [buildHistoryPrefix(prefixLocation)],
1610
+ keys: [],
1611
+ ranges: []
1612
+ };
1613
+ for (const [key, entry] of storage.history.entries) {
1614
+ if (isLocationPrefix(prefixLocation, entry.location)) {
1615
+ pending.keys.push(buildEntryMetadataKey(entry.id));
1616
+ storage.entryMetadata.delete(entry.id);
1617
+ storage.history.entries.delete(key);
1618
+ }
1619
+ }
1620
+ return pending;
1621
+ }
1622
+ function getEntry(storage, location) {
1623
+ const key = locationToKey(storage, location);
1624
+ return storage.history.entries.get(key);
1625
+ }
1626
+ function setEntry(storage, location, entry) {
1627
+ const key = locationToKey(storage, location);
1628
+ storage.history.entries.set(key, entry);
1629
+ }
1630
+
1631
+ // src/utils.ts
1632
+ function sleep(ms) {
1633
+ return new Promise((resolve) => setTimeout(resolve, ms));
1634
+ }
1635
+ var TIMEOUT_MAX = 2147483647;
1636
+ function setLongTimeout(listener, after) {
1637
+ let timeout;
1638
+ function start(remaining) {
1639
+ if (remaining <= TIMEOUT_MAX) {
1640
+ timeout = setTimeout(listener, remaining);
1641
+ } else {
1642
+ timeout = setTimeout(() => {
1643
+ start(remaining - TIMEOUT_MAX);
1644
+ }, TIMEOUT_MAX);
1645
+ }
1646
+ }
1647
+ start(after);
1648
+ return {
1649
+ abort: () => {
1650
+ if (timeout !== void 0) clearTimeout(timeout);
1651
+ }
1652
+ };
1653
+ }
1654
+
1655
+ // src/context.ts
1656
+ var DEFAULT_MAX_RETRIES = 3;
1657
+ var DEFAULT_RETRY_BACKOFF_BASE = 100;
1658
+ var DEFAULT_RETRY_BACKOFF_MAX = 3e4;
1659
+ var DEFAULT_LOOP_HISTORY_PRUNE_INTERVAL = 20;
1660
+ var DEFAULT_STEP_TIMEOUT = 3e4;
1661
+ var DEFAULT_TRY_STEP_CATCH = [
1662
+ "critical",
1663
+ "timeout",
1664
+ "exhausted"
1665
+ ];
1666
+ var DEFAULT_TRY_BLOCK_CATCH = [
1667
+ "step",
1668
+ "join",
1669
+ "race"
1670
+ ];
1671
+ var QUEUE_HISTORY_MESSAGE_MARKER = "__rivetWorkflowQueueMessage";
1672
+ var TRY_STEP_FAILURE_SYMBOL = /* @__PURE__ */ Symbol("workflow.try-step.failure");
1673
+ var TRY_BLOCK_FAILURE_SYMBOL = /* @__PURE__ */ Symbol("workflow.try-block.failure");
1674
+ function calculateBackoff(attempts, base, max) {
1675
+ return Math.min(max, base * 2 ** attempts);
1676
+ }
1677
+ var StepTimeoutError = class extends Error {
1678
+ constructor(stepName, timeoutMs) {
1679
+ super(`Step "${stepName}" timed out after ${timeoutMs}ms`);
1680
+ this.stepName = stepName;
1681
+ this.timeoutMs = timeoutMs;
1682
+ this.name = "StepTimeoutError";
1683
+ }
1684
+ };
1685
+ function attachTryStepFailure(error, failure) {
1686
+ error[TRY_STEP_FAILURE_SYMBOL] = failure;
1687
+ return error;
1688
+ }
1689
+ function readTryStepFailure(error) {
1690
+ if (!(error instanceof Error)) {
1691
+ return void 0;
1692
+ }
1693
+ return error[TRY_STEP_FAILURE_SYMBOL];
1694
+ }
1695
+ function attachTryBlockFailure(error, failure) {
1696
+ error[TRY_BLOCK_FAILURE_SYMBOL] = failure;
1697
+ return error;
1698
+ }
1699
+ function readTryBlockFailure(error) {
1700
+ if (!(error instanceof Error)) {
1701
+ return void 0;
1702
+ }
1703
+ return error[TRY_BLOCK_FAILURE_SYMBOL];
1704
+ }
1705
+ function shouldRethrowTryError(error) {
1706
+ return error instanceof StepFailedError || error instanceof SleepError || error instanceof MessageWaitError || error instanceof EvictedError || error instanceof HistoryDivergedError || error instanceof EntryInProgressError || error instanceof RollbackCheckpointError || error instanceof RollbackStopError;
1707
+ }
1708
+ function shouldCatchTryStepFailure(failure, catchKinds) {
1709
+ const effectiveCatch = _nullishCoalesce(catchKinds, () => ( DEFAULT_TRY_STEP_CATCH));
1710
+ return effectiveCatch.includes(failure.kind);
1711
+ }
1712
+ function shouldCatchTryBlockFailure(failure, catchKinds) {
1713
+ var _a;
1714
+ const effectiveCatch = _nullishCoalesce(catchKinds, () => ( DEFAULT_TRY_BLOCK_CATCH));
1715
+ if (failure.source === "step") {
1716
+ return ((_a = failure.step) == null ? void 0 : _a.kind) === "rollback" ? effectiveCatch.includes("rollback") : effectiveCatch.includes("step");
1717
+ }
1718
+ if (failure.source === "join") {
1719
+ return effectiveCatch.includes("join");
1720
+ }
1721
+ if (failure.source === "race") {
1722
+ return effectiveCatch.includes("race");
1723
+ }
1724
+ return effectiveCatch.includes("rollback");
1725
+ }
1726
+ function parseStoredWorkflowError(message) {
1727
+ if (!message) {
1728
+ return {
1729
+ name: "Error",
1730
+ message: "unknown error"
1731
+ };
1732
+ }
1733
+ const match = /^([^:]+):\s*(.*)$/s.exec(message);
1734
+ if (!match) {
1735
+ return {
1736
+ name: "Error",
1737
+ message
1738
+ };
1739
+ }
1740
+ return {
1741
+ name: match[1],
1742
+ message: match[2]
1743
+ };
1744
+ }
1745
+ function getTryStepFailureFromExhaustedError(stepName, attempts, error) {
1746
+ return {
1747
+ kind: "exhausted",
1748
+ stepName,
1749
+ attempts,
1750
+ error: parseStoredWorkflowError(error.lastError)
1751
+ };
1752
+ }
1753
+ function mergeSchedulerYield(state, error) {
1754
+ const nextState = _nullishCoalesce(state, () => ( {
1755
+ messageNames: /* @__PURE__ */ new Set()
1756
+ }));
1757
+ if (error instanceof SleepError) {
1758
+ nextState.deadline = nextState.deadline === void 0 ? error.deadline : Math.min(nextState.deadline, error.deadline);
1759
+ for (const messageName of _nullishCoalesce(error.messageNames, () => ( []))) {
1760
+ nextState.messageNames.add(messageName);
1761
+ }
1762
+ return nextState;
1763
+ }
1764
+ if (error instanceof MessageWaitError) {
1765
+ for (const messageName of error.messageNames) {
1766
+ nextState.messageNames.add(messageName);
1767
+ }
1768
+ return nextState;
1769
+ }
1770
+ nextState.deadline = nextState.deadline === void 0 ? error.retryAt : Math.min(nextState.deadline, error.retryAt);
1771
+ return nextState;
1772
+ }
1773
+ function buildSchedulerYieldError(state) {
1774
+ const messageNames = [...state.messageNames];
1775
+ if (state.deadline !== void 0) {
1776
+ return new SleepError(
1777
+ state.deadline,
1778
+ messageNames.length > 0 ? messageNames : void 0
1779
+ );
1780
+ }
1781
+ return new MessageWaitError(messageNames);
1782
+ }
1783
+ function controlFlowErrorPriority(error) {
1784
+ if (error instanceof EvictedError) {
1785
+ return 0;
1786
+ }
1787
+ if (error instanceof HistoryDivergedError) {
1788
+ return 1;
1789
+ }
1790
+ if (error instanceof EntryInProgressError) {
1791
+ return 2;
1792
+ }
1793
+ if (error instanceof RollbackCheckpointError) {
1794
+ return 3;
1795
+ }
1796
+ if (error instanceof RollbackStopError) {
1797
+ return 4;
1798
+ }
1799
+ return 5;
1800
+ }
1801
+ function selectControlFlowError(current, candidate) {
1802
+ if (!current) {
1803
+ return candidate;
1804
+ }
1805
+ return controlFlowErrorPriority(candidate) < controlFlowErrorPriority(current) ? candidate : current;
1806
+ }
1807
+ var WorkflowContextImpl = (_class = class _WorkflowContextImpl {
1808
+ constructor(workflowId, storage, driver, messageDriver, location = emptyLocation(), abortController, mode = "forward", rollbackActions, rollbackCheckpointSet = false, historyNotifier, onError, logger, visitedKeys) {;_class.prototype.__init.call(this);_class.prototype.__init2.call(this);_class.prototype.__init3.call(this);
1809
+ this.workflowId = workflowId;
1810
+ this.storage = storage;
1811
+ this.driver = driver;
1812
+ this.messageDriver = messageDriver;
1813
+ this.currentLocation = location;
1814
+ this.abortController = _nullishCoalesce(abortController, () => ( new AbortController()));
1815
+ this.mode = mode;
1816
+ this.rollbackActions = rollbackActions;
1817
+ this.rollbackCheckpointSet = rollbackCheckpointSet;
1818
+ this.historyNotifier = historyNotifier;
1819
+ this.onError = onError;
1820
+ this.logger = logger;
1821
+ this.visitedKeys = _nullishCoalesce(visitedKeys, () => ( /* @__PURE__ */ new Set()));
1822
+ }
1823
+ __init() {this.entryInProgress = false}
1824
+
1825
+
1826
+
1827
+
1828
+
1829
+
1830
+ /** Track names used in current execution to detect duplicates */
1831
+ __init2() {this.usedNamesInExecution = /* @__PURE__ */ new Set()}
1832
+ __init3() {this.pendingCompletableMessageIds = /* @__PURE__ */ new Set()}
1833
+
1834
+
1835
+
1836
+ get abortSignal() {
1837
+ return this.abortController.signal;
1838
+ }
1839
+ get queue() {
1840
+ return {
1841
+ next: async (name, opts) => await this.queueNext(name, opts),
1842
+ nextBatch: async (name, opts) => await this.queueNextBatch(name, opts),
1843
+ send: async (name, body) => await this.queueSend(name, body)
1844
+ };
1845
+ }
1846
+ isEvicted() {
1847
+ return this.abortSignal.aborted;
1848
+ }
1849
+ assertNotInProgress() {
1850
+ if (this.entryInProgress) {
1851
+ throw new EntryInProgressError();
1852
+ }
1853
+ }
1854
+ checkEvicted() {
1855
+ if (this.abortSignal.aborted) {
1856
+ throw new EvictedError();
1857
+ }
1858
+ }
1859
+ async flushStorage() {
1860
+ await flush(this.storage, this.driver, this.historyNotifier);
1861
+ }
1862
+ /**
1863
+ * Create a new branch context for parallel/nested execution.
1864
+ */
1865
+ createBranch(location, abortController) {
1866
+ return new _WorkflowContextImpl(
1867
+ this.workflowId,
1868
+ this.storage,
1869
+ this.driver,
1870
+ this.messageDriver,
1871
+ location,
1872
+ _nullishCoalesce(abortController, () => ( this.abortController)),
1873
+ this.mode,
1874
+ this.rollbackActions,
1875
+ this.rollbackCheckpointSet,
1876
+ this.historyNotifier,
1877
+ this.onError,
1878
+ this.logger,
1879
+ this.visitedKeys
1880
+ );
1881
+ }
1882
+ /**
1883
+ * Log a debug message using the configured logger.
1884
+ */
1885
+ log(level, data) {
1886
+ if (!this.logger) return;
1887
+ this.logger[level](data);
1888
+ }
1889
+ async notifyError(event) {
1890
+ if (!this.onError) {
1891
+ return;
1892
+ }
1893
+ try {
1894
+ await this.onError(event);
1895
+ } catch (error) {
1896
+ this.log("warn", {
1897
+ msg: "workflow error hook failed",
1898
+ hookEventType: getErrorEventTag(event),
1899
+ error: extractErrorInfo(error)
1900
+ });
1901
+ }
1902
+ }
1903
+ async notifyStepError(config2, attempt, error, opts) {
1904
+ const maxRetries = _nullishCoalesce(config2.maxRetries, () => ( DEFAULT_MAX_RETRIES));
1905
+ await this.notifyError({
1906
+ step: {
1907
+ workflowId: this.workflowId,
1908
+ stepName: config2.name,
1909
+ attempt,
1910
+ maxRetries,
1911
+ remainingRetries: Math.max(0, maxRetries - (attempt - 1)),
1912
+ willRetry: opts.willRetry,
1913
+ retryDelay: opts.retryDelay,
1914
+ retryAt: opts.retryAt,
1915
+ error: extractErrorInfo(error)
1916
+ }
1917
+ });
1918
+ }
1919
+ /**
1920
+ * Mark a key as visited.
1921
+ */
1922
+ markVisited(key) {
1923
+ this.visitedKeys.add(key);
1924
+ }
1925
+ /**
1926
+ * Check if a name has already been used at the current location in this execution.
1927
+ * Throws HistoryDivergedError if duplicate detected.
1928
+ */
1929
+ checkDuplicateName(name) {
1930
+ const fullKey = locationToKey(this.storage, this.currentLocation) + "/" + name;
1931
+ if (this.usedNamesInExecution.has(fullKey)) {
1932
+ throw new HistoryDivergedError(
1933
+ `Duplicate entry name "${name}" at location "${locationToKey(this.storage, this.currentLocation)}". Each step/loop/sleep/queue.next/join/race must have a unique name within its scope.`
1934
+ );
1935
+ }
1936
+ this.usedNamesInExecution.add(fullKey);
1937
+ }
1938
+ stopRollback() {
1939
+ throw new RollbackStopError();
1940
+ }
1941
+ stopRollbackIfMissing(entry) {
1942
+ if (this.mode === "rollback" && !entry) {
1943
+ this.stopRollback();
1944
+ }
1945
+ }
1946
+ stopRollbackIfIncomplete(condition) {
1947
+ if (this.mode === "rollback" && condition) {
1948
+ this.stopRollback();
1949
+ }
1950
+ }
1951
+ registerRollbackAction(config2, entryId, output, metadata) {
1952
+ var _a;
1953
+ if (!config2.rollback) {
1954
+ return;
1955
+ }
1956
+ if (metadata.rollbackCompletedAt !== void 0) {
1957
+ return;
1958
+ }
1959
+ (_a = this.rollbackActions) == null ? void 0 : _a.push({
1960
+ entryId,
1961
+ name: config2.name,
1962
+ output,
1963
+ rollback: config2.rollback
1964
+ });
1965
+ }
1966
+ /**
1967
+ * Ensure a rollback checkpoint exists before registering rollback handlers.
1968
+ */
1969
+ ensureRollbackCheckpoint(config2) {
1970
+ if (!config2.rollback) {
1971
+ return;
1972
+ }
1973
+ if (!this.rollbackCheckpointSet) {
1974
+ throw new RollbackCheckpointError();
1975
+ }
1976
+ }
1977
+ /**
1978
+ * Validate that all expected entries in the branch were visited.
1979
+ * Throws HistoryDivergedError if there are unvisited entries.
1980
+ */
1981
+ validateComplete() {
1982
+ const prefix = locationToKey(this.storage, this.currentLocation);
1983
+ for (const key of this.storage.history.entries.keys()) {
1984
+ const isUnderPrefix = prefix === "" ? true : key.startsWith(prefix + "/") || key === prefix;
1985
+ if (isUnderPrefix) {
1986
+ if (!this.visitedKeys.has(key)) {
1987
+ throw new HistoryDivergedError(
1988
+ `Entry "${key}" exists in history but was not visited. Workflow code may have changed. Use ctx.removed() to handle migrations.`
1989
+ );
1990
+ }
1991
+ }
1992
+ }
1993
+ }
1994
+ /**
1995
+ * Evict the workflow.
1996
+ */
1997
+ evict() {
1998
+ this.abortController.abort(new EvictedError());
1999
+ }
2000
+ /**
2001
+ * Wait for eviction message.
2002
+ *
2003
+ * The event listener uses { once: true } to auto-remove after firing,
2004
+ * preventing memory leaks if this method is called multiple times.
2005
+ */
2006
+ waitForEviction() {
2007
+ return new Promise((_, reject) => {
2008
+ if (this.abortSignal.aborted) {
2009
+ reject(new EvictedError());
2010
+ return;
2011
+ }
2012
+ this.abortSignal.addEventListener(
2013
+ "abort",
2014
+ () => {
2015
+ reject(new EvictedError());
2016
+ },
2017
+ { once: true }
2018
+ );
2019
+ });
2020
+ }
2021
+ // === Step ===
2022
+ async step(nameOrConfig, run) {
2023
+ this.assertNotInProgress();
2024
+ this.checkEvicted();
2025
+ const config2 = typeof nameOrConfig === "string" ? { name: nameOrConfig, run } : nameOrConfig;
2026
+ this.entryInProgress = true;
2027
+ try {
2028
+ return await this.executeStep(config2);
2029
+ } finally {
2030
+ this.entryInProgress = false;
2031
+ }
2032
+ }
2033
+ async tryStep(nameOrConfig, run) {
2034
+ const config2 = typeof nameOrConfig === "string" ? {
2035
+ name: nameOrConfig,
2036
+ run
2037
+ } : nameOrConfig;
2038
+ try {
2039
+ return {
2040
+ ok: true,
2041
+ value: await this.step(config2)
2042
+ };
2043
+ } catch (error) {
2044
+ if (shouldRethrowTryError(error)) {
2045
+ throw error;
2046
+ }
2047
+ const failure = readTryStepFailure(error);
2048
+ if (!failure || !shouldCatchTryStepFailure(failure, config2.catch)) {
2049
+ throw error;
2050
+ }
2051
+ return {
2052
+ ok: false,
2053
+ failure
2054
+ };
2055
+ }
2056
+ }
2057
+ async try(nameOrConfig, run) {
2058
+ this.assertNotInProgress();
2059
+ this.checkEvicted();
2060
+ const config2 = typeof nameOrConfig === "string" ? {
2061
+ name: nameOrConfig,
2062
+ run
2063
+ } : nameOrConfig;
2064
+ this.entryInProgress = true;
2065
+ try {
2066
+ return await this.executeTry(config2);
2067
+ } finally {
2068
+ this.entryInProgress = false;
2069
+ }
2070
+ }
2071
+ async executeTry(config2) {
2072
+ this.checkDuplicateName(config2.name);
2073
+ const location = appendName(
2074
+ this.storage,
2075
+ this.currentLocation,
2076
+ config2.name
2077
+ );
2078
+ const blockCtx = this.createBranch(location);
2079
+ try {
2080
+ const value = await config2.run(blockCtx);
2081
+ blockCtx.validateComplete();
2082
+ return {
2083
+ ok: true,
2084
+ value
2085
+ };
2086
+ } catch (error) {
2087
+ if (shouldRethrowTryError(error)) {
2088
+ throw error;
2089
+ }
2090
+ const stepFailure = readTryStepFailure(error);
2091
+ if (stepFailure) {
2092
+ const failure = {
2093
+ source: "step",
2094
+ name: stepFailure.stepName,
2095
+ error: stepFailure.error,
2096
+ step: stepFailure
2097
+ };
2098
+ if (!shouldCatchTryBlockFailure(failure, config2.catch)) {
2099
+ throw error;
2100
+ }
2101
+ return {
2102
+ ok: false,
2103
+ failure
2104
+ };
2105
+ }
2106
+ const operationFailure = readTryBlockFailure(error);
2107
+ if (operationFailure) {
2108
+ const failure = {
2109
+ ...operationFailure,
2110
+ error: extractErrorInfo(error)
2111
+ };
2112
+ if (!shouldCatchTryBlockFailure(failure, config2.catch)) {
2113
+ throw error;
2114
+ }
2115
+ return {
2116
+ ok: false,
2117
+ failure
2118
+ };
2119
+ }
2120
+ if (error instanceof RollbackError) {
2121
+ const failure = {
2122
+ source: "block",
2123
+ name: config2.name,
2124
+ error: extractErrorInfo(error)
2125
+ };
2126
+ if (!shouldCatchTryBlockFailure(failure, config2.catch)) {
2127
+ throw error;
2128
+ }
2129
+ return {
2130
+ ok: false,
2131
+ failure
2132
+ };
2133
+ }
2134
+ throw error;
2135
+ }
2136
+ }
2137
+ async executeStep(config2) {
2138
+ this.ensureRollbackCheckpoint(config2);
2139
+ if (this.mode === "rollback") {
2140
+ return await this.executeStepRollback(config2);
2141
+ }
2142
+ this.checkDuplicateName(config2.name);
2143
+ const location = appendName(
2144
+ this.storage,
2145
+ this.currentLocation,
2146
+ config2.name
2147
+ );
2148
+ const key = locationToKey(this.storage, location);
2149
+ const existing = this.storage.history.entries.get(key);
2150
+ this.markVisited(key);
2151
+ if (existing) {
2152
+ if (existing.kind.type !== "step") {
2153
+ throw new HistoryDivergedError(
2154
+ `Expected step "${config2.name}" at ${key}, found ${existing.kind.type}`
2155
+ );
2156
+ }
2157
+ const stepData = existing.kind.data;
2158
+ const metadata2 = await loadMetadata(
2159
+ this.storage,
2160
+ this.driver,
2161
+ existing.id
2162
+ );
2163
+ if (metadata2.status === "completed" || stepData.output !== void 0) {
2164
+ return stepData.output;
2165
+ }
2166
+ const maxRetries2 = _nullishCoalesce(config2.maxRetries, () => ( DEFAULT_MAX_RETRIES));
2167
+ if (metadata2.attempts > maxRetries2) {
2168
+ const lastError = _nullishCoalesce(stepData.error, () => ( metadata2.error));
2169
+ const exhaustedError = new StepExhaustedError(
2170
+ config2.name,
2171
+ lastError
2172
+ );
2173
+ attachTryStepFailure(
2174
+ exhaustedError,
2175
+ getTryStepFailureFromExhaustedError(
2176
+ config2.name,
2177
+ metadata2.attempts,
2178
+ exhaustedError
2179
+ )
2180
+ );
2181
+ markErrorReported(exhaustedError);
2182
+ if (metadata2.status !== "exhausted") {
2183
+ metadata2.status = "exhausted";
2184
+ metadata2.dirty = true;
2185
+ await this.flushStorage();
2186
+ await this.notifyStepError(
2187
+ config2,
2188
+ metadata2.attempts,
2189
+ exhaustedError,
2190
+ { willRetry: false }
2191
+ );
2192
+ }
2193
+ throw exhaustedError;
2194
+ }
2195
+ const backoffDelay = calculateBackoff(
2196
+ metadata2.attempts,
2197
+ _nullishCoalesce(config2.retryBackoffBase, () => ( DEFAULT_RETRY_BACKOFF_BASE)),
2198
+ _nullishCoalesce(config2.retryBackoffMax, () => ( DEFAULT_RETRY_BACKOFF_MAX))
2199
+ );
2200
+ const retryAt = metadata2.lastAttemptAt + backoffDelay;
2201
+ const now = Date.now();
2202
+ if (now < retryAt) {
2203
+ throw new SleepError(retryAt);
2204
+ }
2205
+ }
2206
+ const entry = _nullishCoalesce(existing, () => ( createEntry(location, { type: "step", data: {} })));
2207
+ if (!existing) {
2208
+ this.log("debug", {
2209
+ msg: "executing new step",
2210
+ step: config2.name,
2211
+ key
2212
+ });
2213
+ const nameIndex = registerName(this.storage, config2.name);
2214
+ entry.location = [...location];
2215
+ entry.location[entry.location.length - 1] = nameIndex;
2216
+ setEntry(this.storage, location, entry);
2217
+ } else {
2218
+ this.log("debug", { msg: "retrying step", step: config2.name, key });
2219
+ }
2220
+ const metadata = getOrCreateMetadata(this.storage, entry.id);
2221
+ const maxRetries = _nullishCoalesce(config2.maxRetries, () => ( DEFAULT_MAX_RETRIES));
2222
+ const retryBackoffBase = _nullishCoalesce(config2.retryBackoffBase, () => ( DEFAULT_RETRY_BACKOFF_BASE));
2223
+ const retryBackoffMax = _nullishCoalesce(config2.retryBackoffMax, () => ( DEFAULT_RETRY_BACKOFF_MAX));
2224
+ metadata.status = "running";
2225
+ metadata.attempts++;
2226
+ metadata.lastAttemptAt = Date.now();
2227
+ metadata.dirty = true;
2228
+ const timeout = _nullishCoalesce(config2.timeout, () => ( DEFAULT_STEP_TIMEOUT));
2229
+ try {
2230
+ const output = await this.executeWithTimeout(
2231
+ config2.run(),
2232
+ timeout,
2233
+ config2.name
2234
+ );
2235
+ if (entry.kind.type === "step") {
2236
+ entry.kind.data.output = output;
2237
+ }
2238
+ entry.dirty = true;
2239
+ metadata.status = "completed";
2240
+ metadata.error = void 0;
2241
+ metadata.completedAt = Date.now();
2242
+ if (!config2.ephemeral) {
2243
+ this.log("debug", {
2244
+ msg: "flushing step",
2245
+ step: config2.name,
2246
+ key
2247
+ });
2248
+ await this.flushStorage();
2249
+ }
2250
+ this.log("debug", {
2251
+ msg: "step completed",
2252
+ step: config2.name,
2253
+ key
2254
+ });
2255
+ return output;
2256
+ } catch (error) {
2257
+ if (error instanceof StepTimeoutError) {
2258
+ if (entry.kind.type === "step") {
2259
+ entry.kind.data.error = String(error);
2260
+ }
2261
+ entry.dirty = true;
2262
+ metadata.status = "exhausted";
2263
+ metadata.error = String(error);
2264
+ await this.flushStorage();
2265
+ await this.notifyStepError(config2, metadata.attempts, error, {
2266
+ willRetry: false
2267
+ });
2268
+ throw markErrorReported(
2269
+ attachTryStepFailure(
2270
+ new CriticalError(error.message),
2271
+ {
2272
+ kind: "timeout",
2273
+ stepName: config2.name,
2274
+ attempts: metadata.attempts,
2275
+ error: extractErrorInfo(error)
2276
+ }
2277
+ )
2278
+ );
2279
+ }
2280
+ if (error instanceof CriticalError || error instanceof RollbackError) {
2281
+ if (entry.kind.type === "step") {
2282
+ entry.kind.data.error = String(error);
2283
+ }
2284
+ entry.dirty = true;
2285
+ metadata.status = "exhausted";
2286
+ metadata.error = String(error);
2287
+ await this.flushStorage();
2288
+ await this.notifyStepError(config2, metadata.attempts, error, {
2289
+ willRetry: false
2290
+ });
2291
+ throw markErrorReported(
2292
+ attachTryStepFailure(error, {
2293
+ kind: error instanceof RollbackError ? "rollback" : "critical",
2294
+ stepName: config2.name,
2295
+ attempts: metadata.attempts,
2296
+ error: extractErrorInfo(error)
2297
+ })
2298
+ );
2299
+ }
2300
+ if (entry.kind.type === "step") {
2301
+ entry.kind.data.error = String(error);
2302
+ }
2303
+ entry.dirty = true;
2304
+ const willRetry = metadata.attempts <= maxRetries;
2305
+ metadata.status = willRetry ? "failed" : "exhausted";
2306
+ metadata.error = String(error);
2307
+ await this.flushStorage();
2308
+ if (willRetry) {
2309
+ const retryDelay = calculateBackoff(
2310
+ metadata.attempts,
2311
+ retryBackoffBase,
2312
+ retryBackoffMax
2313
+ );
2314
+ const retryAt = metadata.lastAttemptAt + retryDelay;
2315
+ await this.notifyStepError(config2, metadata.attempts, error, {
2316
+ willRetry: true,
2317
+ retryDelay,
2318
+ retryAt
2319
+ });
2320
+ throw new StepFailedError(
2321
+ config2.name,
2322
+ error,
2323
+ metadata.attempts,
2324
+ retryAt
2325
+ );
2326
+ }
2327
+ const exhaustedError = markErrorReported(
2328
+ attachTryStepFailure(
2329
+ new StepExhaustedError(config2.name, String(error)),
2330
+ {
2331
+ kind: "exhausted",
2332
+ stepName: config2.name,
2333
+ attempts: metadata.attempts,
2334
+ error: extractErrorInfo(error)
2335
+ }
2336
+ )
2337
+ );
2338
+ await this.notifyStepError(config2, metadata.attempts, error, {
2339
+ willRetry: false
2340
+ });
2341
+ throw exhaustedError;
2342
+ }
2343
+ }
2344
+ /**
2345
+ * Execute a promise with timeout.
2346
+ *
2347
+ * Note: This does NOT cancel the underlying operation. JavaScript Promises
2348
+ * cannot be cancelled once started. When a timeout occurs:
2349
+ * - The step is marked as failed with StepTimeoutError
2350
+ * - The underlying async operation continues running in the background
2351
+ * - Any side effects from the operation may still occur
2352
+ *
2353
+ * For cancellable operations, pass ctx.abortSignal to APIs that support AbortSignal:
2354
+ *
2355
+ * return fetch(url, { signal: ctx.abortSignal });
2356
+
2357
+ * });
2358
+ *
2359
+ * Or check ctx.isEvicted() periodically in long-running loops.
2360
+ */
2361
+ async executeStepRollback(config2) {
2362
+ this.checkDuplicateName(config2.name);
2363
+ this.ensureRollbackCheckpoint(config2);
2364
+ const location = appendName(
2365
+ this.storage,
2366
+ this.currentLocation,
2367
+ config2.name
2368
+ );
2369
+ const key = locationToKey(this.storage, location);
2370
+ const existing = this.storage.history.entries.get(key);
2371
+ this.markVisited(key);
2372
+ if (!existing || existing.kind.type !== "step") {
2373
+ this.stopRollback();
2374
+ }
2375
+ const metadata = await loadMetadata(
2376
+ this.storage,
2377
+ this.driver,
2378
+ existing.id
2379
+ );
2380
+ if (metadata.status !== "completed") {
2381
+ this.stopRollback();
2382
+ }
2383
+ const output = existing.kind.data.output;
2384
+ this.registerRollbackAction(config2, existing.id, output, metadata);
2385
+ return output;
2386
+ }
2387
+ async executeWithTimeout(promise, timeoutMs, stepName) {
2388
+ if (timeoutMs <= 0) {
2389
+ return promise;
2390
+ }
2391
+ let timeoutId;
2392
+ const timeoutPromise = new Promise((_, reject) => {
2393
+ timeoutId = setTimeout(() => {
2394
+ reject(new StepTimeoutError(stepName, timeoutMs));
2395
+ }, timeoutMs);
2396
+ });
2397
+ try {
2398
+ return await Promise.race([promise, timeoutPromise]);
2399
+ } finally {
2400
+ if (timeoutId !== void 0) {
2401
+ clearTimeout(timeoutId);
2402
+ }
2403
+ }
2404
+ }
2405
+ // === Loop ===
2406
+ async loop(nameOrConfig, run) {
2407
+ this.assertNotInProgress();
2408
+ this.checkEvicted();
2409
+ const config2 = typeof nameOrConfig === "string" ? { name: nameOrConfig, run } : nameOrConfig;
2410
+ this.entryInProgress = true;
2411
+ try {
2412
+ return await this.executeLoop(config2);
2413
+ } finally {
2414
+ this.entryInProgress = false;
2415
+ }
2416
+ }
2417
+ async executeLoop(config2) {
2418
+ this.checkDuplicateName(config2.name);
2419
+ const location = appendName(
2420
+ this.storage,
2421
+ this.currentLocation,
2422
+ config2.name
2423
+ );
2424
+ const key = locationToKey(this.storage, location);
2425
+ const existing = this.storage.history.entries.get(key);
2426
+ this.markVisited(key);
2427
+ let entry;
2428
+ let metadata;
2429
+ let state;
2430
+ let iteration;
2431
+ let rollbackSingleIteration = false;
2432
+ let rollbackIterationRan = false;
2433
+ let rollbackOutput;
2434
+ const rollbackMode = this.mode === "rollback";
2435
+ if (existing) {
2436
+ if (existing.kind.type !== "loop") {
2437
+ throw new HistoryDivergedError(
2438
+ `Expected loop "${config2.name}" at ${key}, found ${existing.kind.type}`
2439
+ );
2440
+ }
2441
+ const loopData = existing.kind.data;
2442
+ metadata = await loadMetadata(
2443
+ this.storage,
2444
+ this.driver,
2445
+ existing.id
2446
+ );
2447
+ if (rollbackMode) {
2448
+ if (loopData.output !== void 0) {
2449
+ return loopData.output;
2450
+ }
2451
+ rollbackSingleIteration = true;
2452
+ rollbackIterationRan = false;
2453
+ rollbackOutput = void 0;
2454
+ }
2455
+ if (metadata.status === "completed") {
2456
+ return loopData.output;
2457
+ }
2458
+ if (loopData.output !== void 0) {
2459
+ return loopData.output;
2460
+ }
2461
+ entry = existing;
2462
+ state = loopData.state;
2463
+ iteration = loopData.iteration;
2464
+ if (rollbackMode) {
2465
+ rollbackOutput = loopData.output;
2466
+ rollbackIterationRan = rollbackOutput !== void 0;
2467
+ }
2468
+ } else {
2469
+ this.stopRollbackIfIncomplete(true);
2470
+ state = config2.state;
2471
+ iteration = 0;
2472
+ entry = createEntry(location, {
2473
+ type: "loop",
2474
+ data: { state, iteration }
2475
+ });
2476
+ setEntry(this.storage, location, entry);
2477
+ metadata = getOrCreateMetadata(this.storage, entry.id);
2478
+ }
2479
+ if (metadata) {
2480
+ metadata.status = "running";
2481
+ metadata.error = void 0;
2482
+ metadata.dirty = true;
2483
+ }
2484
+ const historyPruneInterval = _nullishCoalesce(config2.historyPruneInterval, () => ( DEFAULT_LOOP_HISTORY_PRUNE_INTERVAL));
2485
+ const historySize = _nullishCoalesce(config2.historySize, () => ( historyPruneInterval));
2486
+ let lastPrunedUpTo = 0;
2487
+ let deferredFlush = null;
2488
+ while (true) {
2489
+ if (deferredFlush) {
2490
+ await deferredFlush;
2491
+ deferredFlush = null;
2492
+ }
2493
+ if (rollbackMode && rollbackSingleIteration) {
2494
+ if (rollbackIterationRan) {
2495
+ return rollbackOutput;
2496
+ }
2497
+ this.stopRollbackIfIncomplete(true);
2498
+ }
2499
+ this.checkEvicted();
2500
+ const iterationLocation = appendLoopIteration(
2501
+ this.storage,
2502
+ location,
2503
+ config2.name,
2504
+ iteration
2505
+ );
2506
+ const branchCtx = this.createBranch(iterationLocation);
2507
+ const iterationResult = await config2.run(branchCtx, state);
2508
+ if (iterationResult === void 0 && state !== void 0) {
2509
+ throw new Error(
2510
+ `Loop "${config2.name}" returned undefined for a stateful iteration. Return Loop.continue(state) or Loop.break(value).`
2511
+ );
2512
+ }
2513
+ const result = iterationResult === void 0 ? { continue: true, state } : iterationResult;
2514
+ branchCtx.validateComplete();
2515
+ if ("break" in result && result.break) {
2516
+ if (entry.kind.type === "loop") {
2517
+ entry.kind.data.output = result.value;
2518
+ entry.kind.data.state = state;
2519
+ entry.kind.data.iteration = iteration;
2520
+ }
2521
+ entry.dirty = true;
2522
+ if (metadata) {
2523
+ metadata.status = "completed";
2524
+ metadata.completedAt = Date.now();
2525
+ metadata.dirty = true;
2526
+ }
2527
+ const deletions = this.collectLoopPruning(
2528
+ location,
2529
+ iteration + 1,
2530
+ historySize,
2531
+ lastPrunedUpTo
2532
+ );
2533
+ await this.flushStorageWithDeletions(deletions);
2534
+ if (rollbackMode && rollbackSingleIteration) {
2535
+ rollbackOutput = result.value;
2536
+ rollbackIterationRan = true;
2537
+ continue;
2538
+ }
2539
+ return result.value;
2540
+ }
2541
+ if ("continue" in result && result.continue) {
2542
+ state = result.state;
2543
+ }
2544
+ iteration++;
2545
+ if (!rollbackMode) {
2546
+ if (entry.kind.type === "loop") {
2547
+ entry.kind.data.state = state;
2548
+ entry.kind.data.iteration = iteration;
2549
+ }
2550
+ entry.dirty = true;
2551
+ }
2552
+ if (iteration % historyPruneInterval === 0) {
2553
+ const deletions = this.collectLoopPruning(
2554
+ location,
2555
+ iteration,
2556
+ historySize,
2557
+ lastPrunedUpTo
2558
+ );
2559
+ lastPrunedUpTo = Math.max(0, iteration - historySize);
2560
+ deferredFlush = this.flushStorageWithDeletions(deletions);
2561
+ }
2562
+ }
2563
+ }
2564
+ /**
2565
+ * Collect pending deletions for loop history pruning.
2566
+ *
2567
+ * Only deletes iterations in the range [fromIteration, keepFrom) where
2568
+ * keepFrom = currentIteration - historySize. This avoids re-scanning
2569
+ * already-deleted iterations.
2570
+ */
2571
+ collectLoopPruning(loopLocation, currentIteration, historySize, fromIteration) {
2572
+ if (currentIteration <= historySize) {
2573
+ return void 0;
2574
+ }
2575
+ const keepFrom = Math.max(0, currentIteration - historySize);
2576
+ if (fromIteration >= keepFrom) {
2577
+ return void 0;
2578
+ }
2579
+ const loopSegment = loopLocation[loopLocation.length - 1];
2580
+ if (typeof loopSegment !== "number") {
2581
+ throw new Error("Expected loop location to end with a name index");
2582
+ }
2583
+ const range = buildLoopIterationRange(
2584
+ loopLocation,
2585
+ loopSegment,
2586
+ fromIteration,
2587
+ keepFrom
2588
+ );
2589
+ const metadataKeys = [];
2590
+ for (const [key, entry] of this.storage.history.entries) {
2591
+ if (!isLocationPrefix(loopLocation, entry.location)) {
2592
+ continue;
2593
+ }
2594
+ const iterationSegment = entry.location[loopLocation.length];
2595
+ if (!iterationSegment || typeof iterationSegment === "number" || iterationSegment.loop !== loopSegment || iterationSegment.iteration < fromIteration || iterationSegment.iteration >= keepFrom) {
2596
+ continue;
2597
+ }
2598
+ metadataKeys.push(buildEntryMetadataKey(entry.id));
2599
+ this.storage.entryMetadata.delete(entry.id);
2600
+ this.storage.history.entries.delete(key);
2601
+ }
2602
+ return {
2603
+ prefixes: [],
2604
+ keys: metadataKeys,
2605
+ ranges: [range]
2606
+ };
2607
+ }
2608
+ /**
2609
+ * Flush storage with optional pending deletions so pruning
2610
+ * happens alongside the state write.
2611
+ */
2612
+ async flushStorageWithDeletions(deletions) {
2613
+ await flush(this.storage, this.driver, this.historyNotifier, deletions);
2614
+ }
2615
+ // === Sleep ===
2616
+ async sleep(name, durationMs) {
2617
+ const deadline = Date.now() + durationMs;
2618
+ return this.sleepUntil(name, deadline);
2619
+ }
2620
+ async sleepUntil(name, timestampMs) {
2621
+ this.assertNotInProgress();
2622
+ this.checkEvicted();
2623
+ this.entryInProgress = true;
2624
+ try {
2625
+ await this.executeSleep(name, timestampMs);
2626
+ } finally {
2627
+ this.entryInProgress = false;
2628
+ }
2629
+ }
2630
+ async executeSleep(name, deadline) {
2631
+ this.checkDuplicateName(name);
2632
+ const location = appendName(this.storage, this.currentLocation, name);
2633
+ const key = locationToKey(this.storage, location);
2634
+ const existing = this.storage.history.entries.get(key);
2635
+ this.markVisited(key);
2636
+ let entry;
2637
+ if (existing) {
2638
+ if (existing.kind.type !== "sleep") {
2639
+ throw new HistoryDivergedError(
2640
+ `Expected sleep "${name}" at ${key}, found ${existing.kind.type}`
2641
+ );
2642
+ }
2643
+ const sleepData = existing.kind.data;
2644
+ if (this.mode === "rollback") {
2645
+ this.stopRollbackIfIncomplete(sleepData.state === "pending");
2646
+ return;
2647
+ }
2648
+ if (sleepData.state !== "pending") {
2649
+ return;
2650
+ }
2651
+ deadline = sleepData.deadline;
2652
+ entry = existing;
2653
+ } else {
2654
+ this.stopRollbackIfIncomplete(true);
2655
+ entry = createEntry(location, {
2656
+ type: "sleep",
2657
+ data: { deadline, state: "pending" }
2658
+ });
2659
+ setEntry(this.storage, location, entry);
2660
+ entry.dirty = true;
2661
+ await this.flushStorage();
2662
+ }
2663
+ const now = Date.now();
2664
+ const remaining = deadline - now;
2665
+ if (remaining <= 0) {
2666
+ if (entry.kind.type === "sleep") {
2667
+ entry.kind.data.state = "completed";
2668
+ }
2669
+ entry.dirty = true;
2670
+ await this.flushStorage();
2671
+ return;
2672
+ }
2673
+ if (remaining < this.driver.workerPollInterval) {
2674
+ await Promise.race([sleep(remaining), this.waitForEviction()]);
2675
+ this.checkEvicted();
2676
+ if (entry.kind.type === "sleep") {
2677
+ entry.kind.data.state = "completed";
2678
+ }
2679
+ entry.dirty = true;
2680
+ await this.flushStorage();
2681
+ return;
2682
+ }
2683
+ throw new SleepError(deadline);
2684
+ }
2685
+ // === Rollback Checkpoint ===
2686
+ async rollbackCheckpoint(name) {
2687
+ this.assertNotInProgress();
2688
+ this.checkEvicted();
2689
+ this.entryInProgress = true;
2690
+ try {
2691
+ await this.executeRollbackCheckpoint(name);
2692
+ } finally {
2693
+ this.entryInProgress = false;
2694
+ }
2695
+ }
2696
+ async executeRollbackCheckpoint(name) {
2697
+ this.checkDuplicateName(name);
2698
+ const location = appendName(this.storage, this.currentLocation, name);
2699
+ const key = locationToKey(this.storage, location);
2700
+ const existing = this.storage.history.entries.get(key);
2701
+ this.markVisited(key);
2702
+ if (existing) {
2703
+ if (existing.kind.type !== "rollback_checkpoint") {
2704
+ throw new HistoryDivergedError(
2705
+ `Expected rollback checkpoint "${name}" at ${key}, found ${existing.kind.type}`
2706
+ );
2707
+ }
2708
+ this.rollbackCheckpointSet = true;
2709
+ return;
2710
+ }
2711
+ if (this.mode === "rollback") {
2712
+ throw new HistoryDivergedError(
2713
+ `Missing rollback checkpoint "${name}" at ${key}`
2714
+ );
2715
+ }
2716
+ const entry = createEntry(location, {
2717
+ type: "rollback_checkpoint",
2718
+ data: { name }
2719
+ });
2720
+ setEntry(this.storage, location, entry);
2721
+ entry.dirty = true;
2722
+ await this.flushStorage();
2723
+ this.rollbackCheckpointSet = true;
2724
+ }
2725
+ // === Queue ===
2726
+ async queueSend(name, body) {
2727
+ const message = {
2728
+ id: crypto.randomUUID(),
2729
+ name,
2730
+ data: body,
2731
+ sentAt: Date.now()
2732
+ };
2733
+ await this.messageDriver.addMessage(message);
2734
+ }
2735
+ async queueNext(name, opts) {
2736
+ const messages = await this.queueNextBatch(name, {
2737
+ ..._nullishCoalesce(opts, () => ( {})),
2738
+ count: 1
2739
+ });
2740
+ const message = messages[0];
2741
+ if (!message) {
2742
+ throw new Error(
2743
+ `queue.next("${name}") timed out before receiving a message. Use queue.nextBatch(...) for optional/time-limited reads.`
2744
+ );
2745
+ }
2746
+ return message;
2747
+ }
2748
+ async queueNextBatch(name, opts) {
2749
+ this.assertNotInProgress();
2750
+ this.checkEvicted();
2751
+ this.entryInProgress = true;
2752
+ try {
2753
+ return await this.executeQueueNextBatch(name, opts);
2754
+ } finally {
2755
+ this.entryInProgress = false;
2756
+ }
2757
+ }
2758
+ async executeQueueNextBatch(name, opts) {
2759
+ if (this.pendingCompletableMessageIds.size > 0) {
2760
+ throw new Error(
2761
+ "Previous completable queue message is not completed. Call `message.complete(...)` before receiving the next message."
2762
+ );
2763
+ }
2764
+ const resolvedOpts = _nullishCoalesce(opts, () => ( {}));
2765
+ const messageNames = this.normalizeQueueNames(resolvedOpts.names);
2766
+ const messageNameLabel = this.messageNamesLabel(messageNames);
2767
+ const count = Math.max(1, _nullishCoalesce(resolvedOpts.count, () => ( 1)));
2768
+ const completable = resolvedOpts.completable === true;
2769
+ this.checkDuplicateName(name);
2770
+ const countLocation = appendName(
2771
+ this.storage,
2772
+ this.currentLocation,
2773
+ `${name}:count`
2774
+ );
2775
+ const countKey = locationToKey(this.storage, countLocation);
2776
+ const existingCount = this.storage.history.entries.get(countKey);
2777
+ this.markVisited(countKey);
2778
+ this.stopRollbackIfMissing(existingCount);
2779
+ let deadline;
2780
+ let deadlineEntry;
2781
+ if (resolvedOpts.timeout !== void 0) {
2782
+ const deadlineLocation = appendName(
2783
+ this.storage,
2784
+ this.currentLocation,
2785
+ `${name}:deadline`
2786
+ );
2787
+ const deadlineKey = locationToKey(this.storage, deadlineLocation);
2788
+ deadlineEntry = this.storage.history.entries.get(deadlineKey);
2789
+ this.markVisited(deadlineKey);
2790
+ this.stopRollbackIfMissing(deadlineEntry);
2791
+ if (deadlineEntry && deadlineEntry.kind.type === "sleep") {
2792
+ deadline = deadlineEntry.kind.data.deadline;
2793
+ } else {
2794
+ deadline = Date.now() + resolvedOpts.timeout;
2795
+ const created = createEntry(deadlineLocation, {
2796
+ type: "sleep",
2797
+ data: { deadline, state: "pending" }
2798
+ });
2799
+ setEntry(this.storage, deadlineLocation, created);
2800
+ created.dirty = true;
2801
+ await this.flushStorage();
2802
+ deadlineEntry = created;
2803
+ }
2804
+ }
2805
+ if (existingCount && existingCount.kind.type === "message") {
2806
+ const replayCount = existingCount.kind.data.data;
2807
+ return await this.readReplayQueueMessages(
2808
+ name,
2809
+ replayCount,
2810
+ completable
2811
+ );
2812
+ }
2813
+ const now = Date.now();
2814
+ if (deadline !== void 0 && now >= deadline) {
2815
+ if (deadlineEntry && deadlineEntry.kind.type === "sleep") {
2816
+ deadlineEntry.kind.data.state = "completed";
2817
+ deadlineEntry.dirty = true;
2818
+ }
2819
+ await this.recordQueueCountEntry(
2820
+ countLocation,
2821
+ `${messageNameLabel}:count`,
2822
+ 0
2823
+ );
2824
+ return [];
2825
+ }
2826
+ const received = await this.receiveMessagesNow(
2827
+ messageNames,
2828
+ count,
2829
+ completable
2830
+ );
2831
+ if (received.length > 0) {
2832
+ const historyMessages = received.map(
2833
+ (message) => this.toWorkflowQueueMessage(message)
2834
+ );
2835
+ if (deadlineEntry && deadlineEntry.kind.type === "sleep") {
2836
+ deadlineEntry.kind.data.state = "interrupted";
2837
+ deadlineEntry.dirty = true;
2838
+ }
2839
+ await this.recordQueueMessages(
2840
+ name,
2841
+ countLocation,
2842
+ messageNames,
2843
+ historyMessages
2844
+ );
2845
+ const queueMessages = received.map(
2846
+ (message, index) => this.createQueueMessage(message, completable, {
2847
+ historyLocation: appendName(
2848
+ this.storage,
2849
+ this.currentLocation,
2850
+ `${name}:${index}`
2851
+ )
2852
+ })
2853
+ );
2854
+ return queueMessages;
2855
+ }
2856
+ if (deadline === void 0) {
2857
+ throw new MessageWaitError(messageNames);
2858
+ }
2859
+ throw new SleepError(deadline, messageNames);
2860
+ }
2861
+ normalizeQueueNames(names) {
2862
+ if (!names || names.length === 0) {
2863
+ return [];
2864
+ }
2865
+ const deduped = [];
2866
+ const seen = /* @__PURE__ */ new Set();
2867
+ for (const name of names) {
2868
+ if (seen.has(name)) {
2869
+ continue;
2870
+ }
2871
+ seen.add(name);
2872
+ deduped.push(name);
2873
+ }
2874
+ return deduped;
2875
+ }
2876
+ messageNamesLabel(messageNames) {
2877
+ if (messageNames.length === 0) {
2878
+ return "*";
2879
+ }
2880
+ return messageNames.length === 1 ? messageNames[0] : messageNames.join("|");
2881
+ }
2882
+ async receiveMessagesNow(messageNames, count, completable) {
2883
+ return await this.messageDriver.receiveMessages({
2884
+ names: messageNames.length > 0 ? messageNames : void 0,
2885
+ count,
2886
+ completable
2887
+ });
2888
+ }
2889
+ async recordQueueMessages(name, countLocation, messageNames, messages) {
2890
+ for (let i = 0; i < messages.length; i++) {
2891
+ const messageLocation = appendName(
2892
+ this.storage,
2893
+ this.currentLocation,
2894
+ `${name}:${i}`
2895
+ );
2896
+ const messageEntry = createEntry(messageLocation, {
2897
+ type: "message",
2898
+ data: {
2899
+ name: messages[i].name,
2900
+ data: this.toHistoryQueueMessage(messages[i])
2901
+ }
2902
+ });
2903
+ setEntry(this.storage, messageLocation, messageEntry);
2904
+ this.markVisited(locationToKey(this.storage, messageLocation));
2905
+ }
2906
+ await this.recordQueueCountEntry(
2907
+ countLocation,
2908
+ `${this.messageNamesLabel(messageNames)}:count`,
2909
+ messages.length
2910
+ );
2911
+ }
2912
+ async recordQueueCountEntry(countLocation, countLabel, count) {
2913
+ const countEntry = createEntry(countLocation, {
2914
+ type: "message",
2915
+ data: {
2916
+ name: countLabel,
2917
+ data: count
2918
+ }
2919
+ });
2920
+ setEntry(this.storage, countLocation, countEntry);
2921
+ await this.flushStorage();
2922
+ }
2923
+ async readReplayQueueMessages(name, count, completable) {
2924
+ const results = [];
2925
+ for (let i = 0; i < count; i++) {
2926
+ const messageLocation = appendName(
2927
+ this.storage,
2928
+ this.currentLocation,
2929
+ `${name}:${i}`
2930
+ );
2931
+ const messageKey = locationToKey(this.storage, messageLocation);
2932
+ this.markVisited(messageKey);
2933
+ const existingMessage = this.storage.history.entries.get(messageKey);
2934
+ if (!existingMessage || existingMessage.kind.type !== "message") {
2935
+ throw new HistoryDivergedError(
2936
+ `Expected queue message "${name}:${i}" in history`
2937
+ );
2938
+ }
2939
+ const parsed = this.fromHistoryQueueMessage(
2940
+ existingMessage.kind.data.name,
2941
+ existingMessage.kind.data.data
2942
+ );
2943
+ results.push(
2944
+ this.createQueueMessage(parsed.message, completable, {
2945
+ historyLocation: messageLocation,
2946
+ completed: parsed.completed,
2947
+ replay: true
2948
+ })
2949
+ );
2950
+ }
2951
+ return results;
2952
+ }
2953
+ toWorkflowQueueMessage(message) {
2954
+ return {
2955
+ id: message.id,
2956
+ name: message.name,
2957
+ body: message.data,
2958
+ createdAt: message.sentAt
2959
+ };
2960
+ }
2961
+ createQueueMessage(message, completable, opts) {
2962
+ const queueMessage = this.toWorkflowQueueMessage(message);
2963
+ if (!completable) {
2964
+ return queueMessage;
2965
+ }
2966
+ if ((opts == null ? void 0 : opts.replay) && opts.completed) {
2967
+ return {
2968
+ ...queueMessage,
2969
+ complete: async () => {
2970
+ }
2971
+ };
2972
+ }
2973
+ const messageId = message.id;
2974
+ this.pendingCompletableMessageIds.add(messageId);
2975
+ let completed = false;
2976
+ return {
2977
+ ...queueMessage,
2978
+ complete: async (response) => {
2979
+ if (completed) {
2980
+ throw new Error("Queue message already completed");
2981
+ }
2982
+ completed = true;
2983
+ try {
2984
+ await this.completeMessage(message, response);
2985
+ await this.markQueueMessageCompleted(opts == null ? void 0 : opts.historyLocation);
2986
+ this.pendingCompletableMessageIds.delete(messageId);
2987
+ } catch (error) {
2988
+ completed = false;
2989
+ throw error;
2990
+ }
2991
+ }
2992
+ };
2993
+ }
2994
+ async markQueueMessageCompleted(historyLocation) {
2995
+ if (!historyLocation) {
2996
+ return;
2997
+ }
2998
+ const key = locationToKey(this.storage, historyLocation);
2999
+ const entry = this.storage.history.entries.get(key);
3000
+ if (!entry || entry.kind.type !== "message") {
3001
+ return;
3002
+ }
3003
+ const parsed = this.fromHistoryQueueMessage(
3004
+ entry.kind.data.name,
3005
+ entry.kind.data.data
3006
+ );
3007
+ entry.kind.data.data = this.toHistoryQueueMessage(
3008
+ this.toWorkflowQueueMessage(parsed.message),
3009
+ true
3010
+ );
3011
+ entry.dirty = true;
3012
+ await this.flushStorage();
3013
+ }
3014
+ async completeMessage(message, response) {
3015
+ if (message.complete) {
3016
+ await message.complete(response);
3017
+ return;
3018
+ }
3019
+ await this.messageDriver.completeMessage(message.id, response);
3020
+ }
3021
+ toHistoryQueueMessage(message, completed = false) {
3022
+ return {
3023
+ [QUEUE_HISTORY_MESSAGE_MARKER]: 1,
3024
+ id: message.id,
3025
+ name: message.name,
3026
+ body: message.body,
3027
+ createdAt: message.createdAt,
3028
+ completed
3029
+ };
3030
+ }
3031
+ fromHistoryQueueMessage(name, value) {
3032
+ if (typeof value === "object" && value !== null && value[QUEUE_HISTORY_MESSAGE_MARKER] === 1) {
3033
+ const serialized = value;
3034
+ const id = typeof serialized.id === "string" ? serialized.id : "";
3035
+ const serializedName = typeof serialized.name === "string" ? serialized.name : name;
3036
+ const createdAt = typeof serialized.createdAt === "number" ? serialized.createdAt : 0;
3037
+ const completed = typeof serialized.completed === "boolean" ? serialized.completed : false;
3038
+ return {
3039
+ message: {
3040
+ id,
3041
+ name: serializedName,
3042
+ data: serialized.body,
3043
+ sentAt: createdAt
3044
+ },
3045
+ completed
3046
+ };
3047
+ }
3048
+ return {
3049
+ message: {
3050
+ id: "",
3051
+ name,
3052
+ data: value,
3053
+ sentAt: 0
3054
+ },
3055
+ completed: false
3056
+ };
3057
+ }
3058
+ // === Join ===
3059
+ async join(name, branches) {
3060
+ this.assertNotInProgress();
3061
+ this.checkEvicted();
3062
+ this.entryInProgress = true;
3063
+ try {
3064
+ return await this.executeJoin(name, branches);
3065
+ } finally {
3066
+ this.entryInProgress = false;
3067
+ }
3068
+ }
3069
+ async executeJoin(name, branches) {
3070
+ this.checkDuplicateName(name);
3071
+ const location = appendName(this.storage, this.currentLocation, name);
3072
+ const key = locationToKey(this.storage, location);
3073
+ const existing = this.storage.history.entries.get(key);
3074
+ this.markVisited(key);
3075
+ this.stopRollbackIfMissing(existing);
3076
+ let entry;
3077
+ if (existing) {
3078
+ if (existing.kind.type !== "join") {
3079
+ throw new HistoryDivergedError(
3080
+ `Expected join "${name}" at ${key}, found ${existing.kind.type}`
3081
+ );
3082
+ }
3083
+ entry = existing;
3084
+ } else {
3085
+ entry = createEntry(location, {
3086
+ type: "join",
3087
+ data: {
3088
+ branches: Object.fromEntries(
3089
+ Object.keys(branches).map((k) => [
3090
+ k,
3091
+ { status: "pending" }
3092
+ ])
3093
+ )
3094
+ }
3095
+ });
3096
+ setEntry(this.storage, location, entry);
3097
+ entry.dirty = true;
3098
+ await this.flushStorage();
3099
+ }
3100
+ if (entry.kind.type !== "join") {
3101
+ throw new HistoryDivergedError("Entry type mismatch");
3102
+ }
3103
+ this.stopRollbackIfIncomplete(
3104
+ Object.values(entry.kind.data.branches).some(
3105
+ (branch) => branch.status !== "completed"
3106
+ )
3107
+ );
3108
+ const joinData = entry.kind.data;
3109
+ const results = {};
3110
+ const errors = {};
3111
+ let schedulerYieldState;
3112
+ let propagatedError;
3113
+ for (const [branchName, branchStatus] of Object.entries(
3114
+ joinData.branches
3115
+ )) {
3116
+ if (branchStatus.status === "completed") {
3117
+ results[branchName] = branchStatus.output;
3118
+ continue;
3119
+ }
3120
+ if (branchStatus.status === "failed") {
3121
+ errors[branchName] = new Error(
3122
+ _nullishCoalesce(branchStatus.error, () => ( "branch failed"))
3123
+ );
3124
+ }
3125
+ }
3126
+ const branchPromises = Object.entries(branches).map(
3127
+ async ([branchName, config2]) => {
3128
+ const branchStatus = joinData.branches[branchName];
3129
+ if (!branchStatus) {
3130
+ throw new HistoryDivergedError(
3131
+ `Expected join branch "${branchName}" in "${name}"`
3132
+ );
3133
+ }
3134
+ if (branchStatus.status === "completed") {
3135
+ results[branchName] = branchStatus.output;
3136
+ return;
3137
+ }
3138
+ if (branchStatus.status === "failed") {
3139
+ errors[branchName] = new Error(branchStatus.error);
3140
+ return;
3141
+ }
3142
+ const branchLocation = appendName(
3143
+ this.storage,
3144
+ location,
3145
+ branchName
3146
+ );
3147
+ const branchCtx = this.createBranch(branchLocation);
3148
+ branchStatus.status = "running";
3149
+ branchStatus.error = void 0;
3150
+ entry.dirty = true;
3151
+ try {
3152
+ const output = await config2.run(branchCtx);
3153
+ branchCtx.validateComplete();
3154
+ branchStatus.status = "completed";
3155
+ branchStatus.output = output;
3156
+ branchStatus.error = void 0;
3157
+ results[branchName] = output;
3158
+ } catch (error) {
3159
+ if (error instanceof SleepError || error instanceof MessageWaitError || error instanceof StepFailedError) {
3160
+ schedulerYieldState = mergeSchedulerYield(
3161
+ schedulerYieldState,
3162
+ error
3163
+ );
3164
+ branchStatus.status = "running";
3165
+ branchStatus.error = void 0;
3166
+ entry.dirty = true;
3167
+ return;
3168
+ }
3169
+ if (error instanceof EvictedError || error instanceof HistoryDivergedError || error instanceof EntryInProgressError || error instanceof RollbackCheckpointError || error instanceof RollbackStopError) {
3170
+ propagatedError = selectControlFlowError(
3171
+ propagatedError,
3172
+ error
3173
+ );
3174
+ branchStatus.status = "running";
3175
+ branchStatus.error = void 0;
3176
+ entry.dirty = true;
3177
+ return;
3178
+ }
3179
+ branchStatus.status = "failed";
3180
+ branchStatus.output = void 0;
3181
+ branchStatus.error = String(error);
3182
+ errors[branchName] = error;
3183
+ }
3184
+ entry.dirty = true;
3185
+ }
3186
+ );
3187
+ await Promise.allSettled(branchPromises);
3188
+ await this.flushStorage();
3189
+ if (propagatedError) {
3190
+ throw propagatedError;
3191
+ }
3192
+ if (Object.values(joinData.branches).some(
3193
+ (branch) => branch.status === "pending" || branch.status === "running"
3194
+ )) {
3195
+ if (!schedulerYieldState) {
3196
+ throw new Error(
3197
+ `Join "${name}" has pending branches without a scheduler yield`
3198
+ );
3199
+ }
3200
+ throw buildSchedulerYieldError(schedulerYieldState);
3201
+ }
3202
+ if (Object.keys(errors).length > 0) {
3203
+ throw attachTryBlockFailure(new JoinError(errors), {
3204
+ source: "join",
3205
+ name
3206
+ });
3207
+ }
3208
+ return results;
3209
+ }
3210
+ // === Race ===
3211
+ async race(name, branches) {
3212
+ this.assertNotInProgress();
3213
+ this.checkEvicted();
3214
+ this.entryInProgress = true;
3215
+ try {
3216
+ return await this.executeRace(name, branches);
3217
+ } finally {
3218
+ this.entryInProgress = false;
3219
+ }
3220
+ }
3221
+ async executeRace(name, branches) {
3222
+ this.checkDuplicateName(name);
3223
+ const location = appendName(this.storage, this.currentLocation, name);
3224
+ const key = locationToKey(this.storage, location);
3225
+ const existing = this.storage.history.entries.get(key);
3226
+ this.markVisited(key);
3227
+ this.stopRollbackIfMissing(existing);
3228
+ let entry;
3229
+ if (existing) {
3230
+ if (existing.kind.type !== "race") {
3231
+ throw new HistoryDivergedError(
3232
+ `Expected race "${name}" at ${key}, found ${existing.kind.type}`
3233
+ );
3234
+ }
3235
+ entry = existing;
3236
+ const raceKind = existing.kind;
3237
+ if (raceKind.data.winner !== null) {
3238
+ const winnerStatus = raceKind.data.branches[raceKind.data.winner];
3239
+ return {
3240
+ winner: raceKind.data.winner,
3241
+ value: winnerStatus.output
3242
+ };
3243
+ }
3244
+ this.stopRollbackIfIncomplete(true);
3245
+ } else {
3246
+ entry = createEntry(location, {
3247
+ type: "race",
3248
+ data: {
3249
+ winner: null,
3250
+ branches: Object.fromEntries(
3251
+ branches.map((b) => [
3252
+ b.name,
3253
+ { status: "pending" }
3254
+ ])
3255
+ )
3256
+ }
3257
+ });
3258
+ setEntry(this.storage, location, entry);
3259
+ entry.dirty = true;
3260
+ await this.flushStorage();
3261
+ }
3262
+ if (entry.kind.type !== "race") {
3263
+ throw new HistoryDivergedError("Entry type mismatch");
3264
+ }
3265
+ const raceData = entry.kind.data;
3266
+ const raceAbortController = new AbortController();
3267
+ const branchPromises = [];
3268
+ let winnerName = null;
3269
+ let winnerValue;
3270
+ let hasWinner = false;
3271
+ const errors = {};
3272
+ const lateErrors = [];
3273
+ let schedulerYieldState;
3274
+ let propagatedError;
3275
+ for (const branch of branches) {
3276
+ const branchStatus = raceData.branches[branch.name];
3277
+ if (!branchStatus) {
3278
+ throw new HistoryDivergedError(
3279
+ `Expected race branch "${branch.name}" in "${name}"`
3280
+ );
3281
+ }
3282
+ if (branchStatus.status !== "pending" && branchStatus.status !== "running") {
3283
+ if (branchStatus.status === "failed") {
3284
+ errors[branch.name] = new Error(
3285
+ _nullishCoalesce(branchStatus.error, () => ( "branch failed"))
3286
+ );
3287
+ }
3288
+ if (branchStatus.status === "completed" && !hasWinner) {
3289
+ hasWinner = true;
3290
+ winnerName = branch.name;
3291
+ winnerValue = branchStatus.output;
3292
+ }
3293
+ }
3294
+ }
3295
+ if (hasWinner && winnerName !== null) {
3296
+ return { winner: winnerName, value: winnerValue };
3297
+ }
3298
+ for (const branch of branches) {
3299
+ const branchStatus = raceData.branches[branch.name];
3300
+ if (!branchStatus) {
3301
+ throw new HistoryDivergedError(
3302
+ `Expected race branch "${branch.name}" in "${name}"`
3303
+ );
3304
+ }
3305
+ if (branchStatus.status !== "pending" && branchStatus.status !== "running") {
3306
+ continue;
3307
+ }
3308
+ const branchLocation = appendName(
3309
+ this.storage,
3310
+ location,
3311
+ branch.name
3312
+ );
3313
+ const branchCtx = this.createBranch(
3314
+ branchLocation,
3315
+ raceAbortController
3316
+ );
3317
+ branchStatus.status = "running";
3318
+ branchStatus.error = void 0;
3319
+ entry.dirty = true;
3320
+ const branchPromise = branch.run(branchCtx).then(
3321
+ async (output) => {
3322
+ if (hasWinner) {
3323
+ branchStatus.status = "completed";
3324
+ branchStatus.output = output;
3325
+ branchStatus.error = void 0;
3326
+ entry.dirty = true;
3327
+ return;
3328
+ }
3329
+ if (propagatedError) {
3330
+ branchStatus.status = "completed";
3331
+ branchStatus.output = output;
3332
+ branchStatus.error = void 0;
3333
+ entry.dirty = true;
3334
+ return;
3335
+ }
3336
+ hasWinner = true;
3337
+ winnerName = branch.name;
3338
+ winnerValue = output;
3339
+ branchCtx.validateComplete();
3340
+ branchStatus.status = "completed";
3341
+ branchStatus.output = output;
3342
+ branchStatus.error = void 0;
3343
+ raceData.winner = branch.name;
3344
+ entry.dirty = true;
3345
+ raceAbortController.abort();
3346
+ },
3347
+ (error) => {
3348
+ if (hasWinner) {
3349
+ if (error instanceof CancelledError || error instanceof EvictedError) {
3350
+ branchStatus.status = "cancelled";
3351
+ } else {
3352
+ lateErrors.push({
3353
+ name: branch.name,
3354
+ error: String(error)
3355
+ });
3356
+ }
3357
+ entry.dirty = true;
3358
+ return;
3359
+ }
3360
+ if (error instanceof SleepError || error instanceof MessageWaitError || error instanceof StepFailedError) {
3361
+ schedulerYieldState = mergeSchedulerYield(
3362
+ schedulerYieldState,
3363
+ error
3364
+ );
3365
+ branchStatus.status = "running";
3366
+ branchStatus.error = void 0;
3367
+ entry.dirty = true;
3368
+ return;
3369
+ }
3370
+ if (error instanceof EvictedError || error instanceof HistoryDivergedError || error instanceof EntryInProgressError || error instanceof RollbackCheckpointError || error instanceof RollbackStopError) {
3371
+ propagatedError = selectControlFlowError(
3372
+ propagatedError,
3373
+ error
3374
+ );
3375
+ branchStatus.status = "running";
3376
+ branchStatus.error = void 0;
3377
+ entry.dirty = true;
3378
+ return;
3379
+ }
3380
+ if (error instanceof CancelledError) {
3381
+ branchStatus.status = "cancelled";
3382
+ } else {
3383
+ branchStatus.status = "failed";
3384
+ branchStatus.output = void 0;
3385
+ branchStatus.error = String(error);
3386
+ errors[branch.name] = error;
3387
+ }
3388
+ entry.dirty = true;
3389
+ }
3390
+ );
3391
+ branchPromises.push(branchPromise);
3392
+ }
3393
+ await Promise.allSettled(branchPromises);
3394
+ if (propagatedError) {
3395
+ await this.flushStorage();
3396
+ throw propagatedError;
3397
+ }
3398
+ if (!hasWinner && Object.values(raceData.branches).some(
3399
+ (branch) => branch.status === "pending" || branch.status === "running"
3400
+ )) {
3401
+ await this.flushStorage();
3402
+ if (!schedulerYieldState) {
3403
+ throw new Error(
3404
+ `Race "${name}" has pending branches without a scheduler yield`
3405
+ );
3406
+ }
3407
+ throw buildSchedulerYieldError(schedulerYieldState);
3408
+ }
3409
+ if (hasWinner && winnerName !== null) {
3410
+ for (const branch of branches) {
3411
+ if (branch.name !== winnerName) {
3412
+ const branchLocation = appendName(
3413
+ this.storage,
3414
+ location,
3415
+ branch.name
3416
+ );
3417
+ await deleteEntriesWithPrefix(
3418
+ this.storage,
3419
+ this.driver,
3420
+ branchLocation,
3421
+ this.historyNotifier
3422
+ );
3423
+ }
3424
+ }
3425
+ }
3426
+ await this.flushStorage();
3427
+ if (lateErrors.length > 0) {
3428
+ console.warn(
3429
+ `Race "${name}" had ${lateErrors.length} branch(es) fail after winner was determined:`,
3430
+ lateErrors
3431
+ );
3432
+ }
3433
+ if (hasWinner && winnerName !== null) {
3434
+ return { winner: winnerName, value: winnerValue };
3435
+ }
3436
+ throw attachTryBlockFailure(
3437
+ new RaceError(
3438
+ "All branches failed",
3439
+ Object.entries(errors).map(([branchName, error]) => ({
3440
+ name: branchName,
3441
+ error: String(error)
3442
+ }))
3443
+ ),
3444
+ {
3445
+ source: "race",
3446
+ name
3447
+ }
3448
+ );
3449
+ }
3450
+ // === Removed ===
3451
+ async removed(name, originalType) {
3452
+ this.assertNotInProgress();
3453
+ this.checkEvicted();
3454
+ this.entryInProgress = true;
3455
+ try {
3456
+ await this.executeRemoved(name, originalType);
3457
+ } finally {
3458
+ this.entryInProgress = false;
3459
+ }
3460
+ }
3461
+ async executeRemoved(name, originalType) {
3462
+ this.checkDuplicateName(name);
3463
+ const location = appendName(this.storage, this.currentLocation, name);
3464
+ const key = locationToKey(this.storage, location);
3465
+ const existing = this.storage.history.entries.get(key);
3466
+ this.markVisited(key);
3467
+ this.stopRollbackIfMissing(existing);
3468
+ if (existing) {
3469
+ if (existing.kind.type !== "removed" && existing.kind.type !== originalType) {
3470
+ throw new HistoryDivergedError(
3471
+ `Expected ${originalType} or removed at ${key}, found ${existing.kind.type}`
3472
+ );
3473
+ }
3474
+ return;
3475
+ }
3476
+ const entry = createEntry(location, {
3477
+ type: "removed",
3478
+ data: { originalType, originalName: name }
3479
+ });
3480
+ setEntry(this.storage, location, entry);
3481
+ await this.flushStorage();
3482
+ }
3483
+ }, _class);
3484
+
3485
+ // src/index.ts
3486
+ var Loop = {
3487
+ continue: (state) => ({
3488
+ continue: true,
3489
+ state
3490
+ }),
3491
+ break: (value) => ({
3492
+ break: true,
3493
+ value
3494
+ })
3495
+ };
3496
+ function createLiveRuntime() {
3497
+ return {
3498
+ isSleeping: false
3499
+ };
3500
+ }
3501
+ function createEvictionWait(signal) {
3502
+ if (signal.aborted) {
3503
+ return {
3504
+ promise: Promise.reject(new EvictedError()),
3505
+ cleanup: () => {
3506
+ }
3507
+ };
3508
+ }
3509
+ let onAbort;
3510
+ const promise = new Promise((_, reject) => {
3511
+ onAbort = () => {
3512
+ reject(new EvictedError());
3513
+ };
3514
+ signal.addEventListener("abort", onAbort, { once: true });
3515
+ });
3516
+ return {
3517
+ promise,
3518
+ cleanup: () => {
3519
+ if (onAbort) {
3520
+ signal.removeEventListener("abort", onAbort);
3521
+ }
3522
+ }
3523
+ };
3524
+ }
3525
+ function createRollbackContext(workflowId, abortController) {
3526
+ return {
3527
+ workflowId,
3528
+ abortSignal: abortController.signal,
3529
+ isEvicted: () => abortController.signal.aborted
3530
+ };
3531
+ }
3532
+ async function awaitWithEviction(promise, abortSignal) {
3533
+ const { promise: evictionPromise, cleanup } = createEvictionWait(abortSignal);
3534
+ try {
3535
+ return await Promise.race([promise, evictionPromise]);
3536
+ } finally {
3537
+ cleanup();
3538
+ }
3539
+ }
3540
+ async function executeRollback(workflowId, workflowFn, input, driver, messageDriver, abortController, storage, historyNotifier, onError, logger) {
3541
+ const rollbackActions = [];
3542
+ const ctx = new WorkflowContextImpl(
3543
+ workflowId,
3544
+ storage,
3545
+ driver,
3546
+ messageDriver,
3547
+ void 0,
3548
+ abortController,
3549
+ "rollback",
3550
+ rollbackActions,
3551
+ false,
3552
+ historyNotifier,
3553
+ onError,
3554
+ logger
3555
+ );
3556
+ try {
3557
+ await workflowFn(ctx, input);
3558
+ } catch (error) {
3559
+ if (error instanceof EvictedError) {
3560
+ throw error;
3561
+ }
3562
+ if (error instanceof RollbackStopError) {
3563
+ } else {
3564
+ }
3565
+ }
3566
+ if (rollbackActions.length === 0) {
3567
+ return;
3568
+ }
3569
+ const rollbackContext = createRollbackContext(workflowId, abortController);
3570
+ for (let i = rollbackActions.length - 1; i >= 0; i--) {
3571
+ if (abortController.signal.aborted) {
3572
+ throw new EvictedError();
3573
+ }
3574
+ const action = rollbackActions[i];
3575
+ const metadata = await loadMetadata(storage, driver, action.entryId);
3576
+ if (metadata.rollbackCompletedAt !== void 0) {
3577
+ continue;
3578
+ }
3579
+ let rollbackEvent;
3580
+ try {
3581
+ await awaitWithEviction(
3582
+ action.rollback(rollbackContext, action.output),
3583
+ abortController.signal
3584
+ );
3585
+ metadata.rollbackCompletedAt = Date.now();
3586
+ metadata.rollbackError = void 0;
3587
+ } catch (error) {
3588
+ if (error instanceof EvictedError) {
3589
+ throw error;
3590
+ }
3591
+ metadata.rollbackError = error instanceof Error ? error.message : String(error);
3592
+ if (onError) {
3593
+ rollbackEvent = {
3594
+ rollback: {
3595
+ workflowId,
3596
+ stepName: action.name,
3597
+ error: extractErrorInfo(error)
3598
+ }
3599
+ };
3600
+ }
3601
+ if (error instanceof Error) {
3602
+ markErrorReported(error);
3603
+ }
3604
+ throw error;
3605
+ } finally {
3606
+ metadata.dirty = true;
3607
+ await flush(storage, driver, historyNotifier);
3608
+ if (rollbackEvent && onError) {
3609
+ await notifyError(onError, logger, rollbackEvent);
3610
+ }
3611
+ }
3612
+ }
3613
+ }
3614
+ async function notifyError(onError, logger, event) {
3615
+ try {
3616
+ await onError(event);
3617
+ } catch (error) {
3618
+ logger == null ? void 0 : logger.warn({
3619
+ msg: "workflow error hook failed",
3620
+ hookEventType: getErrorEventTag(event),
3621
+ error: extractErrorInfo(error)
3622
+ });
3623
+ }
3624
+ }
3625
+ async function setSleepState(storage, driver, workflowId, deadline, messageNames, historyNotifier) {
3626
+ storage.state = "sleeping";
3627
+ await flush(storage, driver, historyNotifier);
3628
+ await driver.setAlarm(workflowId, deadline);
3629
+ return {
3630
+ state: "sleeping",
3631
+ sleepUntil: deadline,
3632
+ waitingForMessages: messageNames
3633
+ };
3634
+ }
3635
+ async function setMessageWaitState(storage, driver, messageNames, historyNotifier) {
3636
+ storage.state = "sleeping";
3637
+ await flush(storage, driver, historyNotifier);
3638
+ return { state: "sleeping", waitingForMessages: messageNames };
3639
+ }
3640
+ async function setEvictedState(storage, driver, historyNotifier) {
3641
+ await flush(storage, driver, historyNotifier);
3642
+ return { state: storage.state };
3643
+ }
3644
+ async function setRetryState(storage, driver, workflowId, retryAt, historyNotifier) {
3645
+ storage.state = "sleeping";
3646
+ await flush(storage, driver, historyNotifier);
3647
+ await driver.setAlarm(workflowId, retryAt);
3648
+ return { state: "sleeping", sleepUntil: retryAt };
3649
+ }
3650
+ async function setFailedState(storage, driver, error, historyNotifier) {
3651
+ storage.state = "failed";
3652
+ storage.error = extractErrorInfo(error);
3653
+ await flush(storage, driver, historyNotifier);
3654
+ }
3655
+ async function waitForSleep(runtime, deadline, abortSignal) {
3656
+ while (true) {
3657
+ const remaining = deadline - Date.now();
3658
+ if (remaining <= 0) {
3659
+ return;
3660
+ }
3661
+ let timeoutHandle;
3662
+ const timeoutPromise = new Promise((resolve) => {
3663
+ timeoutHandle = setLongTimeout(resolve, remaining);
3664
+ });
3665
+ const wakePromise = new Promise((resolve) => {
3666
+ runtime.sleepWaiter = resolve;
3667
+ });
3668
+ runtime.isSleeping = true;
3669
+ try {
3670
+ await awaitWithEviction(
3671
+ Promise.race([timeoutPromise, wakePromise]),
3672
+ abortSignal
3673
+ );
3674
+ } finally {
3675
+ runtime.isSleeping = false;
3676
+ runtime.sleepWaiter = void 0;
3677
+ timeoutHandle == null ? void 0 : timeoutHandle.abort();
3678
+ }
3679
+ if (abortSignal.aborted) {
3680
+ throw new EvictedError();
3681
+ }
3682
+ if (Date.now() >= deadline) {
3683
+ return;
3684
+ }
3685
+ }
3686
+ }
3687
+ async function executeLiveWorkflow(workflowId, workflowFn, input, driver, messageDriver, abortController, runtime, onHistoryUpdated, onError, logger) {
3688
+ let lastResult;
3689
+ while (true) {
3690
+ const result = await executeWorkflow(
3691
+ workflowId,
3692
+ workflowFn,
3693
+ input,
3694
+ driver,
3695
+ messageDriver,
3696
+ abortController,
3697
+ onHistoryUpdated,
3698
+ onError,
3699
+ logger
3700
+ );
3701
+ lastResult = result;
3702
+ if (result.state !== "sleeping") {
3703
+ return result;
3704
+ }
3705
+ const hasMessages = result.waitingForMessages !== void 0;
3706
+ const hasDeadline = result.sleepUntil !== void 0;
3707
+ if (hasMessages && hasDeadline) {
3708
+ try {
3709
+ const messagePromise = awaitWithEviction(
3710
+ driver.waitForMessages(
3711
+ result.waitingForMessages,
3712
+ abortController.signal
3713
+ ),
3714
+ abortController.signal
3715
+ );
3716
+ const sleepPromise = waitForSleep(
3717
+ runtime,
3718
+ result.sleepUntil,
3719
+ abortController.signal
3720
+ );
3721
+ await Promise.race([messagePromise, sleepPromise]);
3722
+ } catch (error) {
3723
+ if (error instanceof EvictedError) {
3724
+ return lastResult;
3725
+ }
3726
+ throw error;
3727
+ }
3728
+ continue;
3729
+ }
3730
+ if (hasMessages) {
3731
+ try {
3732
+ await awaitWithEviction(
3733
+ driver.waitForMessages(
3734
+ result.waitingForMessages,
3735
+ abortController.signal
3736
+ ),
3737
+ abortController.signal
3738
+ );
3739
+ } catch (error) {
3740
+ if (error instanceof EvictedError) {
3741
+ return lastResult;
3742
+ }
3743
+ throw error;
3744
+ }
3745
+ continue;
3746
+ }
3747
+ if (hasDeadline) {
3748
+ try {
3749
+ await waitForSleep(
3750
+ runtime,
3751
+ result.sleepUntil,
3752
+ abortController.signal
3753
+ );
3754
+ } catch (error) {
3755
+ if (error instanceof EvictedError) {
3756
+ return lastResult;
3757
+ }
3758
+ throw error;
3759
+ }
3760
+ continue;
3761
+ }
3762
+ return result;
3763
+ }
3764
+ }
3765
+ function runWorkflow(workflowId, workflowFn, input, driver, options = {}) {
3766
+ const messageDriver = driver.messageDriver;
3767
+ const abortController = new AbortController();
3768
+ const mode = _nullishCoalesce(options.mode, () => ( "yield"));
3769
+ const liveRuntime = mode === "live" ? createLiveRuntime() : void 0;
3770
+ const logger = options.logger;
3771
+ const resultPromise = mode === "live" && liveRuntime ? executeLiveWorkflow(
3772
+ workflowId,
3773
+ workflowFn,
3774
+ input,
3775
+ driver,
3776
+ messageDriver,
3777
+ abortController,
3778
+ liveRuntime,
3779
+ options.onHistoryUpdated,
3780
+ options.onError,
3781
+ logger
3782
+ ) : executeWorkflow(
3783
+ workflowId,
3784
+ workflowFn,
3785
+ input,
3786
+ driver,
3787
+ messageDriver,
3788
+ abortController,
3789
+ options.onHistoryUpdated,
3790
+ options.onError,
3791
+ logger
3792
+ );
3793
+ return {
3794
+ workflowId,
3795
+ result: resultPromise,
3796
+ async message(name, data) {
3797
+ const messageId = generateId();
3798
+ await messageDriver.addMessage({
3799
+ id: messageId,
3800
+ name,
3801
+ data,
3802
+ sentAt: Date.now()
3803
+ });
3804
+ },
3805
+ async wake() {
3806
+ if (liveRuntime) {
3807
+ if (liveRuntime.isSleeping && liveRuntime.sleepWaiter) {
3808
+ liveRuntime.sleepWaiter();
3809
+ }
3810
+ return;
3811
+ }
3812
+ await driver.setAlarm(workflowId, Date.now());
3813
+ },
3814
+ async recover() {
3815
+ const stateValue = await driver.get(buildWorkflowStateKey());
3816
+ const state = stateValue ? deserializeWorkflowState(stateValue) : "pending";
3817
+ if (state !== "failed") {
3818
+ return;
3819
+ }
3820
+ const metadataEntries = await driver.list(
3821
+ buildEntryMetadataPrefix()
3822
+ );
3823
+ const writes = [];
3824
+ for (const entry of metadataEntries) {
3825
+ const metadata = deserializeEntryMetadata(entry.value);
3826
+ if (metadata.status !== "failed" && metadata.status !== "exhausted") {
3827
+ continue;
3828
+ }
3829
+ metadata.status = "pending";
3830
+ metadata.attempts = 0;
3831
+ metadata.lastAttemptAt = 0;
3832
+ metadata.error = void 0;
3833
+ metadata.dirty = false;
3834
+ writes.push({
3835
+ key: entry.key,
3836
+ value: serializeEntryMetadata(metadata)
3837
+ });
3838
+ }
3839
+ if (writes.length > 0) {
3840
+ await driver.batch(writes);
3841
+ }
3842
+ await driver.delete(buildWorkflowErrorKey());
3843
+ await driver.set(
3844
+ buildWorkflowStateKey(),
3845
+ serializeWorkflowState("sleeping")
3846
+ );
3847
+ if (liveRuntime) {
3848
+ if (liveRuntime.isSleeping && liveRuntime.sleepWaiter) {
3849
+ liveRuntime.sleepWaiter();
3850
+ }
3851
+ return;
3852
+ }
3853
+ await driver.setAlarm(workflowId, Date.now());
3854
+ },
3855
+ evict() {
3856
+ abortController.abort(new EvictedError());
3857
+ },
3858
+ async cancel() {
3859
+ abortController.abort(new EvictedError());
3860
+ await driver.set(
3861
+ buildWorkflowStateKey(),
3862
+ serializeWorkflowState("cancelled")
3863
+ );
3864
+ await driver.clearAlarm(workflowId);
3865
+ },
3866
+ async getOutput() {
3867
+ const value = await driver.get(buildWorkflowOutputKey());
3868
+ if (!value) {
3869
+ return void 0;
3870
+ }
3871
+ return deserializeWorkflowOutput(value);
3872
+ },
3873
+ async getState() {
3874
+ const value = await driver.get(buildWorkflowStateKey());
3875
+ if (!value) {
3876
+ return "pending";
3877
+ }
3878
+ return deserializeWorkflowState(value);
3879
+ }
3880
+ };
3881
+ }
3882
+ async function replayWorkflowFromStep(workflowId, driver, entryId, options) {
3883
+ const storage = await loadStorage(driver);
3884
+ const entries = await Promise.all(
3885
+ Array.from(storage.history.entries.entries()).map(
3886
+ async ([key, entry]) => ({
3887
+ key,
3888
+ entry,
3889
+ metadata: await loadMetadata(storage, driver, entry.id)
3890
+ })
3891
+ )
3892
+ );
3893
+ const ordered = [...entries].sort((a, b) => {
3894
+ if (a.metadata.createdAt !== b.metadata.createdAt) {
3895
+ return a.metadata.createdAt - b.metadata.createdAt;
3896
+ }
3897
+ return a.key.localeCompare(b.key);
3898
+ });
3899
+ let entriesToDelete = ordered;
3900
+ if (entryId !== void 0) {
3901
+ const target = entries.find(({ entry }) => entry.id === entryId);
3902
+ if (!target) {
3903
+ throw new Error(`Workflow step not found: ${entryId}`);
3904
+ }
3905
+ if (target.entry.kind.type !== "step") {
3906
+ throw new Error("Workflow replay target must be a step");
3907
+ }
3908
+ const replayBoundary = findReplayBoundaryEntry(entries, target);
3909
+ const targetIndex = ordered.findIndex(
3910
+ ({ entry }) => entry.id === replayBoundary.entry.id
3911
+ );
3912
+ entriesToDelete = ordered.slice(targetIndex);
3913
+ }
3914
+ const entryIdsToDelete = new Set(
3915
+ entriesToDelete.map(({ entry }) => entry.id)
3916
+ );
3917
+ if (entries.some(
3918
+ ({ entry, metadata }) => metadata.status === "running" && !entryIdsToDelete.has(entry.id)
3919
+ )) {
3920
+ throw new Error(
3921
+ "Cannot replay a workflow while a step is currently running"
3922
+ );
3923
+ }
3924
+ await Promise.all(
3925
+ entriesToDelete.flatMap(({ entry }) => [
3926
+ driver.delete(buildHistoryKey(entry.location)),
3927
+ driver.delete(buildEntryMetadataKey(entry.id))
3928
+ ])
3929
+ );
3930
+ for (const { key, entry } of entriesToDelete) {
3931
+ storage.history.entries.delete(key);
3932
+ storage.entryMetadata.delete(entry.id);
3933
+ }
3934
+ storage.output = void 0;
3935
+ storage.flushedOutput = void 0;
3936
+ storage.error = void 0;
3937
+ storage.flushedError = void 0;
3938
+ storage.state = "sleeping";
3939
+ storage.flushedState = "sleeping";
3940
+ await Promise.all([
3941
+ driver.delete(buildWorkflowOutputKey()),
3942
+ driver.delete(buildWorkflowErrorKey()),
3943
+ driver.set(buildWorkflowStateKey(), serializeWorkflowState("sleeping"))
3944
+ ]);
3945
+ if (_nullishCoalesce((options == null ? void 0 : options.scheduleAlarm), () => ( true))) {
3946
+ await driver.setAlarm(workflowId, Date.now());
3947
+ }
3948
+ return createHistorySnapshot(storage);
3949
+ }
3950
+ function findReplayBoundaryEntry(entries, target) {
3951
+ let boundary = target;
3952
+ let boundaryDepth = -1;
3953
+ for (const candidate of entries) {
3954
+ if (candidate.entry.kind.type !== "loop") {
3955
+ continue;
3956
+ }
3957
+ if (candidate.entry.location.length >= target.entry.location.length || !isLocationPrefix(candidate.entry.location, target.entry.location)) {
3958
+ continue;
3959
+ }
3960
+ if (candidate.entry.location.length > boundaryDepth) {
3961
+ boundary = candidate;
3962
+ boundaryDepth = candidate.entry.location.length;
3963
+ }
3964
+ }
3965
+ return boundary;
3966
+ }
3967
+ async function executeWorkflow(workflowId, workflowFn, input, driver, messageDriver, abortController, onHistoryUpdated, onError, logger) {
3968
+ var _a;
3969
+ const storage = await loadStorage(driver);
3970
+ const historyNotifier = onHistoryUpdated ? () => onHistoryUpdated(createHistorySnapshot(storage)) : void 0;
3971
+ if (historyNotifier) {
3972
+ historyNotifier();
3973
+ }
3974
+ if (logger) {
3975
+ const entryKeys = Array.from(storage.history.entries.keys());
3976
+ logger.debug({
3977
+ msg: "loaded workflow storage",
3978
+ state: storage.state,
3979
+ entryCount: entryKeys.length,
3980
+ entries: entryKeys.slice(0, 10),
3981
+ nameRegistry: storage.nameRegistry
3982
+ });
3983
+ }
3984
+ if (storage.state === "cancelled") {
3985
+ throw new EvictedError();
3986
+ }
3987
+ const storedInputBytes = await driver.get(buildWorkflowInputKey());
3988
+ let effectiveInput;
3989
+ if (storedInputBytes) {
3990
+ effectiveInput = deserializeWorkflowInput(storedInputBytes);
3991
+ } else {
3992
+ effectiveInput = input;
3993
+ await driver.set(
3994
+ buildWorkflowInputKey(),
3995
+ serializeWorkflowInput(input)
3996
+ );
3997
+ }
3998
+ if (storage.state === "rolling_back") {
3999
+ try {
4000
+ await executeRollback(
4001
+ workflowId,
4002
+ workflowFn,
4003
+ effectiveInput,
4004
+ driver,
4005
+ messageDriver,
4006
+ abortController,
4007
+ storage,
4008
+ historyNotifier,
4009
+ onError,
4010
+ logger
4011
+ );
4012
+ } catch (error) {
4013
+ if (error instanceof EvictedError) {
4014
+ return { state: storage.state };
4015
+ }
4016
+ throw error;
4017
+ }
4018
+ storage.state = "failed";
4019
+ await flush(storage, driver, historyNotifier);
4020
+ const storedError = storage.error ? new Error(storage.error.message) : new Error("Workflow failed");
4021
+ if ((_a = storage.error) == null ? void 0 : _a.name) {
4022
+ storedError.name = storage.error.name;
4023
+ }
4024
+ throw storedError;
4025
+ }
4026
+ const ctx = new WorkflowContextImpl(
4027
+ workflowId,
4028
+ storage,
4029
+ driver,
4030
+ messageDriver,
4031
+ void 0,
4032
+ abortController,
4033
+ "forward",
4034
+ void 0,
4035
+ false,
4036
+ historyNotifier,
4037
+ onError,
4038
+ logger
4039
+ );
4040
+ storage.state = "running";
4041
+ try {
4042
+ const output = await workflowFn(ctx, effectiveInput);
4043
+ storage.state = "completed";
4044
+ storage.output = output;
4045
+ await flush(storage, driver, historyNotifier);
4046
+ await driver.clearAlarm(workflowId);
4047
+ return { state: "completed", output };
4048
+ } catch (error) {
4049
+ if (error instanceof SleepError) {
4050
+ return await setSleepState(
4051
+ storage,
4052
+ driver,
4053
+ workflowId,
4054
+ error.deadline,
4055
+ error.messageNames,
4056
+ historyNotifier
4057
+ );
4058
+ }
4059
+ if (error instanceof MessageWaitError) {
4060
+ return await setMessageWaitState(
4061
+ storage,
4062
+ driver,
4063
+ error.messageNames,
4064
+ historyNotifier
4065
+ );
4066
+ }
4067
+ if (error instanceof EvictedError) {
4068
+ return await setEvictedState(storage, driver, historyNotifier);
4069
+ }
4070
+ if (error instanceof StepFailedError) {
4071
+ return await setRetryState(
4072
+ storage,
4073
+ driver,
4074
+ workflowId,
4075
+ error.retryAt,
4076
+ historyNotifier
4077
+ );
4078
+ }
4079
+ if (error instanceof RollbackCheckpointError) {
4080
+ await setFailedState(storage, driver, error, historyNotifier);
4081
+ if (onError && !isErrorReported(error)) {
4082
+ await notifyError(onError, logger, {
4083
+ workflow: {
4084
+ workflowId,
4085
+ error: extractErrorInfo(error)
4086
+ }
4087
+ });
4088
+ }
4089
+ throw error;
4090
+ }
4091
+ storage.error = extractErrorInfo(error);
4092
+ storage.state = "rolling_back";
4093
+ await flush(storage, driver, historyNotifier);
4094
+ try {
4095
+ await executeRollback(
4096
+ workflowId,
4097
+ workflowFn,
4098
+ effectiveInput,
4099
+ driver,
4100
+ messageDriver,
4101
+ abortController,
4102
+ storage,
4103
+ historyNotifier,
4104
+ onError,
4105
+ logger
4106
+ );
4107
+ } catch (rollbackError) {
4108
+ if (rollbackError instanceof EvictedError) {
4109
+ return { state: storage.state };
4110
+ }
4111
+ throw rollbackError;
4112
+ }
4113
+ storage.state = "failed";
4114
+ await flush(storage, driver, historyNotifier);
4115
+ if (onError && !isErrorReported(error)) {
4116
+ await notifyError(onError, logger, {
4117
+ workflow: {
4118
+ workflowId,
4119
+ error: extractErrorInfo(error)
4120
+ }
4121
+ });
4122
+ if (error instanceof CriticalError || error instanceof RollbackError || error instanceof StepExhaustedError) {
4123
+ markErrorReported(error);
4124
+ }
4125
+ }
4126
+ throw error;
4127
+ }
4128
+ }
4129
+
4130
+
4131
+
4132
+
4133
+
4134
+
4135
+
4136
+
4137
+
4138
+
4139
+
4140
+
4141
+
4142
+
4143
+
4144
+
4145
+
4146
+
4147
+
4148
+
4149
+
4150
+
4151
+
4152
+
4153
+
4154
+
4155
+
4156
+
4157
+
4158
+
4159
+
4160
+
4161
+
4162
+
4163
+
4164
+
4165
+
4166
+
4167
+
4168
+
4169
+
4170
+
4171
+
4172
+
4173
+
4174
+
4175
+
4176
+
4177
+
4178
+
4179
+ exports.extractErrorInfo = extractErrorInfo; exports.CriticalError = CriticalError; exports.RollbackError = RollbackError; exports.RollbackCheckpointError = RollbackCheckpointError; exports.SleepError = SleepError; exports.MessageWaitError = MessageWaitError; exports.EvictedError = EvictedError; exports.HistoryDivergedError = HistoryDivergedError; exports.StepExhaustedError = StepExhaustedError; exports.StepFailedError = StepFailedError; exports.JoinError = JoinError; exports.RaceError = RaceError; exports.CancelledError = CancelledError; exports.EntryInProgressError = EntryInProgressError; exports.keyStartsWith = keyStartsWith; exports.compareKeys = compareKeys; exports.keyToHex = keyToHex; exports.isLoopIterationMarker = isLoopIterationMarker; exports.registerName = registerName; exports.resolveName = resolveName; exports.locationToKey = locationToKey; exports.appendName = appendName; exports.appendLoopIteration = appendLoopIteration; exports.emptyLocation = emptyLocation; exports.parentLocation = parentLocation; exports.isLocationPrefix = isLocationPrefix; exports.locationsEqual = locationsEqual; exports.createStorage = createStorage; exports.createHistorySnapshot = createHistorySnapshot; exports.generateId = generateId; exports.createEntry = createEntry; exports.getOrCreateMetadata = getOrCreateMetadata; exports.loadStorage = loadStorage; exports.loadMetadata = loadMetadata; exports.flush = flush; exports.deleteEntriesWithPrefix = deleteEntriesWithPrefix; exports.getEntry = getEntry; exports.setEntry = setEntry; exports.sleep = sleep; exports.DEFAULT_MAX_RETRIES = DEFAULT_MAX_RETRIES; exports.DEFAULT_RETRY_BACKOFF_BASE = DEFAULT_RETRY_BACKOFF_BASE; exports.DEFAULT_RETRY_BACKOFF_MAX = DEFAULT_RETRY_BACKOFF_MAX; exports.DEFAULT_LOOP_HISTORY_PRUNE_INTERVAL = DEFAULT_LOOP_HISTORY_PRUNE_INTERVAL; exports.DEFAULT_STEP_TIMEOUT = DEFAULT_STEP_TIMEOUT; exports.WorkflowContextImpl = WorkflowContextImpl; exports.Loop = Loop; exports.runWorkflow = runWorkflow; exports.replayWorkflowFromStep = replayWorkflowFromStep;
4180
+ //# sourceMappingURL=chunk-4SWXLWKL.cjs.map