@rivetkit/workflow-engine 0.0.0-0-0-0-preview-guard-stops.9d82529

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