@rivetkit/workflow-engine 2.1.0-rc.2 → 2.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/tsup/{chunk-GJ66YE5W.cjs → chunk-6TTCEQL3.cjs} +24 -4
- package/dist/tsup/chunk-6TTCEQL3.cjs.map +1 -0
- package/dist/tsup/{chunk-JWHWQBZP.js → chunk-WA4TXB6Y.js} +24 -4
- package/dist/tsup/chunk-WA4TXB6Y.js.map +1 -0
- package/dist/tsup/index.cjs +2 -2
- package/dist/tsup/index.d.cts +22 -8
- package/dist/tsup/index.d.ts +22 -8
- package/dist/tsup/index.js +1 -1
- package/dist/tsup/testing.cjs +21 -21
- package/dist/tsup/testing.d.cts +1 -1
- package/dist/tsup/testing.d.ts +1 -1
- package/dist/tsup/testing.js +1 -1
- package/package.json +1 -1
- package/src/context.ts +34 -5
- package/src/index.ts +1 -0
- package/src/types.ts +29 -4
- package/dist/tsup/chunk-GJ66YE5W.cjs.map +0 -1
- package/dist/tsup/chunk-JWHWQBZP.js.map +0 -1
|
@@ -1602,6 +1602,7 @@ var WorkflowContextImpl = (_class = class _WorkflowContextImpl {
|
|
|
1602
1602
|
get queue() {
|
|
1603
1603
|
return {
|
|
1604
1604
|
next: async (name, opts) => await this.queueNext(name, opts),
|
|
1605
|
+
nextBatch: async (name, opts) => await this.queueNextBatch(name, opts),
|
|
1605
1606
|
send: async (name, body) => await this.queueSend(name, body)
|
|
1606
1607
|
};
|
|
1607
1608
|
}
|
|
@@ -2015,7 +2016,13 @@ var WorkflowContextImpl = (_class = class _WorkflowContextImpl {
|
|
|
2015
2016
|
iteration
|
|
2016
2017
|
);
|
|
2017
2018
|
const branchCtx = this.createBranch(iterationLocation);
|
|
2018
|
-
const
|
|
2019
|
+
const iterationResult = await config2.run(branchCtx, state);
|
|
2020
|
+
if (iterationResult === void 0 && state !== void 0) {
|
|
2021
|
+
throw new Error(
|
|
2022
|
+
`Loop "${config2.name}" returned undefined for a stateful iteration. Return Loop.continue(state) or Loop.break(value).`
|
|
2023
|
+
);
|
|
2024
|
+
}
|
|
2025
|
+
const result = iterationResult === void 0 ? { continue: true, state } : iterationResult;
|
|
2019
2026
|
branchCtx.validateComplete();
|
|
2020
2027
|
if ("break" in result && result.break) {
|
|
2021
2028
|
if (entry.kind.type === "loop") {
|
|
@@ -2218,16 +2225,29 @@ var WorkflowContextImpl = (_class = class _WorkflowContextImpl {
|
|
|
2218
2225
|
await this.messageDriver.addMessage(message);
|
|
2219
2226
|
}
|
|
2220
2227
|
async queueNext(name, opts) {
|
|
2228
|
+
const messages = await this.queueNextBatch(name, {
|
|
2229
|
+
..._nullishCoalesce(opts, () => ( {})),
|
|
2230
|
+
count: 1
|
|
2231
|
+
});
|
|
2232
|
+
const message = messages[0];
|
|
2233
|
+
if (!message) {
|
|
2234
|
+
throw new Error(
|
|
2235
|
+
`queue.next("${name}") timed out before receiving a message. Use queue.nextBatch(...) for optional/time-limited reads.`
|
|
2236
|
+
);
|
|
2237
|
+
}
|
|
2238
|
+
return message;
|
|
2239
|
+
}
|
|
2240
|
+
async queueNextBatch(name, opts) {
|
|
2221
2241
|
this.assertNotInProgress();
|
|
2222
2242
|
this.checkEvicted();
|
|
2223
2243
|
this.entryInProgress = true;
|
|
2224
2244
|
try {
|
|
2225
|
-
return await this.
|
|
2245
|
+
return await this.executeQueueNextBatch(name, opts);
|
|
2226
2246
|
} finally {
|
|
2227
2247
|
this.entryInProgress = false;
|
|
2228
2248
|
}
|
|
2229
2249
|
}
|
|
2230
|
-
async
|
|
2250
|
+
async executeQueueNextBatch(name, opts) {
|
|
2231
2251
|
if (this.pendingCompletableMessageIds.size > 0) {
|
|
2232
2252
|
throw new Error(
|
|
2233
2253
|
"Previous completable queue message is not completed. Call `message.complete(...)` before receiving the next message."
|
|
@@ -3438,4 +3458,4 @@ function extractErrorInfo(error) {
|
|
|
3438
3458
|
|
|
3439
3459
|
|
|
3440
3460
|
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.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.keyStartsWith = keyStartsWith; exports.compareKeys = compareKeys; exports.keyToHex = keyToHex; exports.createStorage = createStorage; exports.createHistorySnapshot = createHistorySnapshot; exports.generateId = generateId; exports.createEntry = createEntry; exports.getOrCreateMetadata = getOrCreateMetadata; exports.loadStorage = loadStorage; exports.loadMetadata = loadMetadata; exports.flush = flush; exports.deleteEntriesWithPrefix = deleteEntriesWithPrefix; exports.getEntry = getEntry; exports.setEntry = setEntry; exports.sleep = sleep; exports.DEFAULT_MAX_RETRIES = DEFAULT_MAX_RETRIES; exports.DEFAULT_RETRY_BACKOFF_BASE = DEFAULT_RETRY_BACKOFF_BASE; exports.DEFAULT_RETRY_BACKOFF_MAX = DEFAULT_RETRY_BACKOFF_MAX; exports.DEFAULT_LOOP_COMMIT_INTERVAL = DEFAULT_LOOP_COMMIT_INTERVAL; exports.DEFAULT_LOOP_HISTORY_EVERY = DEFAULT_LOOP_HISTORY_EVERY; exports.DEFAULT_LOOP_HISTORY_KEEP = DEFAULT_LOOP_HISTORY_KEEP; exports.DEFAULT_STEP_TIMEOUT = DEFAULT_STEP_TIMEOUT; exports.WorkflowContextImpl = WorkflowContextImpl; exports.Loop = Loop; exports.runWorkflow = runWorkflow;
|
|
3441
|
-
//# sourceMappingURL=chunk-
|
|
3461
|
+
//# sourceMappingURL=chunk-6TTCEQL3.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["/home/runner/work/rivet/rivet/rivetkit-typescript/packages/workflow-engine/dist/tsup/chunk-6TTCEQL3.cjs","../../src/errors.ts","../../src/location.ts","../../schemas/serde.ts","../schemas/v1.ts","../../schemas/versioned.ts","../../src/keys.ts","../../src/storage.ts","../../src/utils.ts","../../src/context.ts","../../src/index.ts"],"names":["name"],"mappings":"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oB,MAAA;AACZ,QAAA;AAC/B,MAAA;AACM,MAAA;AACP,IAAA;AAEgB,IAAA;AAC4B,IAAA;AAEtC,IAAA;AACP,EAAA;AACD;AAUE;AAC2B,EAAA;AAMvB,IAAA;AACS,MAAA;AACG,MAAA;AACF,MAAA;AACd,IAAA;AAG2C,IAAA;AACL,IAAA;AACuB,MAAA;AAG3D,QAAA;AAMW,QAAA;AAEM,UAAA;AACjB,QAAA;AACD,MAAA;AACD,IAAA;AACsC,IAAA;AACnB,MAAA;AACnB,IAAA;AAEO,IAAA;AACR,EAAA;AAEO,EAAA;AACA,IAAA;AACe,IAAA;AACtB,EAAA;AACD;AVs8EmH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA","file":"/home/runner/work/rivet/rivet/rivetkit-typescript/packages/workflow-engine/dist/tsup/chunk-6TTCEQL3.cjs","sourcesContent":[null,"/**\n * Thrown from steps to prevent retry.\n * Use this when an error is unrecoverable and retrying would be pointless.\n */\nexport class CriticalError extends Error {\n\tconstructor(message: string) {\n\t\tsuper(message);\n\t\tthis.name = \"CriticalError\";\n\t}\n}\n\n/**\n * Thrown from steps to force rollback without retry.\n */\nexport class RollbackError extends Error {\n\tconstructor(message: string) {\n\t\tsuper(message);\n\t\tthis.name = \"RollbackError\";\n\t}\n}\n\n/**\n * Thrown when rollback is used without a checkpoint.\n */\nexport class RollbackCheckpointError extends Error {\n\tconstructor() {\n\t\tsuper(\"Rollback requires a checkpoint before any rollback step\");\n\t\tthis.name = \"RollbackCheckpointError\";\n\t}\n}\n\n/**\n * Internal: Workflow should sleep until deadline.\n * This is thrown to yield control back to the scheduler.\n * Optionally, the workflow can also wake early if certain messages arrive.\n */\nexport class SleepError extends Error {\n\tconstructor(\n\t\tpublic readonly deadline: number,\n\t\tpublic readonly messageNames?: string[],\n\t) {\n\t\tsuper(\n\t\t\tmessageNames && messageNames.length > 0\n\t\t\t\t? `Sleeping until ${deadline} or messages: ${messageNames.join(\", \")}`\n\t\t\t\t: `Sleeping until ${deadline}`,\n\t\t);\n\t\tthis.name = \"SleepError\";\n\t}\n}\n\n/**\n * Internal: Workflow is waiting for messages.\n * This is thrown to yield control back to the scheduler.\n */\nexport class MessageWaitError extends Error {\n\tconstructor(public readonly messageNames: string[]) {\n\t\tsuper(`Waiting for messages: ${messageNames.join(\", \")}`);\n\t\tthis.name = \"MessageWaitError\";\n\t}\n}\n\n/**\n * Internal: Workflow was evicted.\n * This is thrown when the workflow is being gracefully stopped.\n */\nexport class EvictedError extends Error {\n\tconstructor() {\n\t\tsuper(\"Workflow evicted\");\n\t\tthis.name = \"EvictedError\";\n\t}\n}\n\n/**\n * Internal: Stop rollback traversal.\n */\nexport class RollbackStopError extends Error {\n\tconstructor() {\n\t\tsuper(\"Rollback traversal halted\");\n\t\tthis.name = \"RollbackStopError\";\n\t}\n}\n\n/**\n * Workflow code changed incompatibly.\n * Thrown when history doesn't match the current workflow code.\n */\nexport class HistoryDivergedError extends Error {\n\tconstructor(message: string) {\n\t\tsuper(message);\n\t\tthis.name = \"HistoryDivergedError\";\n\t}\n}\n\n/**\n * Step exhausted all retries.\n */\nexport class StepExhaustedError extends Error {\n\tconstructor(\n\t\tpublic readonly stepName: string,\n\t\tpublic readonly lastError?: string,\n\t) {\n\t\tsuper(\n\t\t\t`Step \"${stepName}\" exhausted retries: ${lastError ?? \"unknown error\"}`,\n\t\t);\n\t\tthis.name = \"StepExhaustedError\";\n\t}\n}\n\n/**\n * Step failed (will be retried).\n * Internal error used to trigger retry logic.\n */\nexport class StepFailedError extends Error {\n\tconstructor(\n\t\tpublic readonly stepName: string,\n\t\tpublic readonly originalError: unknown,\n\t\tpublic readonly attempts: number,\n\t) {\n\t\tsuper(`Step \"${stepName}\" failed (attempt ${attempts})`);\n\t\tthis.name = \"StepFailedError\";\n\t\tthis.cause = originalError;\n\t}\n}\n\n/**\n * Join had branch failures.\n */\nexport class JoinError extends Error {\n\tconstructor(public readonly errors: Record<string, Error>) {\n\t\tsuper(`Join failed: ${Object.keys(errors).join(\", \")}`);\n\t\tthis.name = \"JoinError\";\n\t}\n}\n\n/**\n * Race had all branches fail.\n */\nexport class RaceError extends Error {\n\tconstructor(\n\t\tmessage: string,\n\t\tpublic readonly errors: Array<{ name: string; error: string }>,\n\t) {\n\t\tsuper(message);\n\t\tthis.name = \"RaceError\";\n\t}\n}\n\n/**\n * Branch was cancelled (used by race).\n */\nexport class CancelledError extends Error {\n\tconstructor() {\n\t\tsuper(\"Branch cancelled\");\n\t\tthis.name = \"CancelledError\";\n\t}\n}\n\n/**\n * Entry is currently being processed.\n * Thrown when user forgets to await a step.\n */\nexport class EntryInProgressError extends Error {\n\tconstructor() {\n\t\tsuper(\n\t\t\t\"Cannot start a new workflow entry while another is in progress. \" +\n\t\t\t\t\"Did you forget to await the previous step/loop/sleep?\",\n\t\t);\n\t\tthis.name = \"EntryInProgressError\";\n\t}\n}\n","import type {\n\tLocation,\n\tLoopIterationMarker,\n\tNameIndex,\n\tPathSegment,\n\tStorage,\n} from \"./types.js\";\n\n/**\n * Check if a path segment is a loop iteration marker.\n */\nexport function isLoopIterationMarker(\n\tsegment: PathSegment,\n): segment is LoopIterationMarker {\n\treturn typeof segment === \"object\" && \"loop\" in segment;\n}\n\n/**\n * Register a name in the registry and return its index.\n * If the name already exists, returns the existing index.\n */\nexport function registerName(storage: Storage, name: string): NameIndex {\n\tconst existing = storage.nameRegistry.indexOf(name);\n\tif (existing !== -1) {\n\t\treturn existing;\n\t}\n\tstorage.nameRegistry.push(name);\n\treturn storage.nameRegistry.length - 1;\n}\n\n/**\n * Resolve a name index to its string value.\n */\nexport function resolveName(storage: Storage, index: NameIndex): string {\n\tconst name = storage.nameRegistry[index];\n\tif (name === undefined) {\n\t\tthrow new Error(`Name index ${index} not found in registry`);\n\t}\n\treturn name;\n}\n\n/**\n * Convert a location to a KV key string.\n * Named entries use their string name, loop iterations use ~N format.\n */\nexport function locationToKey(storage: Storage, location: Location): string {\n\treturn location\n\t\t.map((segment) => {\n\t\t\tif (typeof segment === \"number\") {\n\t\t\t\treturn resolveName(storage, segment);\n\t\t\t}\n\t\t\treturn `~${segment.iteration}`;\n\t\t})\n\t\t.join(\"/\");\n}\n\n/**\n * Append a named segment to a location.\n */\nexport function appendName(\n\tstorage: Storage,\n\tlocation: Location,\n\tname: string,\n): Location {\n\tconst nameIndex = registerName(storage, name);\n\treturn [...location, nameIndex];\n}\n\n/**\n * Append a loop iteration segment to a location.\n */\nexport function appendLoopIteration(\n\tstorage: Storage,\n\tlocation: Location,\n\tloopName: string,\n\titeration: number,\n): Location {\n\tconst loopIndex = registerName(storage, loopName);\n\treturn [...location, { loop: loopIndex, iteration }];\n}\n\n/**\n * Create an empty location (root).\n */\nexport function emptyLocation(): Location {\n\treturn [];\n}\n\n/**\n * Get the parent location (all segments except the last).\n */\nexport function parentLocation(location: Location): Location {\n\treturn location.slice(0, -1);\n}\n\n/**\n * Check if one location is a prefix of another.\n */\nexport function isLocationPrefix(\n\tprefix: Location,\n\tlocation: Location,\n): boolean {\n\tif (prefix.length > location.length) {\n\t\treturn false;\n\t}\n\tfor (let i = 0; i < prefix.length; i++) {\n\t\tconst prefixSegment = prefix[i];\n\t\tconst locationSegment = location[i];\n\n\t\tif (typeof prefixSegment === \"number\" && typeof locationSegment === \"number\") {\n\t\t\tif (prefixSegment !== locationSegment) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t} else if (\n\t\t\tisLoopIterationMarker(prefixSegment) &&\n\t\t\tisLoopIterationMarker(locationSegment)\n\t\t) {\n\t\t\tif (\n\t\t\t\tprefixSegment.loop !== locationSegment.loop ||\n\t\t\t\tprefixSegment.iteration !== locationSegment.iteration\n\t\t\t) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t} else {\n\t\t\treturn false;\n\t\t}\n\t}\n\treturn true;\n}\n\n/**\n * Compare two locations for equality.\n */\nexport function locationsEqual(a: Location, b: Location): boolean {\n\tif (a.length !== b.length) {\n\t\treturn false;\n\t}\n\treturn isLocationPrefix(a, b);\n}\n\n/**\n * Get all entry keys that are children of a given location.\n *\n * Note: Returns a map of key → entry for convenience, not key → location.\n * The location can be retrieved from the entry itself via entry.location.\n */\nexport function getChildEntries(\n\tstorage: Storage,\n\tparentLoc: Location,\n): Map<string, Location> {\n\tconst parentKey = locationToKey(storage, parentLoc);\n\tconst children = new Map<string, Location>();\n\n\tfor (const [key, entry] of storage.history.entries) {\n\t\t// Handle empty parent (root) - all entries are children\n\t\tconst isChild =\n\t\t\tparentKey === \"\"\n\t\t\t\t? true\n\t\t\t\t: key.startsWith(parentKey + \"/\") || key === parentKey;\n\n\t\tif (isChild) {\n\t\t\t// Return the actual entry's location, not the parent location\n\t\t\tchildren.set(key, entry.location);\n\t\t}\n\t}\n\n\treturn children;\n}\n","/**\n * Serialization/deserialization utilities for converting between\n * internal TypeScript types and BARE schema types.\n */\n\nimport * as cbor from \"cbor-x\";\nimport type * as v1 from \"../dist/schemas/v1.js\";\nimport {\n\tBranchStatusType as BareBranchStatusType,\n\tEntryStatus as BareEntryStatus,\n\tSleepState as BareSleepState,\n} from \"../dist/schemas/v1.js\";\nimport type {\n\tBranchStatus as InternalBranchStatus,\n\tBranchStatusType as InternalBranchStatusType,\n\tEntry as InternalEntry,\n\tEntryKind as InternalEntryKind,\n\tEntryMetadata as InternalEntryMetadata,\n\tEntryStatus as InternalEntryStatus,\n\tLocation as InternalLocation,\n\tLoopIterationMarker as InternalLoopIterationMarker,\n\tPathSegment as InternalPathSegment,\n\tSleepState as InternalSleepState,\n\tWorkflowState as InternalWorkflowState,\n} from \"../src/types.js\";\nimport {\n\tCURRENT_VERSION,\n\tENTRY_METADATA_VERSIONED,\n\tENTRY_VERSIONED,\n\tWORKFLOW_METADATA_VERSIONED,\n} from \"./versioned.js\";\n\n// === Helper: ArrayBuffer to/from utilities ===\n\nfunction bufferToArrayBuffer(buf: Uint8Array): ArrayBuffer {\n\t// Create a new ArrayBuffer and copy the data to ensure it's not a SharedArrayBuffer\n\tconst arrayBuffer = new ArrayBuffer(buf.byteLength);\n\tnew Uint8Array(arrayBuffer).set(buf);\n\treturn arrayBuffer;\n}\n\nfunction encodeCbor(value: unknown): ArrayBuffer {\n\treturn bufferToArrayBuffer(cbor.encode(value));\n}\n\nfunction decodeCbor<T>(data: ArrayBuffer): T {\n\treturn cbor.decode(new Uint8Array(data)) as T;\n}\n\n/**\n * Validate that a value is a non-null object.\n */\nfunction assertObject(\n\tvalue: unknown,\n\tcontext: string,\n): asserts value is Record<string, unknown> {\n\tif (typeof value !== \"object\" || value === null) {\n\t\tthrow new Error(`${context}: expected object, got ${typeof value}`);\n\t}\n}\n\n/**\n * Validate that a value is a string.\n */\nfunction assertString(\n\tvalue: unknown,\n\tcontext: string,\n): asserts value is string {\n\tif (typeof value !== \"string\") {\n\t\tthrow new Error(`${context}: expected string, got ${typeof value}`);\n\t}\n}\n\n/**\n * Validate that a value is a number.\n */\nfunction assertNumber(\n\tvalue: unknown,\n\tcontext: string,\n): asserts value is number {\n\tif (typeof value !== \"number\") {\n\t\tthrow new Error(`${context}: expected number, got ${typeof value}`);\n\t}\n}\n\n// === Entry Status Conversion ===\n\nfunction entryStatusToBare(status: InternalEntryStatus): BareEntryStatus {\n\tswitch (status) {\n\t\tcase \"pending\":\n\t\t\treturn BareEntryStatus.PENDING;\n\t\tcase \"running\":\n\t\t\treturn BareEntryStatus.RUNNING;\n\t\tcase \"completed\":\n\t\t\treturn BareEntryStatus.COMPLETED;\n\t\tcase \"failed\":\n\t\t\treturn BareEntryStatus.FAILED;\n\t\tcase \"exhausted\":\n\t\t\treturn BareEntryStatus.EXHAUSTED;\n\t}\n}\n\nfunction entryStatusFromBare(status: BareEntryStatus): InternalEntryStatus {\n\tswitch (status) {\n\t\tcase BareEntryStatus.PENDING:\n\t\t\treturn \"pending\";\n\t\tcase BareEntryStatus.RUNNING:\n\t\t\treturn \"running\";\n\t\tcase BareEntryStatus.COMPLETED:\n\t\t\treturn \"completed\";\n\t\tcase BareEntryStatus.FAILED:\n\t\t\treturn \"failed\";\n\t\tcase BareEntryStatus.EXHAUSTED:\n\t\t\treturn \"exhausted\";\n\t}\n}\n\n// === Sleep State Conversion ===\n\nfunction sleepStateToBare(state: InternalSleepState): BareSleepState {\n\tswitch (state) {\n\t\tcase \"pending\":\n\t\t\treturn BareSleepState.PENDING;\n\t\tcase \"completed\":\n\t\t\treturn BareSleepState.COMPLETED;\n\t\tcase \"interrupted\":\n\t\t\treturn BareSleepState.INTERRUPTED;\n\t}\n}\n\nfunction sleepStateFromBare(state: BareSleepState): InternalSleepState {\n\tswitch (state) {\n\t\tcase BareSleepState.PENDING:\n\t\t\treturn \"pending\";\n\t\tcase BareSleepState.COMPLETED:\n\t\t\treturn \"completed\";\n\t\tcase BareSleepState.INTERRUPTED:\n\t\t\treturn \"interrupted\";\n\t}\n}\n\n// === Branch Status Type Conversion ===\n\nfunction branchStatusTypeToBare(\n\tstatus: InternalBranchStatusType,\n): BareBranchStatusType {\n\tswitch (status) {\n\t\tcase \"pending\":\n\t\t\treturn BareBranchStatusType.PENDING;\n\t\tcase \"running\":\n\t\t\treturn BareBranchStatusType.RUNNING;\n\t\tcase \"completed\":\n\t\t\treturn BareBranchStatusType.COMPLETED;\n\t\tcase \"failed\":\n\t\t\treturn BareBranchStatusType.FAILED;\n\t\tcase \"cancelled\":\n\t\t\treturn BareBranchStatusType.CANCELLED;\n\t}\n}\n\nfunction branchStatusTypeFromBare(\n\tstatus: BareBranchStatusType,\n): InternalBranchStatusType {\n\tswitch (status) {\n\t\tcase BareBranchStatusType.PENDING:\n\t\t\treturn \"pending\";\n\t\tcase BareBranchStatusType.RUNNING:\n\t\t\treturn \"running\";\n\t\tcase BareBranchStatusType.COMPLETED:\n\t\t\treturn \"completed\";\n\t\tcase BareBranchStatusType.FAILED:\n\t\t\treturn \"failed\";\n\t\tcase BareBranchStatusType.CANCELLED:\n\t\t\treturn \"cancelled\";\n\t}\n}\n\n// === Location Conversion ===\n\nfunction locationToBare(location: InternalLocation): v1.Location {\n\treturn location.map((segment): v1.PathSegment => {\n\t\tif (typeof segment === \"number\") {\n\t\t\treturn { tag: \"NameIndex\", val: segment };\n\t\t}\n\t\treturn {\n\t\t\ttag: \"LoopIterationMarker\",\n\t\t\tval: {\n\t\t\t\tloop: segment.loop,\n\t\t\t\titeration: segment.iteration,\n\t\t\t},\n\t\t};\n\t});\n}\n\nfunction locationFromBare(location: v1.Location): InternalLocation {\n\treturn location.map((segment): InternalPathSegment => {\n\t\tif (segment.tag === \"NameIndex\") {\n\t\t\treturn segment.val;\n\t\t}\n\t\treturn {\n\t\t\tloop: segment.val.loop,\n\t\t\titeration: segment.val.iteration,\n\t\t};\n\t});\n}\n\n// === Branch Status Conversion ===\n\nfunction branchStatusToBare(status: InternalBranchStatus): v1.BranchStatus {\n\treturn {\n\t\tstatus: branchStatusTypeToBare(status.status),\n\t\toutput: status.output !== undefined ? encodeCbor(status.output) : null,\n\t\terror: status.error ?? null,\n\t};\n}\n\nfunction branchStatusFromBare(status: v1.BranchStatus): InternalBranchStatus {\n\treturn {\n\t\tstatus: branchStatusTypeFromBare(status.status),\n\t\toutput: status.output !== null ? decodeCbor(status.output) : undefined,\n\t\terror: status.error ?? undefined,\n\t};\n}\n\n// === Entry Kind Conversion ===\n\nfunction entryKindToBare(kind: InternalEntryKind): v1.EntryKind {\n\tswitch (kind.type) {\n\t\tcase \"step\":\n\t\t\treturn {\n\t\t\t\ttag: \"StepEntry\",\n\t\t\t\tval: {\n\t\t\t\t\toutput:\n\t\t\t\t\t\tkind.data.output !== undefined\n\t\t\t\t\t\t\t? encodeCbor(kind.data.output)\n\t\t\t\t\t\t\t: null,\n\t\t\t\t\terror: kind.data.error ?? null,\n\t\t\t\t},\n\t\t\t};\n\t\tcase \"loop\":\n\t\t\treturn {\n\t\t\t\ttag: \"LoopEntry\",\n\t\t\t\tval: {\n\t\t\t\t\tstate: encodeCbor(kind.data.state),\n\t\t\t\t\titeration: kind.data.iteration,\n\t\t\t\t\toutput:\n\t\t\t\t\t\tkind.data.output !== undefined\n\t\t\t\t\t\t\t? encodeCbor(kind.data.output)\n\t\t\t\t\t\t\t: null,\n\t\t\t\t},\n\t\t\t};\n\t\tcase \"sleep\":\n\t\t\treturn {\n\t\t\t\ttag: \"SleepEntry\",\n\t\t\t\tval: {\n\t\t\t\t\tdeadline: BigInt(kind.data.deadline),\n\t\t\t\t\tstate: sleepStateToBare(kind.data.state),\n\t\t\t\t},\n\t\t\t};\n\t\tcase \"message\":\n\t\t\treturn {\n\t\t\t\ttag: \"MessageEntry\",\n\t\t\t\tval: {\n\t\t\t\t\tname: kind.data.name,\n\t\t\t\t\tmessageData: encodeCbor(kind.data.data),\n\t\t\t\t},\n\t\t\t};\n\t\tcase \"rollback_checkpoint\":\n\t\t\treturn {\n\t\t\t\ttag: \"RollbackCheckpointEntry\",\n\t\t\t\tval: {\n\t\t\t\t\tname: kind.data.name,\n\t\t\t\t},\n\t\t\t};\n\t\tcase \"join\":\n\t\t\treturn {\n\t\t\t\ttag: \"JoinEntry\",\n\t\t\t\tval: {\n\t\t\t\t\tbranches: new Map(\n\t\t\t\t\t\tObject.entries(kind.data.branches).map(\n\t\t\t\t\t\t\t([name, status]) => [\n\t\t\t\t\t\t\t\tname,\n\t\t\t\t\t\t\t\tbranchStatusToBare(status),\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t),\n\t\t\t\t\t),\n\t\t\t\t},\n\t\t\t};\n\t\tcase \"race\":\n\t\t\treturn {\n\t\t\t\ttag: \"RaceEntry\",\n\t\t\t\tval: {\n\t\t\t\t\twinner: kind.data.winner,\n\t\t\t\t\tbranches: new Map(\n\t\t\t\t\t\tObject.entries(kind.data.branches).map(\n\t\t\t\t\t\t\t([name, status]) => [\n\t\t\t\t\t\t\t\tname,\n\t\t\t\t\t\t\t\tbranchStatusToBare(status),\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t),\n\t\t\t\t\t),\n\t\t\t\t},\n\t\t\t};\n\t\tcase \"removed\":\n\t\t\treturn {\n\t\t\t\ttag: \"RemovedEntry\",\n\t\t\t\tval: {\n\t\t\t\t\toriginalType: kind.data.originalType,\n\t\t\t\t\toriginalName: kind.data.originalName ?? null,\n\t\t\t\t},\n\t\t\t};\n\t}\n}\n\nfunction entryKindFromBare(kind: v1.EntryKind): InternalEntryKind {\n\tswitch (kind.tag) {\n\t\tcase \"StepEntry\":\n\t\t\treturn {\n\t\t\t\ttype: \"step\",\n\t\t\t\tdata: {\n\t\t\t\t\toutput:\n\t\t\t\t\t\tkind.val.output !== null\n\t\t\t\t\t\t\t? decodeCbor(kind.val.output)\n\t\t\t\t\t\t\t: undefined,\n\t\t\t\t\terror: kind.val.error ?? undefined,\n\t\t\t\t},\n\t\t\t};\n\t\tcase \"LoopEntry\":\n\t\t\treturn {\n\t\t\t\ttype: \"loop\",\n\t\t\t\tdata: {\n\t\t\t\t\tstate: decodeCbor(kind.val.state),\n\t\t\t\t\titeration: kind.val.iteration,\n\t\t\t\t\toutput:\n\t\t\t\t\t\tkind.val.output !== null\n\t\t\t\t\t\t\t? decodeCbor(kind.val.output)\n\t\t\t\t\t\t\t: undefined,\n\t\t\t\t},\n\t\t\t};\n\t\tcase \"SleepEntry\":\n\t\t\treturn {\n\t\t\t\ttype: \"sleep\",\n\t\t\t\tdata: {\n\t\t\t\t\tdeadline: Number(kind.val.deadline),\n\t\t\t\t\tstate: sleepStateFromBare(kind.val.state),\n\t\t\t\t},\n\t\t\t};\n\t\tcase \"MessageEntry\":\n\t\t\treturn {\n\t\t\t\ttype: \"message\",\n\t\t\t\tdata: {\n\t\t\t\t\tname: kind.val.name,\n\t\t\t\t\tdata: decodeCbor(kind.val.messageData),\n\t\t\t\t},\n\t\t\t};\n\t\tcase \"RollbackCheckpointEntry\":\n\t\t\treturn {\n\t\t\t\ttype: \"rollback_checkpoint\",\n\t\t\t\tdata: {\n\t\t\t\t\tname: kind.val.name,\n\t\t\t\t},\n\t\t\t};\n\t\tcase \"JoinEntry\":\n\t\t\treturn {\n\t\t\t\ttype: \"join\",\n\t\t\t\tdata: {\n\t\t\t\t\tbranches: Object.fromEntries(\n\t\t\t\t\t\tArray.from(kind.val.branches.entries()).map(\n\t\t\t\t\t\t\t([name, status]) => [\n\t\t\t\t\t\t\t\tname,\n\t\t\t\t\t\t\t\tbranchStatusFromBare(status),\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t),\n\t\t\t\t\t),\n\t\t\t\t},\n\t\t\t};\n\t\tcase \"RaceEntry\":\n\t\t\treturn {\n\t\t\t\ttype: \"race\",\n\t\t\t\tdata: {\n\t\t\t\t\twinner: kind.val.winner,\n\t\t\t\t\tbranches: Object.fromEntries(\n\t\t\t\t\t\tArray.from(kind.val.branches.entries()).map(\n\t\t\t\t\t\t\t([name, status]) => [\n\t\t\t\t\t\t\t\tname,\n\t\t\t\t\t\t\t\tbranchStatusFromBare(status),\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t),\n\t\t\t\t\t),\n\t\t\t\t},\n\t\t\t};\n\t\tcase \"RemovedEntry\":\n\t\t\treturn {\n\t\t\t\ttype: \"removed\",\n\t\t\t\tdata: {\n\t\t\t\t\toriginalType: kind.val\n\t\t\t\t\t\t.originalType as InternalEntryKind[\"type\"],\n\t\t\t\t\toriginalName: kind.val.originalName ?? undefined,\n\t\t\t\t},\n\t\t\t};\n\t\tdefault:\n\t\t\tthrow new Error(\n\t\t\t\t`Unknown entry kind: ${(kind as { tag: string }).tag}`,\n\t\t\t);\n\t}\n}\n\n// === Entry Conversion & Serialization ===\n\nfunction entryToBare(entry: InternalEntry): v1.Entry {\n\treturn {\n\t\tid: entry.id,\n\t\tlocation: locationToBare(entry.location),\n\t\tkind: entryKindToBare(entry.kind),\n\t};\n}\n\nfunction entryFromBare(bareEntry: v1.Entry): InternalEntry {\n\treturn {\n\t\tid: bareEntry.id,\n\t\tlocation: locationFromBare(bareEntry.location),\n\t\tkind: entryKindFromBare(bareEntry.kind),\n\t\tdirty: false,\n\t};\n}\n\nexport function serializeEntry(entry: InternalEntry): Uint8Array {\n\tconst bareEntry = entryToBare(entry);\n\treturn ENTRY_VERSIONED.serializeWithEmbeddedVersion(\n\t\tbareEntry,\n\t\tCURRENT_VERSION,\n\t);\n}\n\nexport function deserializeEntry(bytes: Uint8Array): InternalEntry {\n\tconst bareEntry = ENTRY_VERSIONED.deserializeWithEmbeddedVersion(bytes);\n\treturn entryFromBare(bareEntry);\n}\n\n// === Entry Metadata Conversion & Serialization ===\n\nfunction entryMetadataToBare(\n\tmetadata: InternalEntryMetadata,\n): v1.EntryMetadata {\n\treturn {\n\t\tstatus: entryStatusToBare(metadata.status),\n\t\terror: metadata.error ?? null,\n\t\tattempts: metadata.attempts,\n\t\tlastAttemptAt: BigInt(metadata.lastAttemptAt),\n\t\tcreatedAt: BigInt(metadata.createdAt),\n\t\tcompletedAt:\n\t\t\tmetadata.completedAt !== undefined\n\t\t\t\t? BigInt(metadata.completedAt)\n\t\t\t\t: null,\n\t\trollbackCompletedAt:\n\t\t\tmetadata.rollbackCompletedAt !== undefined\n\t\t\t\t? BigInt(metadata.rollbackCompletedAt)\n\t\t\t\t: null,\n\t\trollbackError: metadata.rollbackError ?? null,\n\t};\n}\n\nfunction entryMetadataFromBare(\n\tbareMetadata: v1.EntryMetadata,\n): InternalEntryMetadata {\n\treturn {\n\t\tstatus: entryStatusFromBare(bareMetadata.status),\n\t\terror: bareMetadata.error ?? undefined,\n\t\tattempts: bareMetadata.attempts,\n\t\tlastAttemptAt: Number(bareMetadata.lastAttemptAt),\n\t\tcreatedAt: Number(bareMetadata.createdAt),\n\t\tcompletedAt:\n\t\t\tbareMetadata.completedAt !== null\n\t\t\t\t? Number(bareMetadata.completedAt)\n\t\t\t\t: undefined,\n\t\trollbackCompletedAt:\n\t\t\tbareMetadata.rollbackCompletedAt !== null\n\t\t\t\t? Number(bareMetadata.rollbackCompletedAt)\n\t\t\t\t: undefined,\n\t\trollbackError: bareMetadata.rollbackError ?? undefined,\n\t\tdirty: false,\n\t};\n}\n\nexport function serializeEntryMetadata(\n\tmetadata: InternalEntryMetadata,\n): Uint8Array {\n\tconst bareMetadata = entryMetadataToBare(metadata);\n\treturn ENTRY_METADATA_VERSIONED.serializeWithEmbeddedVersion(\n\t\tbareMetadata,\n\t\tCURRENT_VERSION,\n\t);\n}\n\nexport function deserializeEntryMetadata(\n\tbytes: Uint8Array,\n): InternalEntryMetadata {\n\tconst bareMetadata =\n\t\tENTRY_METADATA_VERSIONED.deserializeWithEmbeddedVersion(bytes);\n\treturn entryMetadataFromBare(bareMetadata);\n}\n\n// === Workflow Metadata Serialization ===\n// Note: These are used for reading/writing individual workflow fields\n\nexport function serializeWorkflowState(\n\tstate: InternalWorkflowState,\n): Uint8Array {\n\t// For simple values, we can encode them directly without the full metadata struct\n\t// Using a single byte for efficiency\n\tconst encoder = new TextEncoder();\n\treturn encoder.encode(state);\n}\n\nexport function deserializeWorkflowState(\n\tbytes: Uint8Array,\n): InternalWorkflowState {\n\tconst decoder = new TextDecoder();\n\tconst state = decoder.decode(bytes) as InternalWorkflowState;\n\tconst validStates: InternalWorkflowState[] = [\n\t\t\"pending\",\n\t\t\"running\",\n\t\t\"sleeping\",\n\t\t\"failed\",\n\t\t\"completed\",\n\t\t\"cancelled\",\n\t\t\"rolling_back\",\n\t];\n\tif (!validStates.includes(state)) {\n\t\tthrow new Error(`Invalid workflow state: ${state}`);\n\t}\n\treturn state;\n}\n\nexport function serializeWorkflowOutput(output: unknown): Uint8Array {\n\treturn cbor.encode(output);\n}\n\nexport function deserializeWorkflowOutput<T>(bytes: Uint8Array): T {\n\ttry {\n\t\treturn cbor.decode(bytes) as T;\n\t} catch (error) {\n\t\tthrow new Error(\n\t\t\t`Failed to deserialize workflow output: ${error instanceof Error ? error.message : String(error)}`,\n\t\t);\n\t}\n}\n\n/**\n * Structured error type for serialization.\n */\ninterface SerializedWorkflowError {\n\tname: string;\n\tmessage: string;\n\tstack?: string;\n\tmetadata?: Record<string, unknown>;\n}\n\nexport function serializeWorkflowError(\n\terror: SerializedWorkflowError,\n): Uint8Array {\n\treturn cbor.encode(error);\n}\n\nexport function deserializeWorkflowError(\n\tbytes: Uint8Array,\n): SerializedWorkflowError {\n\tconst decoded = cbor.decode(bytes);\n\tassertObject(decoded, \"WorkflowError\");\n\t// Validate required fields\n\tconst obj = decoded as Record<string, unknown>;\n\tassertString(obj.name, \"WorkflowError.name\");\n\tassertString(obj.message, \"WorkflowError.message\");\n\treturn {\n\t\tname: obj.name,\n\t\tmessage: obj.message,\n\t\tstack: typeof obj.stack === \"string\" ? obj.stack : undefined,\n\t\tmetadata:\n\t\t\ttypeof obj.metadata === \"object\" && obj.metadata !== null\n\t\t\t\t? (obj.metadata as Record<string, unknown>)\n\t\t\t\t: undefined,\n\t};\n}\n\nexport function serializeWorkflowInput(input: unknown): Uint8Array {\n\treturn cbor.encode(input);\n}\n\nexport function deserializeWorkflowInput<T>(bytes: Uint8Array): T {\n\ttry {\n\t\treturn cbor.decode(bytes) as T;\n\t} catch (error) {\n\t\tthrow new Error(\n\t\t\t`Failed to deserialize workflow input: ${error instanceof Error ? error.message : String(error)}`,\n\t\t);\n\t}\n}\n\n// === Name Registry Serialization ===\n\nexport function serializeName(name: string): Uint8Array {\n\tconst encoder = new TextEncoder();\n\treturn encoder.encode(name);\n}\n\nexport function deserializeName(bytes: Uint8Array): string {\n\tconst decoder = new TextDecoder();\n\treturn decoder.decode(bytes);\n}\n","// @generated - post-processed by compile-bare.ts\nimport * as bare from \"@rivetkit/bare-ts\"\n\nconst config = /* @__PURE__ */ bare.Config({})\n\nexport type u32 = number\nexport type u64 = bigint\n\nexport type Cbor = ArrayBuffer\n\nexport function readCbor(bc: bare.ByteCursor): Cbor {\n return bare.readData(bc)\n}\n\nexport function writeCbor(bc: bare.ByteCursor, x: Cbor): void {\n bare.writeData(bc, x)\n}\n\nexport type NameIndex = u32\n\nexport function readNameIndex(bc: bare.ByteCursor): NameIndex {\n return bare.readU32(bc)\n}\n\nexport function writeNameIndex(bc: bare.ByteCursor, x: NameIndex): void {\n bare.writeU32(bc, x)\n}\n\nexport type LoopIterationMarker = {\n readonly loop: NameIndex,\n readonly iteration: u32,\n}\n\nexport function readLoopIterationMarker(bc: bare.ByteCursor): LoopIterationMarker {\n return {\n loop: readNameIndex(bc),\n iteration: bare.readU32(bc),\n }\n}\n\nexport function writeLoopIterationMarker(bc: bare.ByteCursor, x: LoopIterationMarker): void {\n writeNameIndex(bc, x.loop)\n bare.writeU32(bc, x.iteration)\n}\n\nexport type PathSegment =\n | { readonly tag: \"NameIndex\", readonly val: NameIndex }\n | { readonly tag: \"LoopIterationMarker\", readonly val: LoopIterationMarker }\n\nexport function readPathSegment(bc: bare.ByteCursor): PathSegment {\n const offset = bc.offset\n const tag = bare.readU8(bc)\n switch (tag) {\n case 0:\n return { tag: \"NameIndex\", val: readNameIndex(bc) }\n case 1:\n return { tag: \"LoopIterationMarker\", val: readLoopIterationMarker(bc) }\n default: {\n bc.offset = offset\n throw new bare.BareError(offset, \"invalid tag\")\n }\n }\n}\n\nexport function writePathSegment(bc: bare.ByteCursor, x: PathSegment): void {\n switch (x.tag) {\n case \"NameIndex\": {\n bare.writeU8(bc, 0)\n writeNameIndex(bc, x.val)\n break\n }\n case \"LoopIterationMarker\": {\n bare.writeU8(bc, 1)\n writeLoopIterationMarker(bc, x.val)\n break\n }\n }\n}\n\nexport type Location = readonly PathSegment[]\n\nexport function readLocation(bc: bare.ByteCursor): Location {\n const len = bare.readUintSafe(bc)\n if (len === 0) { return [] }\n const result = [readPathSegment(bc)]\n for (let i = 1; i < len; i++) {\n result[i] = readPathSegment(bc)\n }\n return result\n}\n\nexport function writeLocation(bc: bare.ByteCursor, x: Location): void {\n bare.writeUintSafe(bc, x.length)\n for (let i = 0; i < x.length; i++) {\n writePathSegment(bc, x[i])\n }\n}\n\nexport enum EntryStatus {\n PENDING = \"PENDING\",\n RUNNING = \"RUNNING\",\n COMPLETED = \"COMPLETED\",\n FAILED = \"FAILED\",\n EXHAUSTED = \"EXHAUSTED\",\n}\n\nexport function readEntryStatus(bc: bare.ByteCursor): EntryStatus {\n const offset = bc.offset\n const tag = bare.readU8(bc)\n switch (tag) {\n case 0:\n return EntryStatus.PENDING\n case 1:\n return EntryStatus.RUNNING\n case 2:\n return EntryStatus.COMPLETED\n case 3:\n return EntryStatus.FAILED\n case 4:\n return EntryStatus.EXHAUSTED\n default: {\n bc.offset = offset\n throw new bare.BareError(offset, \"invalid tag\")\n }\n }\n}\n\nexport function writeEntryStatus(bc: bare.ByteCursor, x: EntryStatus): void {\n switch (x) {\n case EntryStatus.PENDING: {\n bare.writeU8(bc, 0)\n break\n }\n case EntryStatus.RUNNING: {\n bare.writeU8(bc, 1)\n break\n }\n case EntryStatus.COMPLETED: {\n bare.writeU8(bc, 2)\n break\n }\n case EntryStatus.FAILED: {\n bare.writeU8(bc, 3)\n break\n }\n case EntryStatus.EXHAUSTED: {\n bare.writeU8(bc, 4)\n break\n }\n }\n}\n\nexport enum SleepState {\n PENDING = \"PENDING\",\n COMPLETED = \"COMPLETED\",\n INTERRUPTED = \"INTERRUPTED\",\n}\n\nexport function readSleepState(bc: bare.ByteCursor): SleepState {\n const offset = bc.offset\n const tag = bare.readU8(bc)\n switch (tag) {\n case 0:\n return SleepState.PENDING\n case 1:\n return SleepState.COMPLETED\n case 2:\n return SleepState.INTERRUPTED\n default: {\n bc.offset = offset\n throw new bare.BareError(offset, \"invalid tag\")\n }\n }\n}\n\nexport function writeSleepState(bc: bare.ByteCursor, x: SleepState): void {\n switch (x) {\n case SleepState.PENDING: {\n bare.writeU8(bc, 0)\n break\n }\n case SleepState.COMPLETED: {\n bare.writeU8(bc, 1)\n break\n }\n case SleepState.INTERRUPTED: {\n bare.writeU8(bc, 2)\n break\n }\n }\n}\n\nexport enum BranchStatusType {\n PENDING = \"PENDING\",\n RUNNING = \"RUNNING\",\n COMPLETED = \"COMPLETED\",\n FAILED = \"FAILED\",\n CANCELLED = \"CANCELLED\",\n}\n\nexport function readBranchStatusType(bc: bare.ByteCursor): BranchStatusType {\n const offset = bc.offset\n const tag = bare.readU8(bc)\n switch (tag) {\n case 0:\n return BranchStatusType.PENDING\n case 1:\n return BranchStatusType.RUNNING\n case 2:\n return BranchStatusType.COMPLETED\n case 3:\n return BranchStatusType.FAILED\n case 4:\n return BranchStatusType.CANCELLED\n default: {\n bc.offset = offset\n throw new bare.BareError(offset, \"invalid tag\")\n }\n }\n}\n\nexport function writeBranchStatusType(bc: bare.ByteCursor, x: BranchStatusType): void {\n switch (x) {\n case BranchStatusType.PENDING: {\n bare.writeU8(bc, 0)\n break\n }\n case BranchStatusType.RUNNING: {\n bare.writeU8(bc, 1)\n break\n }\n case BranchStatusType.COMPLETED: {\n bare.writeU8(bc, 2)\n break\n }\n case BranchStatusType.FAILED: {\n bare.writeU8(bc, 3)\n break\n }\n case BranchStatusType.CANCELLED: {\n bare.writeU8(bc, 4)\n break\n }\n }\n}\n\nfunction read0(bc: bare.ByteCursor): Cbor | null {\n return bare.readBool(bc)\n ? readCbor(bc)\n : null\n}\n\nfunction write0(bc: bare.ByteCursor, x: Cbor | null): void {\n bare.writeBool(bc, x !== null)\n if (x !== null) {\n writeCbor(bc, x)\n }\n}\n\nfunction read1(bc: bare.ByteCursor): string | null {\n return bare.readBool(bc)\n ? bare.readString(bc)\n : null\n}\n\nfunction write1(bc: bare.ByteCursor, x: string | null): void {\n bare.writeBool(bc, x !== null)\n if (x !== null) {\n bare.writeString(bc, x)\n }\n}\n\nexport type StepEntry = {\n readonly output: Cbor | null,\n readonly error: string | null,\n}\n\nexport function readStepEntry(bc: bare.ByteCursor): StepEntry {\n return {\n output: read0(bc),\n error: read1(bc),\n }\n}\n\nexport function writeStepEntry(bc: bare.ByteCursor, x: StepEntry): void {\n write0(bc, x.output)\n write1(bc, x.error)\n}\n\nexport type LoopEntry = {\n readonly state: Cbor,\n readonly iteration: u32,\n readonly output: Cbor | null,\n}\n\nexport function readLoopEntry(bc: bare.ByteCursor): LoopEntry {\n return {\n state: readCbor(bc),\n iteration: bare.readU32(bc),\n output: read0(bc),\n }\n}\n\nexport function writeLoopEntry(bc: bare.ByteCursor, x: LoopEntry): void {\n writeCbor(bc, x.state)\n bare.writeU32(bc, x.iteration)\n write0(bc, x.output)\n}\n\nexport type SleepEntry = {\n readonly deadline: u64,\n readonly state: SleepState,\n}\n\nexport function readSleepEntry(bc: bare.ByteCursor): SleepEntry {\n return {\n deadline: bare.readU64(bc),\n state: readSleepState(bc),\n }\n}\n\nexport function writeSleepEntry(bc: bare.ByteCursor, x: SleepEntry): void {\n bare.writeU64(bc, x.deadline)\n writeSleepState(bc, x.state)\n}\n\nexport type MessageEntry = {\n readonly name: string,\n readonly messageData: Cbor,\n}\n\nexport function readMessageEntry(bc: bare.ByteCursor): MessageEntry {\n return {\n name: bare.readString(bc),\n messageData: readCbor(bc),\n }\n}\n\nexport function writeMessageEntry(bc: bare.ByteCursor, x: MessageEntry): void {\n bare.writeString(bc, x.name)\n writeCbor(bc, x.messageData)\n}\n\nexport type RollbackCheckpointEntry = {\n readonly name: string,\n}\n\nexport function readRollbackCheckpointEntry(bc: bare.ByteCursor): RollbackCheckpointEntry {\n return {\n name: bare.readString(bc),\n }\n}\n\nexport function writeRollbackCheckpointEntry(bc: bare.ByteCursor, x: RollbackCheckpointEntry): void {\n bare.writeString(bc, x.name)\n}\n\nexport type BranchStatus = {\n readonly status: BranchStatusType,\n readonly output: Cbor | null,\n readonly error: string | null,\n}\n\nexport function readBranchStatus(bc: bare.ByteCursor): BranchStatus {\n return {\n status: readBranchStatusType(bc),\n output: read0(bc),\n error: read1(bc),\n }\n}\n\nexport function writeBranchStatus(bc: bare.ByteCursor, x: BranchStatus): void {\n writeBranchStatusType(bc, x.status)\n write0(bc, x.output)\n write1(bc, x.error)\n}\n\nfunction read2(bc: bare.ByteCursor): ReadonlyMap<string, BranchStatus> {\n const len = bare.readUintSafe(bc)\n const result = new Map<string, BranchStatus>()\n for (let i = 0; i < len; i++) {\n const offset = bc.offset\n const key = bare.readString(bc)\n if (result.has(key)) {\n bc.offset = offset\n throw new bare.BareError(offset, \"duplicated key\")\n }\n result.set(key, readBranchStatus(bc))\n }\n return result\n}\n\nfunction write2(bc: bare.ByteCursor, x: ReadonlyMap<string, BranchStatus>): void {\n bare.writeUintSafe(bc, x.size)\n for(const kv of x) {\n bare.writeString(bc, kv[0])\n writeBranchStatus(bc, kv[1])\n }\n}\n\nexport type JoinEntry = {\n readonly branches: ReadonlyMap<string, BranchStatus>,\n}\n\nexport function readJoinEntry(bc: bare.ByteCursor): JoinEntry {\n return {\n branches: read2(bc),\n }\n}\n\nexport function writeJoinEntry(bc: bare.ByteCursor, x: JoinEntry): void {\n write2(bc, x.branches)\n}\n\nexport type RaceEntry = {\n readonly winner: string | null,\n readonly branches: ReadonlyMap<string, BranchStatus>,\n}\n\nexport function readRaceEntry(bc: bare.ByteCursor): RaceEntry {\n return {\n winner: read1(bc),\n branches: read2(bc),\n }\n}\n\nexport function writeRaceEntry(bc: bare.ByteCursor, x: RaceEntry): void {\n write1(bc, x.winner)\n write2(bc, x.branches)\n}\n\nexport type RemovedEntry = {\n readonly originalType: string,\n readonly originalName: string | null,\n}\n\nexport function readRemovedEntry(bc: bare.ByteCursor): RemovedEntry {\n return {\n originalType: bare.readString(bc),\n originalName: read1(bc),\n }\n}\n\nexport function writeRemovedEntry(bc: bare.ByteCursor, x: RemovedEntry): void {\n bare.writeString(bc, x.originalType)\n write1(bc, x.originalName)\n}\n\nexport type EntryKind =\n | { readonly tag: \"StepEntry\", readonly val: StepEntry }\n | { readonly tag: \"LoopEntry\", readonly val: LoopEntry }\n | { readonly tag: \"SleepEntry\", readonly val: SleepEntry }\n | { readonly tag: \"MessageEntry\", readonly val: MessageEntry }\n | { readonly tag: \"RollbackCheckpointEntry\", readonly val: RollbackCheckpointEntry }\n | { readonly tag: \"JoinEntry\", readonly val: JoinEntry }\n | { readonly tag: \"RaceEntry\", readonly val: RaceEntry }\n | { readonly tag: \"RemovedEntry\", readonly val: RemovedEntry }\n\nexport function readEntryKind(bc: bare.ByteCursor): EntryKind {\n const offset = bc.offset\n const tag = bare.readU8(bc)\n switch (tag) {\n case 0:\n return { tag: \"StepEntry\", val: readStepEntry(bc) }\n case 1:\n return { tag: \"LoopEntry\", val: readLoopEntry(bc) }\n case 2:\n return { tag: \"SleepEntry\", val: readSleepEntry(bc) }\n case 3:\n return { tag: \"MessageEntry\", val: readMessageEntry(bc) }\n case 4:\n return { tag: \"RollbackCheckpointEntry\", val: readRollbackCheckpointEntry(bc) }\n case 5:\n return { tag: \"JoinEntry\", val: readJoinEntry(bc) }\n case 6:\n return { tag: \"RaceEntry\", val: readRaceEntry(bc) }\n case 7:\n return { tag: \"RemovedEntry\", val: readRemovedEntry(bc) }\n default: {\n bc.offset = offset\n throw new bare.BareError(offset, \"invalid tag\")\n }\n }\n}\n\nexport function writeEntryKind(bc: bare.ByteCursor, x: EntryKind): void {\n switch (x.tag) {\n case \"StepEntry\": {\n bare.writeU8(bc, 0)\n writeStepEntry(bc, x.val)\n break\n }\n case \"LoopEntry\": {\n bare.writeU8(bc, 1)\n writeLoopEntry(bc, x.val)\n break\n }\n case \"SleepEntry\": {\n bare.writeU8(bc, 2)\n writeSleepEntry(bc, x.val)\n break\n }\n case \"MessageEntry\": {\n bare.writeU8(bc, 3)\n writeMessageEntry(bc, x.val)\n break\n }\n case \"RollbackCheckpointEntry\": {\n bare.writeU8(bc, 4)\n writeRollbackCheckpointEntry(bc, x.val)\n break\n }\n case \"JoinEntry\": {\n bare.writeU8(bc, 5)\n writeJoinEntry(bc, x.val)\n break\n }\n case \"RaceEntry\": {\n bare.writeU8(bc, 6)\n writeRaceEntry(bc, x.val)\n break\n }\n case \"RemovedEntry\": {\n bare.writeU8(bc, 7)\n writeRemovedEntry(bc, x.val)\n break\n }\n }\n}\n\nexport type Entry = {\n readonly id: string,\n readonly location: Location,\n readonly kind: EntryKind,\n}\n\nexport function readEntry(bc: bare.ByteCursor): Entry {\n return {\n id: bare.readString(bc),\n location: readLocation(bc),\n kind: readEntryKind(bc),\n }\n}\n\nexport function writeEntry(bc: bare.ByteCursor, x: Entry): void {\n bare.writeString(bc, x.id)\n writeLocation(bc, x.location)\n writeEntryKind(bc, x.kind)\n}\n\nexport function encodeEntry(x: Entry): Uint8Array {\n const bc = new bare.ByteCursor(\n new Uint8Array(config.initialBufferLength),\n config\n )\n writeEntry(bc, x)\n return new Uint8Array(bc.view.buffer, bc.view.byteOffset, bc.offset)\n}\n\nexport function decodeEntry(bytes: Uint8Array): Entry {\n const bc = new bare.ByteCursor(bytes, config)\n const result = readEntry(bc)\n if (bc.offset < bc.view.byteLength) {\n throw new bare.BareError(bc.offset, \"remaining bytes\")\n }\n return result\n}\n\nfunction read3(bc: bare.ByteCursor): u64 | null {\n return bare.readBool(bc)\n ? bare.readU64(bc)\n : null\n}\n\nfunction write3(bc: bare.ByteCursor, x: u64 | null): void {\n bare.writeBool(bc, x !== null)\n if (x !== null) {\n bare.writeU64(bc, x)\n }\n}\n\nexport type EntryMetadata = {\n readonly status: EntryStatus,\n readonly error: string | null,\n readonly attempts: u32,\n readonly lastAttemptAt: u64,\n readonly createdAt: u64,\n readonly completedAt: u64 | null,\n readonly rollbackCompletedAt: u64 | null,\n readonly rollbackError: string | null,\n}\n\nexport function readEntryMetadata(bc: bare.ByteCursor): EntryMetadata {\n return {\n status: readEntryStatus(bc),\n error: read1(bc),\n attempts: bare.readU32(bc),\n lastAttemptAt: bare.readU64(bc),\n createdAt: bare.readU64(bc),\n completedAt: read3(bc),\n rollbackCompletedAt: read3(bc),\n rollbackError: read1(bc),\n }\n}\n\nexport function writeEntryMetadata(bc: bare.ByteCursor, x: EntryMetadata): void {\n writeEntryStatus(bc, x.status)\n write1(bc, x.error)\n bare.writeU32(bc, x.attempts)\n bare.writeU64(bc, x.lastAttemptAt)\n bare.writeU64(bc, x.createdAt)\n write3(bc, x.completedAt)\n write3(bc, x.rollbackCompletedAt)\n write1(bc, x.rollbackError)\n}\n\nexport function encodeEntryMetadata(x: EntryMetadata): Uint8Array {\n const bc = new bare.ByteCursor(\n new Uint8Array(config.initialBufferLength),\n config\n )\n writeEntryMetadata(bc, x)\n return new Uint8Array(bc.view.buffer, bc.view.byteOffset, bc.offset)\n}\n\nexport function decodeEntryMetadata(bytes: Uint8Array): EntryMetadata {\n const bc = new bare.ByteCursor(bytes, config)\n const result = readEntryMetadata(bc)\n if (bc.offset < bc.view.byteLength) {\n throw new bare.BareError(bc.offset, \"remaining bytes\")\n }\n return result\n}\n\nexport type Message = {\n readonly id: string,\n readonly name: string,\n readonly messageData: Cbor,\n readonly sentAt: u64,\n}\n\nexport function readMessage(bc: bare.ByteCursor): Message {\n return {\n id: bare.readString(bc),\n name: bare.readString(bc),\n messageData: readCbor(bc),\n sentAt: bare.readU64(bc),\n }\n}\n\nexport function writeMessage(bc: bare.ByteCursor, x: Message): void {\n bare.writeString(bc, x.id)\n bare.writeString(bc, x.name)\n writeCbor(bc, x.messageData)\n bare.writeU64(bc, x.sentAt)\n}\n\nexport function encodeMessage(x: Message): Uint8Array {\n const bc = new bare.ByteCursor(\n new Uint8Array(config.initialBufferLength),\n config\n )\n writeMessage(bc, x)\n return new Uint8Array(bc.view.buffer, bc.view.byteOffset, bc.offset)\n}\n\nexport function decodeMessage(bytes: Uint8Array): Message {\n const bc = new bare.ByteCursor(bytes, config)\n const result = readMessage(bc)\n if (bc.offset < bc.view.byteLength) {\n throw new bare.BareError(bc.offset, \"remaining bytes\")\n }\n return result\n}\n\nexport enum WorkflowState {\n PENDING = \"PENDING\",\n RUNNING = \"RUNNING\",\n SLEEPING = \"SLEEPING\",\n FAILED = \"FAILED\",\n COMPLETED = \"COMPLETED\",\n ROLLING_BACK = \"ROLLING_BACK\",\n}\n\nexport function readWorkflowState(bc: bare.ByteCursor): WorkflowState {\n const offset = bc.offset\n const tag = bare.readU8(bc)\n switch (tag) {\n case 0:\n return WorkflowState.PENDING\n case 1:\n return WorkflowState.RUNNING\n case 2:\n return WorkflowState.SLEEPING\n case 3:\n return WorkflowState.FAILED\n case 4:\n return WorkflowState.COMPLETED\n case 5:\n return WorkflowState.ROLLING_BACK\n default: {\n bc.offset = offset\n throw new bare.BareError(offset, \"invalid tag\")\n }\n }\n}\n\nexport function writeWorkflowState(bc: bare.ByteCursor, x: WorkflowState): void {\n switch (x) {\n case WorkflowState.PENDING: {\n bare.writeU8(bc, 0)\n break\n }\n case WorkflowState.RUNNING: {\n bare.writeU8(bc, 1)\n break\n }\n case WorkflowState.SLEEPING: {\n bare.writeU8(bc, 2)\n break\n }\n case WorkflowState.FAILED: {\n bare.writeU8(bc, 3)\n break\n }\n case WorkflowState.COMPLETED: {\n bare.writeU8(bc, 4)\n break\n }\n case WorkflowState.ROLLING_BACK: {\n bare.writeU8(bc, 5)\n break\n }\n }\n}\n\nexport type WorkflowMetadata = {\n readonly state: WorkflowState,\n readonly output: Cbor | null,\n readonly error: string | null,\n readonly version: string | null,\n}\n\nexport function readWorkflowMetadata(bc: bare.ByteCursor): WorkflowMetadata {\n return {\n state: readWorkflowState(bc),\n output: read0(bc),\n error: read1(bc),\n version: read1(bc),\n }\n}\n\nexport function writeWorkflowMetadata(bc: bare.ByteCursor, x: WorkflowMetadata): void {\n writeWorkflowState(bc, x.state)\n write0(bc, x.output)\n write1(bc, x.error)\n write1(bc, x.version)\n}\n\nexport function encodeWorkflowMetadata(x: WorkflowMetadata): Uint8Array {\n const bc = new bare.ByteCursor(\n new Uint8Array(config.initialBufferLength),\n config\n )\n writeWorkflowMetadata(bc, x)\n return new Uint8Array(bc.view.buffer, bc.view.byteOffset, bc.offset)\n}\n\nexport function decodeWorkflowMetadata(bytes: Uint8Array): WorkflowMetadata {\n const bc = new bare.ByteCursor(bytes, config)\n const result = readWorkflowMetadata(bc)\n if (bc.offset < bc.view.byteLength) {\n throw new bare.BareError(bc.offset, \"remaining bytes\")\n }\n return result\n}\n\n\nfunction assert(condition: boolean, message?: string): asserts condition {\n if (!condition) throw new Error(message ?? \"Assertion failed\")\n}\n","import { createVersionedDataHandler } from \"vbare\";\nimport * as v1 from \"../dist/schemas/v1.js\";\n\nexport const CURRENT_VERSION = 1;\n\n// Re-export generated types for convenience\nexport type {\n\tBranchStatus,\n\tEntry,\n\tEntryKind,\n\tEntryMetadata,\n\tJoinEntry,\n\tLocation,\n\tLoopEntry,\n\tLoopIterationMarker,\n\tMessageEntry,\n\tPathSegment,\n\tRaceEntry,\n\tRemovedEntry,\n\tSleepEntry,\n\tStepEntry,\n\tWorkflowMetadata,\n} from \"../dist/schemas/v1.js\";\n\nexport {\n\tBranchStatusType,\n\tEntryStatus,\n\tSleepState,\n\tWorkflowState,\n} from \"../dist/schemas/v1.js\";\n\n// === Entry Handler ===\n\nexport const ENTRY_VERSIONED = createVersionedDataHandler<v1.Entry>({\n\tdeserializeVersion: (bytes, version) => {\n\t\tswitch (version) {\n\t\t\tcase 1:\n\t\t\t\treturn v1.decodeEntry(bytes);\n\t\t\tdefault:\n\t\t\t\tthrow new Error(`Unknown Entry version ${version}`);\n\t\t}\n\t},\n\tserializeVersion: (data, version) => {\n\t\tswitch (version) {\n\t\t\tcase 1:\n\t\t\t\treturn v1.encodeEntry(data as v1.Entry);\n\t\t\tdefault:\n\t\t\t\tthrow new Error(`Unknown Entry version ${version}`);\n\t\t}\n\t},\n\tdeserializeConverters: () => [],\n\tserializeConverters: () => [],\n});\n\n// === Entry Metadata Handler ===\n\nexport const ENTRY_METADATA_VERSIONED =\n\tcreateVersionedDataHandler<v1.EntryMetadata>({\n\t\tdeserializeVersion: (bytes, version) => {\n\t\t\tswitch (version) {\n\t\t\t\tcase 1:\n\t\t\t\t\treturn v1.decodeEntryMetadata(bytes);\n\t\t\t\tdefault:\n\t\t\t\t\tthrow new Error(`Unknown EntryMetadata version ${version}`);\n\t\t\t}\n\t\t},\n\t\tserializeVersion: (data, version) => {\n\t\t\tswitch (version) {\n\t\t\t\tcase 1:\n\t\t\t\t\treturn v1.encodeEntryMetadata(data as v1.EntryMetadata);\n\t\t\t\tdefault:\n\t\t\t\t\tthrow new Error(`Unknown EntryMetadata version ${version}`);\n\t\t\t}\n\t\t},\n\t\tdeserializeConverters: () => [],\n\t\tserializeConverters: () => [],\n\t});\n\n// === Workflow Metadata Handler ===\n\nexport const WORKFLOW_METADATA_VERSIONED =\n\tcreateVersionedDataHandler<v1.WorkflowMetadata>({\n\t\tdeserializeVersion: (bytes, version) => {\n\t\t\tswitch (version) {\n\t\t\t\tcase 1:\n\t\t\t\t\treturn v1.decodeWorkflowMetadata(bytes);\n\t\t\t\tdefault:\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`Unknown WorkflowMetadata version ${version}`,\n\t\t\t\t\t);\n\t\t\t}\n\t\t},\n\t\tserializeVersion: (data, version) => {\n\t\t\tswitch (version) {\n\t\t\t\tcase 1:\n\t\t\t\t\treturn v1.encodeWorkflowMetadata(\n\t\t\t\t\t\tdata as v1.WorkflowMetadata,\n\t\t\t\t\t);\n\t\t\t\tdefault:\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`Unknown WorkflowMetadata version ${version}`,\n\t\t\t\t\t);\n\t\t\t}\n\t\t},\n\t\tdeserializeConverters: () => [],\n\t\tserializeConverters: () => [],\n\t});\n","/**\n * Binary key encoding/decoding using fdb-tuple.\n * All keys are encoded as tuples with integer prefixes for proper sorting.\n */\n\nimport * as tuple from \"fdb-tuple\";\nimport type { Location, LoopIterationMarker, PathSegment } from \"./types.js\";\n\n// === Key Prefixes ===\n// Using integers for compact encoding and proper sorting\n\nexport const KEY_PREFIX = {\n\tNAMES: 1, // Name registry: [1, index]\n\tHISTORY: 2, // History entries: [2, ...locationSegments]\n\tWORKFLOW: 3, // Workflow metadata: [3, field]\n\tENTRY_METADATA: 4, // Entry metadata: [4, entryId]\n} as const;\n\n// Workflow metadata field identifiers\nexport const WORKFLOW_FIELD = {\n\tSTATE: 1,\n\tOUTPUT: 2,\n\tERROR: 3,\n\tINPUT: 4,\n} as const;\n\n// === Type Definitions ===\n\n// fdb-tuple's TupleItem type - we use a subset\ntype TupleItem = string | number | boolean | null | TupleItem[];\n\n// === Location Segment Encoding ===\n\n/**\n * Convert a path segment to tuple elements.\n * - NameIndex (number) → just the number\n * - LoopIterationMarker → nested tuple [loopIdx, iteration]\n */\nfunction segmentToTuple(segment: PathSegment): TupleItem {\n\tif (typeof segment === \"number\") {\n\t\treturn segment;\n\t}\n\t// LoopIterationMarker\n\treturn [segment.loop, segment.iteration];\n}\n\n/**\n * Convert tuple elements back to a path segment.\n */\nfunction tupleToSegment(element: TupleItem): PathSegment {\n\tif (typeof element === \"number\") {\n\t\treturn element;\n\t}\n\tif (Array.isArray(element) && element.length === 2) {\n\t\tconst [loop, iteration] = element;\n\t\tif (typeof loop === \"number\" && typeof iteration === \"number\") {\n\t\t\treturn { loop, iteration } as LoopIterationMarker;\n\t\t}\n\t}\n\tthrow new Error(\n\t\t`Invalid path segment tuple element: ${JSON.stringify(element)}`,\n\t);\n}\n\n/**\n * Convert a location to tuple elements.\n */\nfunction locationToTupleElements(location: Location): TupleItem[] {\n\treturn location.map(segmentToTuple);\n}\n\n/**\n * Convert tuple elements back to a location.\n */\nfunction tupleElementsToLocation(elements: TupleItem[]): Location {\n\treturn elements.map(tupleToSegment);\n}\n\n// === Helper Functions ===\n\n/**\n * Convert Buffer to Uint8Array.\n */\nfunction bufferToUint8Array(buf: Buffer): Uint8Array {\n\treturn new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength);\n}\n\n/**\n * Convert Uint8Array to Buffer.\n */\nfunction uint8ArrayToBuffer(arr: Uint8Array): Buffer {\n\treturn Buffer.from(arr.buffer, arr.byteOffset, arr.byteLength);\n}\n\n/**\n * Pack tuple items and return as Uint8Array.\n */\nfunction pack(items: TupleItem | TupleItem[]): Uint8Array {\n\tconst buf = tuple.pack(items);\n\treturn bufferToUint8Array(buf);\n}\n\n/**\n * Unpack a Uint8Array and return tuple items.\n */\nfunction unpack(data: Uint8Array): TupleItem[] {\n\tconst buf = uint8ArrayToBuffer(data);\n\treturn tuple.unpack(buf) as TupleItem[];\n}\n\n// === Key Builders ===\n\n/**\n * Build a key for the name registry.\n * Key: [1, index]\n */\nexport function buildNameKey(index: number): Uint8Array {\n\treturn pack([KEY_PREFIX.NAMES, index]);\n}\n\n/**\n * Build a prefix for listing all names.\n * Prefix: [1]\n */\nexport function buildNamePrefix(): Uint8Array {\n\treturn pack([KEY_PREFIX.NAMES]);\n}\n\n/**\n * Build a key for a history entry.\n * Key: [2, ...locationSegments]\n */\nexport function buildHistoryKey(location: Location): Uint8Array {\n\treturn pack([KEY_PREFIX.HISTORY, ...locationToTupleElements(location)]);\n}\n\n/**\n * Build a prefix for listing history entries under a location.\n * Prefix: [2, ...locationSegments]\n */\nexport function buildHistoryPrefix(location: Location): Uint8Array {\n\treturn pack([KEY_PREFIX.HISTORY, ...locationToTupleElements(location)]);\n}\n\n/**\n * Build a prefix for listing all history entries.\n * Prefix: [2]\n */\nexport function buildHistoryPrefixAll(): Uint8Array {\n\treturn pack([KEY_PREFIX.HISTORY]);\n}\n\n/**\n * Build a key for workflow state.\n * Key: [3, 1]\n */\nexport function buildWorkflowStateKey(): Uint8Array {\n\treturn pack([KEY_PREFIX.WORKFLOW, WORKFLOW_FIELD.STATE]);\n}\n\n/**\n * Build a key for workflow output.\n * Key: [3, 2]\n */\nexport function buildWorkflowOutputKey(): Uint8Array {\n\treturn pack([KEY_PREFIX.WORKFLOW, WORKFLOW_FIELD.OUTPUT]);\n}\n\n/**\n * Build a key for workflow error.\n * Key: [3, 3]\n */\nexport function buildWorkflowErrorKey(): Uint8Array {\n\treturn pack([KEY_PREFIX.WORKFLOW, WORKFLOW_FIELD.ERROR]);\n}\n\n/**\n * Build a key for workflow input.\n * Key: [3, 4]\n */\nexport function buildWorkflowInputKey(): Uint8Array {\n\treturn pack([KEY_PREFIX.WORKFLOW, WORKFLOW_FIELD.INPUT]);\n}\n\n/**\n * Build a key for entry metadata.\n * Key: [4, entryId]\n */\nexport function buildEntryMetadataKey(entryId: string): Uint8Array {\n\treturn pack([KEY_PREFIX.ENTRY_METADATA, entryId]);\n}\n\n/**\n * Build a prefix for listing all entry metadata.\n * Prefix: [4]\n */\nexport function buildEntryMetadataPrefix(): Uint8Array {\n\treturn pack([KEY_PREFIX.ENTRY_METADATA]);\n}\n\n// === Key Parsers ===\n\n/**\n * Parse a name key and return the index.\n * Key: [1, index] → index\n */\nexport function parseNameKey(key: Uint8Array): number {\n\tconst elements = unpack(key);\n\tif (elements.length !== 2 || elements[0] !== KEY_PREFIX.NAMES) {\n\t\tthrow new Error(\"Invalid name key\");\n\t}\n\treturn elements[1] as number;\n}\n\n/**\n * Parse a history key and return the location.\n * Key: [2, ...segments] → Location\n */\nexport function parseHistoryKey(key: Uint8Array): Location {\n\tconst elements = unpack(key);\n\tif (elements.length < 1 || elements[0] !== KEY_PREFIX.HISTORY) {\n\t\tthrow new Error(\"Invalid history key\");\n\t}\n\treturn tupleElementsToLocation(elements.slice(1));\n}\n\n/**\n * Parse an entry metadata key and return the entry ID.\n * Key: [4, entryId] → entryId\n */\nexport function parseEntryMetadataKey(key: Uint8Array): string {\n\tconst elements = unpack(key);\n\tif (elements.length !== 2 || elements[0] !== KEY_PREFIX.ENTRY_METADATA) {\n\t\tthrow new Error(\"Invalid entry metadata key\");\n\t}\n\treturn elements[1] as string;\n}\n\n// === Key Comparison Utilities ===\n\n/**\n * Check if a key starts with a prefix.\n */\nexport function keyStartsWith(key: Uint8Array, prefix: Uint8Array): boolean {\n\tif (key.length < prefix.length) {\n\t\treturn false;\n\t}\n\tfor (let i = 0; i < prefix.length; i++) {\n\t\tif (key[i] !== prefix[i]) {\n\t\t\treturn false;\n\t\t}\n\t}\n\treturn true;\n}\n\n/**\n * Compare two keys lexicographically.\n * Returns negative if a < b, 0 if a === b, positive if a > b.\n */\nexport function compareKeys(a: Uint8Array, b: Uint8Array): number {\n\tconst minLen = Math.min(a.length, b.length);\n\tfor (let i = 0; i < minLen; i++) {\n\t\tif (a[i] !== b[i]) {\n\t\t\treturn a[i] - b[i];\n\t\t}\n\t}\n\treturn a.length - b.length;\n}\n\n/**\n * Convert a key to a hex string for debugging.\n */\nexport function keyToHex(key: Uint8Array): string {\n\treturn Array.from(key)\n\t\t.map((b) => b.toString(16).padStart(2, \"0\"))\n\t\t.join(\"\");\n}\n","import {\n\tdeserializeEntry,\n\tdeserializeEntryMetadata,\n\tdeserializeName,\n\tdeserializeWorkflowError,\n\tdeserializeWorkflowOutput,\n\tdeserializeWorkflowState,\n\tserializeEntry,\n\tserializeEntryMetadata,\n\tserializeName,\n\tserializeWorkflowError,\n\tserializeWorkflowOutput,\n\tserializeWorkflowState,\n} from \"../schemas/serde.js\";\nimport type { EngineDriver, KVWrite } from \"./driver.js\";\nimport {\n\tbuildEntryMetadataKey,\n\tbuildHistoryKey,\n\tbuildHistoryPrefix,\n\tbuildHistoryPrefixAll,\n\tbuildNameKey,\n\tbuildNamePrefix,\n\tbuildWorkflowErrorKey,\n\tbuildWorkflowOutputKey,\n\tbuildWorkflowStateKey,\n\tcompareKeys,\n\tparseNameKey,\n} from \"./keys.js\";\nimport { isLocationPrefix, locationToKey } from \"./location.js\";\nimport type {\n\tEntry,\n\tEntryKind,\n\tEntryMetadata,\n\tLocation,\n\tStorage,\n\tWorkflowEntryMetadataSnapshot,\n\tWorkflowHistoryEntry,\n\tWorkflowHistorySnapshot,\n} from \"./types.js\";\n\n/**\n * Create an empty storage instance.\n */\nexport function createStorage(): Storage {\n\treturn {\n\t\tnameRegistry: [],\n\t\tflushedNameCount: 0,\n\t\thistory: { entries: new Map() },\n\t\tentryMetadata: new Map(),\n\t\toutput: undefined,\n\t\tstate: \"pending\",\n\t\tflushedState: undefined,\n\t\terror: undefined,\n\t\tflushedError: undefined,\n\t\tflushedOutput: undefined,\n\t};\n}\n\n/**\n * Create a snapshot of workflow history for observers.\n */\nexport function createHistorySnapshot(\n\tstorage: Storage,\n): WorkflowHistorySnapshot {\n\tconst entryMetadata = new Map<string, WorkflowEntryMetadataSnapshot>();\n\tfor (const [id, metadata] of storage.entryMetadata) {\n\t\tconst { dirty, ...rest } = metadata;\n\t\tentryMetadata.set(id, rest);\n\t}\n\n\tconst entries: WorkflowHistoryEntry[] = [];\n\tconst entryKeys = Array.from(storage.history.entries.keys()).sort();\n\tfor (const key of entryKeys) {\n\t\tconst entry = storage.history.entries.get(key);\n\t\tif (!entry) continue;\n\t\tconst { dirty, ...rest } = entry;\n\t\tentries.push(rest);\n\t}\n\n\treturn {\n\t\tnameRegistry: [...storage.nameRegistry],\n\t\tentries,\n\t\tentryMetadata,\n\t};\n}\n\n/**\n * Generate a UUID v4.\n */\nexport function generateId(): string {\n\treturn crypto.randomUUID();\n}\n\n/**\n * Create a new entry.\n */\nexport function createEntry(location: Location, kind: EntryKind): Entry {\n\treturn {\n\t\tid: generateId(),\n\t\tlocation,\n\t\tkind,\n\t\tdirty: true,\n\t};\n}\n\n/**\n * Create or get metadata for an entry.\n */\nexport function getOrCreateMetadata(\n\tstorage: Storage,\n\tentryId: string,\n): EntryMetadata {\n\tlet metadata = storage.entryMetadata.get(entryId);\n\tif (!metadata) {\n\t\tmetadata = {\n\t\t\tstatus: \"pending\",\n\t\t\tattempts: 0,\n\t\t\tlastAttemptAt: 0,\n\t\t\tcreatedAt: Date.now(),\n\t\t\trollbackCompletedAt: undefined,\n\t\t\trollbackError: undefined,\n\t\t\tdirty: true,\n\t\t};\n\t\tstorage.entryMetadata.set(entryId, metadata);\n\t}\n\treturn metadata;\n}\n\n/**\n * Load storage from the driver.\n */\nexport async function loadStorage(\n\tdriver: EngineDriver,\n): Promise<Storage> {\n\tconst storage = createStorage();\n\n\t// Load name registry\n\tconst nameEntries = await driver.list(buildNamePrefix());\n\t// Sort by index to ensure correct order\n\tnameEntries.sort((a, b) => compareKeys(a.key, b.key));\n\tfor (const entry of nameEntries) {\n\t\tconst index = parseNameKey(entry.key);\n\t\tstorage.nameRegistry[index] = deserializeName(entry.value);\n\t}\n\t// Track how many names are already persisted\n\tstorage.flushedNameCount = storage.nameRegistry.length;\n\n\t// Load history entries\n\tconst historyEntries = await driver.list(buildHistoryPrefixAll());\n\tfor (const entry of historyEntries) {\n\t\tconst parsed = deserializeEntry(entry.value);\n\t\tparsed.dirty = false;\n\t\t// Use locationToKey to match how context.ts looks up entries\n\t\tconst key = locationToKey(storage, parsed.location);\n\t\tstorage.history.entries.set(key, parsed);\n\t}\n\n\t// Load workflow state\n\tconst stateValue = await driver.get(buildWorkflowStateKey());\n\tif (stateValue) {\n\t\tstorage.state = deserializeWorkflowState(stateValue);\n\t\tstorage.flushedState = storage.state;\n\t}\n\n\t// Load output if present\n\tconst outputValue = await driver.get(buildWorkflowOutputKey());\n\tif (outputValue) {\n\t\tstorage.output = deserializeWorkflowOutput(outputValue);\n\t\tstorage.flushedOutput = storage.output;\n\t}\n\n\t// Load error if present\n\tconst errorValue = await driver.get(buildWorkflowErrorKey());\n\tif (errorValue) {\n\t\tstorage.error = deserializeWorkflowError(errorValue);\n\t\tstorage.flushedError = storage.error;\n\t}\n\n\treturn storage;\n}\n\n/**\n * Load metadata for an entry (lazy loading).\n */\nexport async function loadMetadata(\n\tstorage: Storage,\n\tdriver: EngineDriver,\n\tentryId: string,\n): Promise<EntryMetadata> {\n\t// Check if already loaded\n\tconst existing = storage.entryMetadata.get(entryId);\n\tif (existing) {\n\t\treturn existing;\n\t}\n\n\t// Load from driver\n\tconst value = await driver.get(buildEntryMetadataKey(entryId));\n\tif (value) {\n\t\tconst metadata = deserializeEntryMetadata(value);\n\t\tmetadata.dirty = false;\n\t\tstorage.entryMetadata.set(entryId, metadata);\n\t\treturn metadata;\n\t}\n\n\t// Create new metadata\n\treturn getOrCreateMetadata(storage, entryId);\n}\n\n/**\n * Flush all dirty data to the driver.\n */\nexport async function flush(\n\tstorage: Storage,\n\tdriver: EngineDriver,\n\tonHistoryUpdated?: () => void,\n): Promise<void> {\n\tconst writes: KVWrite[] = [];\n\tlet historyUpdated = false;\n\n\t// Flush only new names (those added since last flush)\n\tfor (\n\t\tlet i = storage.flushedNameCount;\n\t\ti < storage.nameRegistry.length;\n\t\ti++\n\t) {\n\t\tconst name = storage.nameRegistry[i];\n\t\tif (name !== undefined) {\n\t\t\twrites.push({\n\t\t\t\tkey: buildNameKey(i),\n\t\t\t\tvalue: serializeName(name),\n\t\t\t});\n\t\t\thistoryUpdated = true;\n\t\t}\n\t}\n\n\t// Flush dirty entries\n\tfor (const [, entry] of storage.history.entries) {\n\t\tif (entry.dirty) {\n\t\t\twrites.push({\n\t\t\t\tkey: buildHistoryKey(entry.location),\n\t\t\t\tvalue: serializeEntry(entry),\n\t\t\t});\n\t\t\tentry.dirty = false;\n\t\t\thistoryUpdated = true;\n\t\t}\n\t}\n\n\t// Flush dirty metadata\n\tfor (const [id, metadata] of storage.entryMetadata) {\n\t\tif (metadata.dirty) {\n\t\t\twrites.push({\n\t\t\t\tkey: buildEntryMetadataKey(id),\n\t\t\t\tvalue: serializeEntryMetadata(metadata),\n\t\t\t});\n\t\t\tmetadata.dirty = false;\n\t\t\thistoryUpdated = true;\n\t\t}\n\t}\n\n\t// Flush workflow state if changed\n\tif (storage.state !== storage.flushedState) {\n\t\twrites.push({\n\t\t\tkey: buildWorkflowStateKey(),\n\t\t\tvalue: serializeWorkflowState(storage.state),\n\t\t});\n\t}\n\n\t// Flush output if changed\n\tif (\n\t\tstorage.output !== undefined &&\n\t\tstorage.output !== storage.flushedOutput\n\t) {\n\t\twrites.push({\n\t\t\tkey: buildWorkflowOutputKey(),\n\t\t\tvalue: serializeWorkflowOutput(storage.output),\n\t\t});\n\t}\n\n\t// Flush error if changed (compare by message since objects aren't reference-equal)\n\tconst errorChanged =\n\t\tstorage.error !== undefined &&\n\t\t(storage.flushedError === undefined ||\n\t\t\tstorage.error.name !== storage.flushedError.name ||\n\t\t\tstorage.error.message !== storage.flushedError.message);\n\tif (errorChanged) {\n\t\twrites.push({\n\t\t\tkey: buildWorkflowErrorKey(),\n\t\t\tvalue: serializeWorkflowError(storage.error!),\n\t\t});\n\t}\n\n\tif (writes.length > 0) {\n\t\tawait driver.batch(writes);\n\t}\n\n\t// Update flushed tracking after successful write\n\tstorage.flushedNameCount = storage.nameRegistry.length;\n\tstorage.flushedState = storage.state;\n\tstorage.flushedOutput = storage.output;\n\tstorage.flushedError = storage.error;\n\n\tif (historyUpdated && onHistoryUpdated) {\n\t\tonHistoryUpdated();\n\t}\n}\n\n/**\n * Delete entries with a given location prefix (used for loop forgetting).\n * Also cleans up associated metadata from both memory and driver.\n */\nexport async function deleteEntriesWithPrefix(\n\tstorage: Storage,\n\tdriver: EngineDriver,\n\tprefixLocation: Location,\n\tonHistoryUpdated?: () => void,\n): Promise<void> {\n\t// Collect entry IDs for metadata cleanup\n\tconst entryIds: string[] = [];\n\n\t// Collect entries to delete and their IDs\n\tfor (const [key, entry] of storage.history.entries) {\n\t\t// Check if the entry's location starts with the prefix location\n\t\tif (isLocationPrefix(prefixLocation, entry.location)) {\n\t\t\tentryIds.push(entry.id);\n\t\t\tstorage.entryMetadata.delete(entry.id);\n\t\t\tstorage.history.entries.delete(key);\n\t\t}\n\t}\n\n\t// Delete entries from driver using binary prefix\n\tawait driver.deletePrefix(buildHistoryPrefix(prefixLocation));\n\n\t// Delete metadata from driver in parallel\n\tawait Promise.all(\n\t\tentryIds.map((id) => driver.delete(buildEntryMetadataKey(id))),\n\t);\n\n\tif (entryIds.length > 0 && onHistoryUpdated) {\n\t\tonHistoryUpdated();\n\t}\n}\n\n/**\n * Get an entry by location.\n */\nexport function getEntry(\n\tstorage: Storage,\n\tlocation: Location,\n): Entry | undefined {\n\tconst key = locationToKey(storage, location);\n\treturn storage.history.entries.get(key);\n}\n\n/**\n * Set an entry by location.\n */\nexport function setEntry(\n\tstorage: Storage,\n\tlocation: Location,\n\tentry: Entry,\n): void {\n\tconst key = locationToKey(storage, location);\n\tstorage.history.entries.set(key, entry);\n}\n","/**\n * Sleep for a given number of milliseconds.\n */\nexport function sleep(ms: number): Promise<void> {\n\treturn new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nconst TIMEOUT_MAX = 2147483647;\n\nexport type LongTimeoutHandle = { abort: () => void };\n\nexport function setLongTimeout(\n\tlistener: () => void,\n\tafter: number,\n): LongTimeoutHandle {\n\tlet timeout: ReturnType<typeof setTimeout> | undefined;\n\n\tfunction start(remaining: number) {\n\t\tif (remaining <= TIMEOUT_MAX) {\n\t\t\ttimeout = setTimeout(listener, remaining);\n\t\t} else {\n\t\t\ttimeout = setTimeout(() => {\n\t\t\t\tstart(remaining - TIMEOUT_MAX);\n\t\t\t}, TIMEOUT_MAX);\n\t\t}\n\t}\n\n\tstart(after);\n\n\treturn {\n\t\tabort: () => {\n\t\t\tif (timeout !== undefined) clearTimeout(timeout);\n\t\t},\n\t};\n}\n\n/**\n * Safely parse JSON with a meaningful error message.\n */\nexport function safeJsonParse<T>(value: string, context: string): T {\n\ttry {\n\t\treturn JSON.parse(value) as T;\n\t} catch (error) {\n\t\tthrow new Error(\n\t\t\t`Failed to parse ${context}: ${error instanceof Error ? error.message : String(error)}`,\n\t\t);\n\t}\n}\n","import type { Logger } from \"pino\";\nimport type { EngineDriver } from \"./driver.js\";\nimport {\n\tCancelledError,\n\tCriticalError,\n\tEntryInProgressError,\n\tEvictedError,\n\tHistoryDivergedError,\n\tJoinError,\n\tMessageWaitError,\n\tRaceError,\n\tRollbackCheckpointError,\n\tRollbackError,\n\tRollbackStopError,\n\tSleepError,\n\tStepExhaustedError,\n\tStepFailedError,\n} from \"./errors.js\";\nimport {\n\tappendLoopIteration,\n\tappendName,\n\temptyLocation,\n\tlocationToKey,\n\tregisterName,\n} from \"./location.js\";\nimport {\n\tcreateEntry,\n\tdeleteEntriesWithPrefix,\n\tflush,\n\tgetOrCreateMetadata,\n\tloadMetadata,\n\tsetEntry,\n} from \"./storage.js\";\nimport type {\n\tBranchConfig,\n\tBranchOutput,\n\tBranchStatus,\n\tEntry,\n\tEntryKindType,\n\tEntryMetadata,\n\tLocation,\n\tLoopConfig,\n\tLoopIterationResult,\n\tLoopResult,\n\tMessage,\n\tRollbackContextInterface,\n\tStepConfig,\n\tStorage,\n\tWorkflowContextInterface,\n\tWorkflowQueue,\n\tWorkflowQueueMessage,\n\tWorkflowQueueNextBatchOptions,\n\tWorkflowQueueNextOptions,\n\tWorkflowMessageDriver,\n} from \"./types.js\";\nimport { sleep } from \"./utils.js\";\n\n/**\n * Default values for step configuration.\n * These are exported so users can reference them when overriding.\n */\nexport const DEFAULT_MAX_RETRIES = 3;\nexport const DEFAULT_RETRY_BACKOFF_BASE = 100;\nexport const DEFAULT_RETRY_BACKOFF_MAX = 30000;\nexport const DEFAULT_LOOP_COMMIT_INTERVAL = 20;\nexport const DEFAULT_LOOP_HISTORY_EVERY = 20;\nexport const DEFAULT_LOOP_HISTORY_KEEP = 20;\nexport const DEFAULT_STEP_TIMEOUT = 30000; // 30 seconds\n\nconst QUEUE_HISTORY_MESSAGE_MARKER = \"__rivetWorkflowQueueMessage\";\n\n/**\n * Calculate backoff delay with exponential backoff.\n * Uses deterministic calculation (no jitter) for replay consistency.\n */\nfunction calculateBackoff(attempts: number, base: number, max: number): number {\n\t// Exponential backoff without jitter for determinism\n\treturn Math.min(max, base * 2 ** attempts);\n}\n\n/**\n * Error thrown when a step times out.\n */\nexport class StepTimeoutError extends Error {\n\tconstructor(\n\t\tpublic readonly stepName: string,\n\t\tpublic readonly timeoutMs: number,\n\t) {\n\t\tsuper(`Step \"${stepName}\" timed out after ${timeoutMs}ms`);\n\t\tthis.name = \"StepTimeoutError\";\n\t}\n}\n\n/**\n * Internal representation of a rollback handler.\n */\nexport interface RollbackAction<T = unknown> {\n\tentryId: string;\n\tname: string;\n\toutput: T;\n\trollback: (ctx: RollbackContextInterface, output: T) => Promise<void>;\n}\n\n/**\n * Internal implementation of WorkflowContext.\n */\nexport class WorkflowContextImpl implements WorkflowContextInterface {\n\tprivate entryInProgress = false;\n\tprivate abortController: AbortController;\n\tprivate currentLocation: Location;\n\tprivate visitedKeys = new Set<string>();\n\tprivate mode: \"forward\" | \"rollback\";\n\tprivate rollbackActions?: RollbackAction[];\n\tprivate rollbackCheckpointSet: boolean;\n\t/** Track names used in current execution to detect duplicates */\n\tprivate usedNamesInExecution = new Set<string>();\n\tprivate pendingCompletableMessageIds = new Set<string>();\n\tprivate historyNotifier?: () => void;\n\tprivate logger?: Logger;\n\n\tconstructor(\n\t\tpublic readonly workflowId: string,\n\t\tprivate storage: Storage,\n\t\tprivate driver: EngineDriver,\n\t\tprivate messageDriver: WorkflowMessageDriver,\n\t\tlocation: Location = emptyLocation(),\n\t\tabortController?: AbortController,\n\t\tmode: \"forward\" | \"rollback\" = \"forward\",\n\t\trollbackActions?: RollbackAction[],\n\t\trollbackCheckpointSet = false,\n\t\thistoryNotifier?: () => void,\n\t\tlogger?: Logger,\n\t) {\n\t\tthis.currentLocation = location;\n\t\tthis.abortController = abortController ?? new AbortController();\n\t\tthis.mode = mode;\n\t\tthis.rollbackActions = rollbackActions;\n\t\tthis.rollbackCheckpointSet = rollbackCheckpointSet;\n\t\tthis.historyNotifier = historyNotifier;\n\t\tthis.logger = logger;\n\t}\n\n\tget abortSignal(): AbortSignal {\n\t\treturn this.abortController.signal;\n\t}\n\n\tget queue(): WorkflowQueue {\n\t\treturn {\n\t\t\tnext: async (name, opts) => await this.queueNext(name, opts),\n\t\t\tnextBatch: async (name, opts) => await this.queueNextBatch(name, opts),\n\t\t\tsend: async (name, body) => await this.queueSend(name, body),\n\t\t};\n\t}\n\n\tisEvicted(): boolean {\n\t\treturn this.abortSignal.aborted;\n\t}\n\n\tprivate assertNotInProgress(): void {\n\t\tif (this.entryInProgress) {\n\t\t\tthrow new EntryInProgressError();\n\t\t}\n\t}\n\n\tprivate checkEvicted(): void {\n\t\tif (this.abortSignal.aborted) {\n\t\t\tthrow new EvictedError();\n\t\t}\n\t}\n\n\tprivate async flushStorage(): Promise<void> {\n\t\tawait flush(this.storage, this.driver, this.historyNotifier);\n\t}\n\n\t/**\n\t * Create a new branch context for parallel/nested execution.\n\t */\n\tcreateBranch(\n\t\tlocation: Location,\n\t\tabortController?: AbortController,\n\t): WorkflowContextImpl {\n\t\treturn new WorkflowContextImpl(\n\t\t\tthis.workflowId,\n\t\t\tthis.storage,\n\t\t\tthis.driver,\n\t\t\tthis.messageDriver,\n\t\t\tlocation,\n\t\t\tabortController ?? this.abortController,\n\t\t\tthis.mode,\n\t\t\tthis.rollbackActions,\n\t\t\tthis.rollbackCheckpointSet,\n\t\t\tthis.historyNotifier,\n\t\t\tthis.logger,\n\t\t);\n\t}\n\n\t/**\n\t * Log a debug message using the configured logger.\n\t */\n\tprivate log(level: \"debug\" | \"info\" | \"warn\" | \"error\", data: Record<string, unknown>): void {\n\t\tif (!this.logger) return;\n\t\tthis.logger[level](data);\n\t}\n\n\t/**\n\t * Mark a key as visited.\n\t */\n\tprivate markVisited(key: string): void {\n\t\tthis.visitedKeys.add(key);\n\t}\n\n\t/**\n\t * Check if a name has already been used at the current location in this execution.\n\t * Throws HistoryDivergedError if duplicate detected.\n\t */\n\tprivate checkDuplicateName(name: string): void {\n\t\tconst fullKey =\n\t\t\tlocationToKey(this.storage, this.currentLocation) + \"/\" + name;\n\t\t\tif (this.usedNamesInExecution.has(fullKey)) {\n\t\t\t\tthrow new HistoryDivergedError(\n\t\t\t\t\t`Duplicate entry name \"${name}\" at location \"${locationToKey(this.storage, this.currentLocation)}\". ` +\n\t\t\t\t\t\t`Each step/loop/sleep/queue.next/join/race must have a unique name within its scope.`,\n\t\t\t\t);\n\t\t\t}\n\t\tthis.usedNamesInExecution.add(fullKey);\n\t}\n\n\tprivate stopRollback(): never {\n\t\tthrow new RollbackStopError();\n\t}\n\n\tprivate stopRollbackIfMissing(entry: Entry | undefined): void {\n\t\tif (this.mode === \"rollback\" && !entry) {\n\t\t\tthis.stopRollback();\n\t\t}\n\t}\n\n\tprivate stopRollbackIfIncomplete(condition: boolean): void {\n\t\tif (this.mode === \"rollback\" && condition) {\n\t\t\tthis.stopRollback();\n\t\t}\n\t}\n\n\tprivate registerRollbackAction<T>(\n\t\tconfig: StepConfig<T>,\n\t\tentryId: string,\n\t\toutput: T,\n\t\tmetadata: EntryMetadata,\n\t): void {\n\t\tif (!config.rollback) {\n\t\t\treturn;\n\t\t}\n\t\tif (metadata.rollbackCompletedAt !== undefined) {\n\t\t\treturn;\n\t\t}\n\t\tthis.rollbackActions?.push({\n\t\t\tentryId,\n\t\t\tname: config.name,\n\t\t\toutput: output as unknown,\n\t\t\trollback: config.rollback as (\n\t\t\t\tctx: RollbackContextInterface,\n\t\t\t\toutput: unknown,\n\t\t\t) => Promise<void>,\n\t\t});\n\t}\n\n\t/**\n\t * Ensure a rollback checkpoint exists before registering rollback handlers.\n\t */\n\tprivate ensureRollbackCheckpoint<T>(config: StepConfig<T>): void {\n\t\tif (!config.rollback) {\n\t\t\treturn;\n\t\t}\n\t\tif (!this.rollbackCheckpointSet) {\n\t\t\tthrow new RollbackCheckpointError();\n\t\t}\n\t}\n\n\t/**\n\t * Validate that all expected entries in the branch were visited.\n\t * Throws HistoryDivergedError if there are unvisited entries.\n\t */\n\tvalidateComplete(): void {\n\t\tconst prefix = locationToKey(this.storage, this.currentLocation);\n\n\t\tfor (const key of this.storage.history.entries.keys()) {\n\t\t\t// Check if this key is under our current location prefix\n\t\t\t// Handle root prefix (empty string) specially - all keys are under root\n\t\t\tconst isUnderPrefix =\n\t\t\t\tprefix === \"\"\n\t\t\t\t\t? true // Root: all keys are children\n\t\t\t\t\t: key.startsWith(prefix + \"/\") || key === prefix;\n\n\t\t\tif (isUnderPrefix) {\n\t\t\t\tif (!this.visitedKeys.has(key)) {\n\t\t\t\t\t// Entry exists in history but wasn't visited\n\t\t\t\t\t// This means workflow code may have changed\n\t\t\t\t\tthrow new HistoryDivergedError(\n\t\t\t\t\t\t`Entry \"${key}\" exists in history but was not visited. ` +\n\t\t\t\t\t\t\t`Workflow code may have changed. Use ctx.removed() to handle migrations.`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Evict the workflow.\n\t */\n\tevict(): void {\n\t\tthis.abortController.abort(new EvictedError());\n\t}\n\n\t/**\n\t * Wait for eviction message.\n\t *\n\t * The event listener uses { once: true } to auto-remove after firing,\n\t * preventing memory leaks if this method is called multiple times.\n\t */\n\twaitForEviction(): Promise<never> {\n\t\treturn new Promise((_, reject) => {\n\t\t\tif (this.abortSignal.aborted) {\n\t\t\t\treject(new EvictedError());\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis.abortSignal.addEventListener(\n\t\t\t\t\"abort\",\n\t\t\t\t() => {\n\t\t\t\t\treject(new EvictedError());\n\t\t\t\t},\n\t\t\t\t{ once: true },\n\t\t\t);\n\t\t});\n\t}\n\n\t// === Step ===\n\n\tasync step<T>(\n\t\tnameOrConfig: string | StepConfig<T>,\n\t\trun?: () => Promise<T>,\n\t): Promise<T> {\n\t\tthis.assertNotInProgress();\n\t\tthis.checkEvicted();\n\n\t\tconst config: StepConfig<T> =\n\t\t\ttypeof nameOrConfig === \"string\"\n\t\t\t\t? { name: nameOrConfig, run: run! }\n\t\t\t\t: nameOrConfig;\n\n\t\tthis.entryInProgress = true;\n\t\ttry {\n\t\t\treturn await this.executeStep(config);\n\t\t} finally {\n\t\t\tthis.entryInProgress = false;\n\t\t}\n\t}\n\n\tprivate async executeStep<T>(config: StepConfig<T>): Promise<T> {\n\t\tthis.ensureRollbackCheckpoint(config);\n\t\tif (this.mode === \"rollback\") {\n\t\t\treturn await this.executeStepRollback(config);\n\t\t}\n\n\t\t// Check for duplicate name in current execution\n\t\tthis.checkDuplicateName(config.name);\n\n\t\tconst location = appendName(\n\t\t\tthis.storage,\n\t\t\tthis.currentLocation,\n\t\t\tconfig.name,\n\t\t);\n\t\tconst key = locationToKey(this.storage, location);\n\t\tconst existing = this.storage.history.entries.get(key);\n\n\t\t// Mark this entry as visited for validateComplete\n\t\tthis.markVisited(key);\n\n\t\tif (existing) {\n\t\t\tif (existing.kind.type !== \"step\") {\n\t\t\t\tthrow new HistoryDivergedError(\n\t\t\t\t\t`Expected step \"${config.name}\" at ${key}, found ${existing.kind.type}`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst stepData = existing.kind.data;\n\n\t\t\t// Replay successful result\n\t\t\tif (stepData.output !== undefined) {\n\t\t\t\tthis.log(\"debug\", { msg: \"replaying step from history\", step: config.name, key });\n\t\t\t\treturn stepData.output as T;\n\t\t\t}\n\n\t\t\t// Check if we should retry\n\t\t\tconst metadata = await loadMetadata(\n\t\t\t\tthis.storage,\n\t\t\t\tthis.driver,\n\t\t\t\texisting.id,\n\t\t\t);\n\t\t\tconst maxRetries = config.maxRetries ?? DEFAULT_MAX_RETRIES;\n\n\t\t\tif (metadata.attempts >= maxRetries) {\n\t\t\t\t// Prefer step history error, but fall back to metadata since\n\t\t\t\t// driver implementations may persist metadata without the history\n\t\t\t\t// entry error (e.g. partial writes/crashes between attempts).\n\t\t\t\tconst lastError = stepData.error ?? metadata.error;\n\t\t\t\tthrow new StepExhaustedError(config.name, lastError);\n\t\t\t}\n\n\t\t\t// Calculate backoff and yield to scheduler\n\t\t\t// This allows the workflow to be evicted during backoff\n\t\t\tconst backoffDelay = calculateBackoff(\n\t\t\t\tmetadata.attempts,\n\t\t\t\tconfig.retryBackoffBase ?? DEFAULT_RETRY_BACKOFF_BASE,\n\t\t\t\tconfig.retryBackoffMax ?? DEFAULT_RETRY_BACKOFF_MAX,\n\t\t\t);\n\t\t\tconst retryAt = metadata.lastAttemptAt + backoffDelay;\n\t\t\tconst now = Date.now();\n\n\t\t\tif (now < retryAt) {\n\t\t\t\t// Yield to scheduler - will be woken up at retryAt\n\t\t\t\tthrow new SleepError(retryAt);\n\t\t\t}\n\t\t}\n\n\t\t// Execute the step\n\t\tconst entry =\n\t\t\texisting ?? createEntry(location, { type: \"step\", data: {} });\n\t\tif (!existing) {\n\t\t\t// New entry - register name\n\t\t\tthis.log(\"debug\", { msg: \"executing new step\", step: config.name, key });\n\t\t\tconst nameIndex = registerName(this.storage, config.name);\n\t\t\tentry.location = [...location];\n\t\t\tentry.location[entry.location.length - 1] = nameIndex;\n\t\t\tsetEntry(this.storage, location, entry);\n\t\t} else {\n\t\t\tthis.log(\"debug\", { msg: \"retrying step\", step: config.name, key });\n\t\t}\n\n\t\tconst metadata = getOrCreateMetadata(this.storage, entry.id);\n\t\tmetadata.status = \"running\";\n\t\tmetadata.attempts++;\n\t\tmetadata.lastAttemptAt = Date.now();\n\t\tmetadata.dirty = true;\n\n\t\t// Get timeout configuration\n\t\tconst timeout = config.timeout ?? DEFAULT_STEP_TIMEOUT;\n\n\t\ttry {\n\t\t\t// Execute with timeout\n\t\t\tconst output = await this.executeWithTimeout(\n\t\t\t\tconfig.run(),\n\t\t\t\ttimeout,\n\t\t\t\tconfig.name,\n\t\t\t);\n\n\t\t\t\tif (entry.kind.type === \"step\") {\n\t\t\t\t\tentry.kind.data.output = output;\n\t\t\t\t}\n\t\t\t\tentry.dirty = true;\n\t\t\t\tmetadata.status = \"completed\";\n\t\t\t\tmetadata.error = undefined;\n\t\t\t\tmetadata.completedAt = Date.now();\n\n\t\t\t\t// Ephemeral steps don't trigger an immediate flush. This avoids the\n\t\t\t// synchronous write overhead for transient operations. Note that the\n\t\t\t// step's entry is still marked dirty and WILL be persisted on the\n\t\t\t// next flush from a non-ephemeral operation. The purpose of ephemeral\n\t\t\t// is to batch writes, not to avoid persistence entirely.\n\t\t\tif (!config.ephemeral) {\n\t\t\t\tthis.log(\"debug\", { msg: \"flushing step\", step: config.name, key });\n\t\t\t\tawait this.flushStorage();\n\t\t\t}\n\n\t\t\tthis.log(\"debug\", { msg: \"step completed\", step: config.name, key });\n\t\t\treturn output;\n\t\t} catch (error) {\n\t\t\t\t// Timeout errors are treated as critical (no retry)\n\t\t\t\tif (error instanceof StepTimeoutError) {\n\t\t\t\t\tif (entry.kind.type === \"step\") {\n\t\t\t\t\t\tentry.kind.data.error = String(error);\n\t\t\t\t\t}\n\t\t\t\t\tentry.dirty = true;\n\t\t\t\t\tmetadata.status = \"exhausted\";\n\t\t\t\t\tmetadata.error = String(error);\n\t\t\t\t\tawait this.flushStorage();\n\t\t\t\t\tthrow new CriticalError(error.message);\n\t\t\t\t}\n\n\t\t\tif (\n\t\t\t\terror instanceof CriticalError ||\n\t\t\t\terror instanceof RollbackError\n\t\t\t\t) {\n\t\t\t\t\tif (entry.kind.type === \"step\") {\n\t\t\t\t\t\tentry.kind.data.error = String(error);\n\t\t\t\t\t}\n\t\t\t\t\tentry.dirty = true;\n\t\t\t\t\tmetadata.status = \"exhausted\";\n\t\t\t\t\tmetadata.error = String(error);\n\t\t\t\t\tawait this.flushStorage();\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\n\t\t\t\tif (entry.kind.type === \"step\") {\n\t\t\t\t\tentry.kind.data.error = String(error);\n\t\t\t\t}\n\t\t\t\tentry.dirty = true;\n\t\t\t\tmetadata.status = \"failed\";\n\t\t\t\tmetadata.error = String(error);\n\n\t\t\t\tawait this.flushStorage();\n\n\t\t\t\tthrow new StepFailedError(config.name, error, metadata.attempts);\n\t\t}\n\t}\n\n\t/**\n\t * Execute a promise with timeout.\n\t *\n\t * Note: This does NOT cancel the underlying operation. JavaScript Promises\n\t * cannot be cancelled once started. When a timeout occurs:\n\t * - The step is marked as failed with StepTimeoutError\n\t * - The underlying async operation continues running in the background\n\t * - Any side effects from the operation may still occur\n\t *\n\t * For cancellable operations, pass ctx.abortSignal to APIs that support AbortSignal:\n\t *\n\t * return fetch(url, { signal: ctx.abortSignal });\n\n\t * });\n\t *\n\t * Or check ctx.isEvicted() periodically in long-running loops.\n\t */\n\tprivate async executeStepRollback<T>(config: StepConfig<T>): Promise<T> {\n\t\tthis.checkDuplicateName(config.name);\n\t\tthis.ensureRollbackCheckpoint(config);\n\n\t\tconst location = appendName(\n\t\t\tthis.storage,\n\t\t\tthis.currentLocation,\n\t\t\tconfig.name,\n\t\t);\n\t\tconst key = locationToKey(this.storage, location);\n\t\tconst existing = this.storage.history.entries.get(key);\n\n\t\tthis.markVisited(key);\n\n\t\tif (!existing || existing.kind.type !== \"step\") {\n\t\t\tthis.stopRollback();\n\t\t}\n\n\t\tconst metadata = await loadMetadata(\n\t\t\tthis.storage,\n\t\t\tthis.driver,\n\t\t\texisting.id,\n\t\t);\n\t\tif (metadata.status !== \"completed\") {\n\t\t\tthis.stopRollback();\n\t\t}\n\n\t\tconst output = existing.kind.data.output as T;\n\t\tthis.registerRollbackAction(config, existing.id, output, metadata);\n\n\t\treturn output;\n\t}\n\n\tprivate async executeWithTimeout<T>(\n\t\tpromise: Promise<T>,\n\t\ttimeoutMs: number,\n\t\tstepName: string,\n\t): Promise<T> {\n\t\tif (timeoutMs <= 0) {\n\t\t\treturn promise;\n\t\t}\n\n\t\tlet timeoutId: ReturnType<typeof setTimeout> | undefined;\n\t\tconst timeoutPromise = new Promise<never>((_, reject) => {\n\t\t\ttimeoutId = setTimeout(() => {\n\t\t\t\treject(new StepTimeoutError(stepName, timeoutMs));\n\t\t\t}, timeoutMs);\n\t\t});\n\n\t\ttry {\n\t\t\treturn await Promise.race([promise, timeoutPromise]);\n\t\t} finally {\n\t\t\tif (timeoutId !== undefined) {\n\t\t\t\tclearTimeout(timeoutId);\n\t\t\t}\n\t\t}\n\t}\n\n\t// === Loop ===\n\n\tasync loop<S, T>(\n\t\tnameOrConfig: string | LoopConfig<S, T>,\n\t\trun?: (\n\t\t\tctx: WorkflowContextInterface,\n\t\t) => LoopIterationResult<undefined, T>,\n\t): Promise<T> {\n\t\tthis.assertNotInProgress();\n\t\tthis.checkEvicted();\n\n\t\tconst config: LoopConfig<S, T> =\n\t\t\ttypeof nameOrConfig === \"string\"\n\t\t\t\t? { name: nameOrConfig, run: run as LoopConfig<S, T>[\"run\"] }\n\t\t\t\t: nameOrConfig;\n\n\t\tthis.entryInProgress = true;\n\t\ttry {\n\t\t\treturn await this.executeLoop(config);\n\t\t} finally {\n\t\t\tthis.entryInProgress = false;\n\t\t}\n\t}\n\n\tprivate async executeLoop<S, T>(config: LoopConfig<S, T>): Promise<T> {\n\t\t// Check for duplicate name in current execution\n\t\tthis.checkDuplicateName(config.name);\n\n\t\tconst location = appendName(\n\t\t\tthis.storage,\n\t\t\tthis.currentLocation,\n\t\t\tconfig.name,\n\t\t);\n\t\tconst key = locationToKey(this.storage, location);\n\t\tconst existing = this.storage.history.entries.get(key);\n\n\t\t// Mark this entry as visited for validateComplete\n\t\tthis.markVisited(key);\n\n\t\tlet entry: Entry;\n\t\tlet state: S;\n\t\tlet iteration: number;\n\t\tlet rollbackSingleIteration = false;\n\t\tlet rollbackIterationRan = false;\n\t\tlet rollbackOutput: T | undefined;\n\t\tconst rollbackMode = this.mode === \"rollback\";\n\n\t\tif (existing) {\n\t\t\tif (existing.kind.type !== \"loop\") {\n\t\t\t\tthrow new HistoryDivergedError(\n\t\t\t\t\t`Expected loop \"${config.name}\" at ${key}, found ${existing.kind.type}`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst loopData = existing.kind.data;\n\n\t\t\tif (rollbackMode) {\n\t\t\t\tif (loopData.output !== undefined) {\n\t\t\t\t\treturn loopData.output as T;\n\t\t\t\t}\n\t\t\t\trollbackSingleIteration = true;\n\t\t\t\trollbackIterationRan = false;\n\t\t\t\trollbackOutput = undefined;\n\t\t\t}\n\n\t\t\t// Loop already completed\n\t\t\tif (loopData.output !== undefined) {\n\t\t\t\treturn loopData.output as T;\n\t\t\t}\n\n\t\t\t// Resume from saved state\n\t\t\tentry = existing;\n\t\t\tstate = loopData.state as S;\n\t\t\titeration = loopData.iteration;\n\t\t\tif (rollbackMode) {\n\t\t\t\trollbackOutput = loopData.output as T | undefined;\n\t\t\t\trollbackIterationRan = rollbackOutput !== undefined;\n\t\t\t}\n\t\t} else {\n\t\t\tthis.stopRollbackIfIncomplete(true);\n\n\t\t\t// New loop\n\t\t\tstate = config.state as S;\n\t\t\titeration = 0;\n\t\t\tentry = createEntry(location, {\n\t\t\t\ttype: \"loop\",\n\t\t\t\tdata: { state, iteration },\n\t\t\t});\n\t\t\tsetEntry(this.storage, location, entry);\n\t\t}\n\n\t\t// TODO: Add validation for commitInterval (must be > 0)\n\t\tconst commitInterval =\n\t\t\tconfig.commitInterval ?? DEFAULT_LOOP_COMMIT_INTERVAL;\n\t\tconst historyEvery =\n\t\t\tconfig.historyEvery ??\n\t\t\tconfig.commitInterval ??\n\t\t\tDEFAULT_LOOP_HISTORY_EVERY;\n\t\tconst historyKeep =\n\t\t\tconfig.historyKeep ??\n\t\t\tconfig.commitInterval ??\n\t\t\tDEFAULT_LOOP_HISTORY_KEEP;\n\n\t\t// Execute loop iterations\n\t\twhile (true) {\n\t\t\tif (rollbackMode && rollbackSingleIteration) {\n\t\t\t\tif (rollbackIterationRan) {\n\t\t\t\t\treturn rollbackOutput as T;\n\t\t\t\t}\n\t\t\t\tthis.stopRollbackIfIncomplete(true);\n\t\t\t}\n\t\t\tthis.checkEvicted();\n\n\t\t\t// Create branch for this iteration\n\t\t\tconst iterationLocation = appendLoopIteration(\n\t\t\t\tthis.storage,\n\t\t\t\tlocation,\n\t\t\t\tconfig.name,\n\t\t\t\titeration,\n\t\t\t);\n\t\t\tconst branchCtx = this.createBranch(iterationLocation);\n\n\t\t\t// Execute iteration\n\t\t\tconst iterationResult = await config.run(branchCtx, state);\n\t\t\tif (iterationResult === undefined && state !== undefined) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Loop \"${config.name}\" returned undefined for a stateful iteration. Return Loop.continue(state) or Loop.break(value).`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst result =\n\t\t\t\titerationResult === undefined\n\t\t\t\t\t? ({ continue: true, state } as LoopResult<S, T>)\n\t\t\t\t\t: iterationResult;\n\n\t\t\t// Validate branch completed cleanly\n\t\t\tbranchCtx.validateComplete();\n\n\t\t\tif (\"break\" in result && result.break) {\n\t\t\t\t// Loop complete\n\t\t\t\tif (entry.kind.type === \"loop\") {\n\t\t\t\t\tentry.kind.data.output = result.value;\n\t\t\t\t\tentry.kind.data.state = state;\n\t\t\t\t\tentry.kind.data.iteration = iteration;\n\t\t\t\t}\n\t\t\t\tentry.dirty = true;\n\n\t\t\t\tawait this.flushStorage();\n\t\t\t\tawait this.forgetOldIterations(\n\t\t\t\t\tlocation,\n\t\t\t\t\titeration + 1,\n\t\t\t\t\thistoryEvery,\n\t\t\t\t\thistoryKeep,\n\t\t\t\t);\n\n\t\t\t\tif (rollbackMode && rollbackSingleIteration) {\n\t\t\t\t\trollbackOutput = result.value;\n\t\t\t\t\trollbackIterationRan = true;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\treturn result.value;\n\t\t\t}\n\n\t\t\t// Continue with new state\n\t\t\tif (\"continue\" in result && result.continue) {\n\t\t\t\tstate = result.state;\n\t\t\t}\n\t\t\titeration++;\n\n\t\t\t// Periodic commit\n\t\t\tif (iteration % commitInterval === 0) {\n\t\t\t\tif (entry.kind.type === \"loop\") {\n\t\t\t\t\tentry.kind.data.state = state;\n\t\t\t\t\tentry.kind.data.iteration = iteration;\n\t\t\t\t}\n\t\t\t\tentry.dirty = true;\n\n\t\t\t\tawait this.flushStorage();\n\t\t\t\tawait this.forgetOldIterations(\n\t\t\t\t\tlocation,\n\t\t\t\t\titeration,\n\t\t\t\t\thistoryEvery,\n\t\t\t\t\thistoryKeep,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Delete old loop iteration entries to save storage space.\n\t *\n\t * Loop locations always end with a NameIndex (number) because loops are\n\t * created via appendName(). Even for nested loops, the innermost loop's\n\t * location ends with its name index:\n\t *\n\t * ctx.loop(\"outer\") → location: [outerIndex]\n\t * iteration 0 → location: [{ loop: outerIndex, iteration: 0 }]\n\t * ctx.loop(\"inner\") → location: [{ loop: outerIndex, iteration: 0 }, innerIndex]\n\t *\n\t * This function removes iterations older than (currentIteration - historyKeep)\n\t * every historyEvery iterations.\n\t */\n\tprivate async forgetOldIterations(\n\t\tloopLocation: Location,\n\t\tcurrentIteration: number,\n\t\thistoryEvery: number,\n\t\thistoryKeep: number,\n\t): Promise<void> {\n\t\tif (historyEvery <= 0 || historyKeep <= 0) {\n\t\t\treturn;\n\t\t}\n\t\tif (currentIteration === 0 || currentIteration % historyEvery !== 0) {\n\t\t\treturn;\n\t\t}\n\t\tconst keepFrom = Math.max(0, currentIteration - historyKeep);\n\t\t// Get the loop name index from the last segment of loopLocation.\n\t\t// This is always a NameIndex (number) because loop entries are created\n\t\t// via appendName(), not appendLoopIteration().\n\t\tconst loopSegment = loopLocation[loopLocation.length - 1];\n\t\tif (typeof loopSegment !== \"number\") {\n\t\t\tthrow new Error(\"Expected loop location to end with a name index\");\n\t\t}\n\n\t\tfor (let i = 0; i < keepFrom; i++) {\n\t\t\tconst iterationLocation: Location = [\n\t\t\t\t...loopLocation,\n\t\t\t\t{ loop: loopSegment, iteration: i },\n\t\t\t];\n\t\t\tawait deleteEntriesWithPrefix(\n\t\t\t\tthis.storage,\n\t\t\t\tthis.driver,\n\t\t\t\titerationLocation,\n\t\t\t\tthis.historyNotifier,\n\t\t\t);\n\t\t}\n\t}\n\n\t// === Sleep ===\n\n\tasync sleep(name: string, durationMs: number): Promise<void> {\n\t\tconst deadline = Date.now() + durationMs;\n\t\treturn this.sleepUntil(name, deadline);\n\t}\n\n\tasync sleepUntil(name: string, timestampMs: number): Promise<void> {\n\t\tthis.assertNotInProgress();\n\t\tthis.checkEvicted();\n\n\t\tthis.entryInProgress = true;\n\t\ttry {\n\t\t\tawait this.executeSleep(name, timestampMs);\n\t\t} finally {\n\t\t\tthis.entryInProgress = false;\n\t\t}\n\t}\n\n\tprivate async executeSleep(name: string, deadline: number): Promise<void> {\n\t\t// Check for duplicate name in current execution\n\t\tthis.checkDuplicateName(name);\n\n\t\tconst location = appendName(this.storage, this.currentLocation, name);\n\t\tconst key = locationToKey(this.storage, location);\n\t\tconst existing = this.storage.history.entries.get(key);\n\n\t\t// Mark this entry as visited for validateComplete\n\t\tthis.markVisited(key);\n\n\t\tlet entry: Entry;\n\n\t\tif (existing) {\n\t\t\tif (existing.kind.type !== \"sleep\") {\n\t\t\t\tthrow new HistoryDivergedError(\n\t\t\t\t\t`Expected sleep \"${name}\" at ${key}, found ${existing.kind.type}`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst sleepData = existing.kind.data;\n\n\t\t\tif (this.mode === \"rollback\") {\n\t\t\t\tthis.stopRollbackIfIncomplete(sleepData.state === \"pending\");\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Already completed or interrupted\n\t\t\tif (sleepData.state !== \"pending\") {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Use stored deadline\n\t\t\tdeadline = sleepData.deadline;\n\t\t\tentry = existing;\n\t\t} else {\n\t\t\tthis.stopRollbackIfIncomplete(true);\n\n\t\t\tentry = createEntry(location, {\n\t\t\t\ttype: \"sleep\",\n\t\t\t\tdata: { deadline, state: \"pending\" },\n\t\t\t});\n\t\t\tsetEntry(this.storage, location, entry);\n\t\t\tentry.dirty = true;\n\t\t\tawait this.flushStorage();\n\t\t}\n\n\t\tconst now = Date.now();\n\t\tconst remaining = deadline - now;\n\n\t\tif (remaining <= 0) {\n\t\t\t// Deadline passed\n\t\t\tif (entry.kind.type === \"sleep\") {\n\t\t\t\tentry.kind.data.state = \"completed\";\n\t\t\t}\n\t\t\tentry.dirty = true;\n\t\t\tawait this.flushStorage();\n\t\t\treturn;\n\t\t}\n\n\t\t// Short sleep: wait in memory\n\t\tif (remaining < this.driver.workerPollInterval) {\n\t\t\tawait Promise.race([sleep(remaining), this.waitForEviction()]);\n\n\t\t\tthis.checkEvicted();\n\n\t\t\tif (entry.kind.type === \"sleep\") {\n\t\t\t\tentry.kind.data.state = \"completed\";\n\t\t\t}\n\t\t\tentry.dirty = true;\n\t\t\tawait this.flushStorage();\n\t\t\treturn;\n\t\t}\n\n\t\t// Long sleep: yield to scheduler\n\t\tthrow new SleepError(deadline);\n\t}\n\n\t// === Rollback Checkpoint ===\n\n\tasync rollbackCheckpoint(name: string): Promise<void> {\n\t\tthis.assertNotInProgress();\n\t\tthis.checkEvicted();\n\n\t\tthis.entryInProgress = true;\n\t\ttry {\n\t\t\tawait this.executeRollbackCheckpoint(name);\n\t\t} finally {\n\t\t\tthis.entryInProgress = false;\n\t\t}\n\t}\n\n\tprivate async executeRollbackCheckpoint(name: string): Promise<void> {\n\t\tthis.checkDuplicateName(name);\n\n\t\tconst location = appendName(this.storage, this.currentLocation, name);\n\t\tconst key = locationToKey(this.storage, location);\n\t\tconst existing = this.storage.history.entries.get(key);\n\n\t\tthis.markVisited(key);\n\n\t\tif (existing) {\n\t\t\tif (existing.kind.type !== \"rollback_checkpoint\") {\n\t\t\t\tthrow new HistoryDivergedError(\n\t\t\t\t\t`Expected rollback checkpoint \"${name}\" at ${key}, found ${existing.kind.type}`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tthis.rollbackCheckpointSet = true;\n\t\t\treturn;\n\t\t}\n\n\t\tif (this.mode === \"rollback\") {\n\t\t\tthrow new HistoryDivergedError(\n\t\t\t\t`Missing rollback checkpoint \"${name}\" at ${key}`,\n\t\t\t);\n\t\t}\n\n\t\tconst entry = createEntry(location, {\n\t\t\ttype: \"rollback_checkpoint\",\n\t\t\tdata: { name },\n\t\t});\n\t\tsetEntry(this.storage, location, entry);\n\t\tentry.dirty = true;\n\t\tawait this.flushStorage();\n\n\t\tthis.rollbackCheckpointSet = true;\n\t}\n\n\t// === Queue ===\n\n\tprivate async queueSend(name: string, body: unknown): Promise<void> {\n\t\tconst message: Message = {\n\t\t\tid: crypto.randomUUID(),\n\t\t\tname,\n\t\t\tdata: body,\n\t\t\tsentAt: Date.now(),\n\t\t};\n\t\tawait this.messageDriver.addMessage(message);\n\t}\n\n\tprivate async queueNext<T>(\n\t\tname: string,\n\t\topts?: WorkflowQueueNextOptions,\n\t): Promise<WorkflowQueueMessage<T>> {\n\t\tconst messages = await this.queueNextBatch<T>(name, {\n\t\t\t...(opts ?? {}),\n\t\t\tcount: 1,\n\t\t});\n\t\tconst message = messages[0];\n\t\tif (!message) {\n\t\t\tthrow new Error(\n\t\t\t\t`queue.next(\"${name}\") timed out before receiving a message. Use queue.nextBatch(...) for optional/time-limited reads.`,\n\t\t\t);\n\t\t}\n\t\treturn message;\n\t}\n\n\tprivate async queueNextBatch<T>(\n\t\tname: string,\n\t\topts?: WorkflowQueueNextBatchOptions,\n\t): Promise<Array<WorkflowQueueMessage<T>>> {\n\t\tthis.assertNotInProgress();\n\t\tthis.checkEvicted();\n\n\t\tthis.entryInProgress = true;\n\t\ttry {\n\t\t\treturn await this.executeQueueNextBatch<T>(name, opts);\n\t\t} finally {\n\t\t\tthis.entryInProgress = false;\n\t\t}\n\t}\n\n\tprivate async executeQueueNextBatch<T>(\n\t\tname: string,\n\t\topts?: WorkflowQueueNextBatchOptions,\n\t): Promise<Array<WorkflowQueueMessage<T>>> {\n\t\tif (this.pendingCompletableMessageIds.size > 0) {\n\t\t\tthrow new Error(\n\t\t\t\t\"Previous completable queue message is not completed. Call `message.complete(...)` before receiving the next message.\",\n\t\t\t);\n\t\t}\n\n\t\tconst resolvedOpts = opts ?? {};\n\t\tconst messageNames = this.normalizeQueueNames(resolvedOpts.names);\n\t\tconst messageNameLabel = this.messageNamesLabel(messageNames);\n\t\tconst count = Math.max(1, resolvedOpts.count ?? 1);\n\t\tconst completable = resolvedOpts.completable === true;\n\n\t\tthis.checkDuplicateName(name);\n\n\t\tconst countLocation = appendName(\n\t\t\tthis.storage,\n\t\t\tthis.currentLocation,\n\t\t\t`${name}:count`,\n\t\t);\n\t\tconst countKey = locationToKey(this.storage, countLocation);\n\t\tconst existingCount = this.storage.history.entries.get(countKey);\n\t\tthis.markVisited(countKey);\n\t\tthis.stopRollbackIfMissing(existingCount);\n\n\t\tlet deadline: number | undefined;\n\t\tlet deadlineEntry: Entry | undefined;\n\t\tif (resolvedOpts.timeout !== undefined) {\n\t\t\tconst deadlineLocation = appendName(\n\t\t\t\tthis.storage,\n\t\t\t\tthis.currentLocation,\n\t\t\t\t`${name}:deadline`,\n\t\t\t);\n\t\t\tconst deadlineKey = locationToKey(this.storage, deadlineLocation);\n\t\t\tdeadlineEntry = this.storage.history.entries.get(deadlineKey);\n\t\t\tthis.markVisited(deadlineKey);\n\t\t\tthis.stopRollbackIfMissing(deadlineEntry);\n\n\t\t\tif (deadlineEntry && deadlineEntry.kind.type === \"sleep\") {\n\t\t\t\tdeadline = deadlineEntry.kind.data.deadline;\n\t\t\t} else {\n\t\t\t\tdeadline = Date.now() + resolvedOpts.timeout;\n\t\t\t\tconst created = createEntry(deadlineLocation, {\n\t\t\t\t\ttype: \"sleep\",\n\t\t\t\t\tdata: { deadline, state: \"pending\" },\n\t\t\t\t});\n\t\t\t\tsetEntry(this.storage, deadlineLocation, created);\n\t\t\t\tcreated.dirty = true;\n\t\t\t\tawait this.flushStorage();\n\t\t\t\tdeadlineEntry = created;\n\t\t\t}\n\t\t}\n\n\t\tif (existingCount && existingCount.kind.type === \"message\") {\n\t\t\tconst replayCount = existingCount.kind.data.data as number;\n\t\t\treturn await this.readReplayQueueMessages<T>(\n\t\t\t\tname,\n\t\t\t\treplayCount,\n\t\t\t\tcompletable,\n\t\t\t);\n\t\t}\n\n\t\tconst now = Date.now();\n\t\tif (deadline !== undefined && now >= deadline) {\n\t\t\tif (deadlineEntry && deadlineEntry.kind.type === \"sleep\") {\n\t\t\t\tdeadlineEntry.kind.data.state = \"completed\";\n\t\t\t\tdeadlineEntry.dirty = true;\n\t\t\t}\n\t\t\tawait this.recordQueueCountEntry(\n\t\t\t\tcountLocation,\n\t\t\t\t`${messageNameLabel}:count`,\n\t\t\t\t0,\n\t\t\t);\n\t\t\treturn [];\n\t\t}\n\n\t\tconst received = await this.receiveMessagesNow(\n\t\t\tmessageNames,\n\t\t\tcount,\n\t\t\tcompletable,\n\t\t);\n\t\tif (received.length > 0) {\n\t\t\tconst historyMessages = received.map((message) =>\n\t\t\t\tthis.toWorkflowQueueMessage<T>(message),\n\t\t\t);\n\t\t\tif (deadlineEntry && deadlineEntry.kind.type === \"sleep\") {\n\t\t\t\tdeadlineEntry.kind.data.state = \"interrupted\";\n\t\t\t\tdeadlineEntry.dirty = true;\n\t\t\t}\n\t\t\tawait this.recordQueueMessages(\n\t\t\t\tname,\n\t\t\t\tcountLocation,\n\t\t\t\tmessageNames,\n\t\t\t\thistoryMessages,\n\t\t\t);\n\t\t\tconst queueMessages = received.map((message, index) =>\n\t\t\t\tthis.createQueueMessage<T>(message, completable, {\n\t\t\t\t\thistoryLocation: appendName(\n\t\t\t\t\t\tthis.storage,\n\t\t\t\t\t\tthis.currentLocation,\n\t\t\t\t\t\t`${name}:${index}`,\n\t\t\t\t\t),\n\t\t\t\t}),\n\t\t\t);\n\t\t\treturn queueMessages;\n\t\t}\n\n\t\tif (deadline === undefined) {\n\t\t\tthrow new MessageWaitError(messageNames);\n\t\t}\n\t\tthrow new SleepError(deadline, messageNames);\n\t}\n\n\tprivate normalizeQueueNames(names?: readonly string[]): string[] {\n\t\tif (!names || names.length === 0) {\n\t\t\treturn [];\n\t\t}\n\t\tconst deduped: string[] = [];\n\t\tconst seen = new Set<string>();\n\t\tfor (const name of names) {\n\t\t\tif (seen.has(name)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tseen.add(name);\n\t\t\tdeduped.push(name);\n\t\t}\n\t\treturn deduped;\n\t}\n\n\tprivate messageNamesLabel(messageNames: string[]): string {\n\t\tif (messageNames.length === 0) {\n\t\t\treturn \"*\";\n\t\t}\n\t\treturn messageNames.length === 1\n\t\t\t? messageNames[0]\n\t\t\t: messageNames.join(\"|\");\n\t}\n\n\tprivate async receiveMessagesNow(\n\t\tmessageNames: string[],\n\t\tcount: number,\n\t\tcompletable: boolean,\n\t): Promise<Message[]> {\n\t\treturn await this.messageDriver.receiveMessages({\n\t\t\tnames: messageNames.length > 0 ? messageNames : undefined,\n\t\t\tcount,\n\t\t\tcompletable,\n\t\t});\n\t}\n\n\tprivate async recordQueueMessages<T>(\n\t\tname: string,\n\t\tcountLocation: Location,\n\t\tmessageNames: string[],\n\t\tmessages: Array<WorkflowQueueMessage<T>>,\n\t): Promise<void> {\n\t\tfor (let i = 0; i < messages.length; i++) {\n\t\t\tconst messageLocation = appendName(\n\t\t\t\tthis.storage,\n\t\t\t\tthis.currentLocation,\n\t\t\t\t`${name}:${i}`,\n\t\t\t);\n\t\t\tconst messageEntry = createEntry(messageLocation, {\n\t\t\t\ttype: \"message\",\n\t\t\t\tdata: {\n\t\t\t\t\tname: messages[i].name,\n\t\t\t\t\tdata: this.toHistoryQueueMessage(messages[i]),\n\t\t\t\t},\n\t\t\t});\n\t\t\tsetEntry(this.storage, messageLocation, messageEntry);\n\t\t\tthis.markVisited(locationToKey(this.storage, messageLocation));\n\t\t}\n\t\tawait this.recordQueueCountEntry(\n\t\t\tcountLocation,\n\t\t\t`${this.messageNamesLabel(messageNames)}:count`,\n\t\t\tmessages.length,\n\t\t);\n\t}\n\n\tprivate async recordQueueCountEntry(\n\t\tcountLocation: Location,\n\t\tcountLabel: string,\n\t\tcount: number,\n\t): Promise<void> {\n\t\tconst countEntry = createEntry(countLocation, {\n\t\t\ttype: \"message\",\n\t\t\tdata: {\n\t\t\t\tname: countLabel,\n\t\t\t\tdata: count,\n\t\t\t},\n\t\t});\n\t\tsetEntry(this.storage, countLocation, countEntry);\n\t\tawait this.flushStorage();\n\t}\n\n\tprivate async readReplayQueueMessages<T>(\n\t\tname: string,\n\t\tcount: number,\n\t\tcompletable: boolean,\n\t): Promise<Array<WorkflowQueueMessage<T>>> {\n\t\tconst results: Array<WorkflowQueueMessage<T>> = [];\n\t\tfor (let i = 0; i < count; i++) {\n\t\t\tconst messageLocation = appendName(\n\t\t\t\tthis.storage,\n\t\t\t\tthis.currentLocation,\n\t\t\t\t`${name}:${i}`,\n\t\t\t);\n\t\t\tconst messageKey = locationToKey(this.storage, messageLocation);\n\t\t\tthis.markVisited(messageKey);\n\t\t\tconst existingMessage = this.storage.history.entries.get(messageKey);\n\t\t\tif (!existingMessage || existingMessage.kind.type !== \"message\") {\n\t\t\t\tthrow new HistoryDivergedError(\n\t\t\t\t\t`Expected queue message \"${name}:${i}\" in history`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst parsed = this.fromHistoryQueueMessage(\n\t\t\t\texistingMessage.kind.data.name,\n\t\t\t\texistingMessage.kind.data.data,\n\t\t\t);\n\t\t\tresults.push(\n\t\t\t\tthis.createQueueMessage<T>(parsed.message, completable, {\n\t\t\t\t\thistoryLocation: messageLocation,\n\t\t\t\t\tcompleted: parsed.completed,\n\t\t\t\t\treplay: true,\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\t\treturn results;\n\t}\n\n\tprivate toWorkflowQueueMessage<T>(message: Message): WorkflowQueueMessage<T> {\n\t\treturn {\n\t\t\tid: message.id,\n\t\t\tname: message.name,\n\t\t\tbody: message.data as T,\n\t\t\tcreatedAt: message.sentAt,\n\t\t};\n\t}\n\n\tprivate createQueueMessage<T>(\n\t\tmessage: Message,\n\t\tcompletable: boolean,\n\t\topts?: {\n\t\t\thistoryLocation?: Location;\n\t\t\tcompleted?: boolean;\n\t\t\treplay?: boolean;\n\t\t},\n\t): WorkflowQueueMessage<T> {\n\t\tconst queueMessage = this.toWorkflowQueueMessage<T>(message);\n\t\tif (!completable) {\n\t\t\treturn queueMessage;\n\t\t}\n\n\t\tif (opts?.replay && opts.completed) {\n\t\t\treturn {\n\t\t\t\t...queueMessage,\n\t\t\t\tcomplete: async () => {\n\t\t\t\t\t// No-op: this message was already completed in a prior run.\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\n\t\tconst messageId = message.id;\n\t\tthis.pendingCompletableMessageIds.add(messageId);\n\t\tlet completed = false;\n\n\t\treturn {\n\t\t\t...queueMessage,\n\t\t\tcomplete: async (response?: unknown) => {\n\t\t\t\tif (completed) {\n\t\t\t\t\tthrow new Error(\"Queue message already completed\");\n\t\t\t\t}\n\t\t\t\tcompleted = true;\n\t\t\t\ttry {\n\t\t\t\t\tawait this.completeMessage(message, response);\n\t\t\t\t\tawait this.markQueueMessageCompleted(opts?.historyLocation);\n\t\t\t\t\tthis.pendingCompletableMessageIds.delete(messageId);\n\t\t\t\t} catch (error) {\n\t\t\t\t\tcompleted = false;\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t},\n\t\t};\n\t}\n\n\tprivate async markQueueMessageCompleted(\n\t\thistoryLocation: Location | undefined,\n\t): Promise<void> {\n\t\tif (!historyLocation) {\n\t\t\treturn;\n\t\t}\n\t\tconst key = locationToKey(this.storage, historyLocation);\n\t\tconst entry = this.storage.history.entries.get(key);\n\t\tif (!entry || entry.kind.type !== \"message\") {\n\t\t\treturn;\n\t\t}\n\t\tconst parsed = this.fromHistoryQueueMessage(\n\t\t\tentry.kind.data.name,\n\t\t\tentry.kind.data.data,\n\t\t);\n\t\tentry.kind.data.data = this.toHistoryQueueMessage(\n\t\t\tthis.toWorkflowQueueMessage(parsed.message),\n\t\t\ttrue,\n\t\t);\n\t\tentry.dirty = true;\n\t\tawait this.flushStorage();\n\t}\n\n\tprivate async completeMessage(\n\t\tmessage: Message,\n\t\tresponse?: unknown,\n\t): Promise<void> {\n\t\tif (message.complete) {\n\t\t\tawait message.complete(response);\n\t\t\treturn;\n\t\t}\n\t\tawait this.messageDriver.completeMessage(message.id, response);\n\t}\n\n\tprivate toHistoryQueueMessage(\n\t\tmessage: WorkflowQueueMessage<unknown>,\n\t\tcompleted = false,\n\t): unknown {\n\t\treturn {\n\t\t\t[QUEUE_HISTORY_MESSAGE_MARKER]: 1,\n\t\t\tid: message.id,\n\t\t\tname: message.name,\n\t\t\tbody: message.body,\n\t\t\tcreatedAt: message.createdAt,\n\t\t\tcompleted,\n\t\t};\n\t}\n\n\tprivate fromHistoryQueueMessage(\n\t\tname: string,\n\t\tvalue: unknown,\n\t): { message: Message; completed: boolean } {\n\t\tif (\n\t\t\ttypeof value === \"object\" &&\n\t\t\tvalue !== null &&\n\t\t\t(value as Record<string, unknown>)[QUEUE_HISTORY_MESSAGE_MARKER] === 1\n\t\t) {\n\t\t\tconst serialized = value as Record<string, unknown>;\n\t\t\tconst id =\n\t\t\t\ttypeof serialized.id === \"string\" ? serialized.id : \"\";\n\t\t\tconst serializedName =\n\t\t\t\ttypeof serialized.name === \"string\" ? serialized.name : name;\n\t\t\tconst createdAt =\n\t\t\t\ttypeof serialized.createdAt === \"number\" ? serialized.createdAt : 0;\n\t\t\tconst completed =\n\t\t\t\ttypeof serialized.completed === \"boolean\"\n\t\t\t\t\t? serialized.completed\n\t\t\t\t\t: false;\n\t\t\treturn {\n\t\t\t\tmessage: {\n\t\t\t\t\tid,\n\t\t\t\t\tname: serializedName,\n\t\t\t\t\tdata: serialized.body,\n\t\t\t\t\tsentAt: createdAt,\n\t\t\t\t},\n\t\t\t\tcompleted,\n\t\t\t};\n\t\t}\n\t\treturn {\n\t\t\tmessage: {\n\t\t\t\tid: \"\",\n\t\t\t\tname,\n\t\t\t\tdata: value,\n\t\t\t\tsentAt: 0,\n\t\t\t},\n\t\t\tcompleted: false,\n\t\t};\n\t}\n\n\t// === Join ===\n\n\tasync join<T extends Record<string, BranchConfig<unknown>>>(\n\t\tname: string,\n\t\tbranches: T,\n\t): Promise<{ [K in keyof T]: BranchOutput<T[K]> }> {\n\t\tthis.assertNotInProgress();\n\t\tthis.checkEvicted();\n\n\t\tthis.entryInProgress = true;\n\t\ttry {\n\t\t\treturn await this.executeJoin(name, branches);\n\t\t} finally {\n\t\t\tthis.entryInProgress = false;\n\t\t}\n\t}\n\n\tprivate async executeJoin<T extends Record<string, BranchConfig<unknown>>>(\n\t\tname: string,\n\t\tbranches: T,\n\t): Promise<{ [K in keyof T]: BranchOutput<T[K]> }> {\n\t\t// Check for duplicate name in current execution\n\t\tthis.checkDuplicateName(name);\n\n\t\tconst location = appendName(this.storage, this.currentLocation, name);\n\t\tconst key = locationToKey(this.storage, location);\n\t\tconst existing = this.storage.history.entries.get(key);\n\n\t\t// Mark this entry as visited for validateComplete\n\t\tthis.markVisited(key);\n\n\t\tthis.stopRollbackIfMissing(existing);\n\n\t\tlet entry: Entry;\n\n\t\tif (existing) {\n\t\t\tif (existing.kind.type !== \"join\") {\n\t\t\t\tthrow new HistoryDivergedError(\n\t\t\t\t\t`Expected join \"${name}\" at ${key}, found ${existing.kind.type}`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tentry = existing;\n\t\t} else {\n\t\t\tentry = createEntry(location, {\n\t\t\t\ttype: \"join\",\n\t\t\t\tdata: {\n\t\t\t\t\tbranches: Object.fromEntries(\n\t\t\t\t\t\tObject.keys(branches).map((k) => [\n\t\t\t\t\t\t\tk,\n\t\t\t\t\t\t\t{ status: \"pending\" as const },\n\t\t\t\t\t\t]),\n\t\t\t\t\t),\n\t\t\t\t},\n\t\t\t});\n\t\t\tsetEntry(this.storage, location, entry);\n\t\t\tentry.dirty = true;\n\t\t\t// Flush immediately to persist entry before branches execute\n\t\t\tawait this.flushStorage();\n\t\t}\n\n\t\tif (entry.kind.type !== \"join\") {\n\t\t\tthrow new HistoryDivergedError(\"Entry type mismatch\");\n\t\t}\n\n\t\tthis.stopRollbackIfIncomplete(\n\t\t\tObject.values(entry.kind.data.branches).some(\n\t\t\t\t(branch) => branch.status !== \"completed\",\n\t\t\t),\n\t\t);\n\n\t\tconst joinData = entry.kind.data;\n\t\tconst results: Record<string, unknown> = {};\n\t\tconst errors: Record<string, Error> = {};\n\n\t\t// Execute all branches in parallel\n\t\tconst branchPromises = Object.entries(branches).map(\n\t\t\tasync ([branchName, config]) => {\n\t\t\t\tconst branchStatus = joinData.branches[branchName];\n\n\t\t\t\t// Already completed\n\t\t\t\tif (branchStatus.status === \"completed\") {\n\t\t\t\t\tresults[branchName] = branchStatus.output;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// Already failed\n\t\t\t\tif (branchStatus.status === \"failed\") {\n\t\t\t\t\terrors[branchName] = new Error(branchStatus.error);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// Execute branch\n\t\t\t\tconst branchLocation = appendName(\n\t\t\t\t\tthis.storage,\n\t\t\t\t\tlocation,\n\t\t\t\t\tbranchName,\n\t\t\t\t);\n\t\t\t\tconst branchCtx = this.createBranch(branchLocation);\n\n\t\t\t\tbranchStatus.status = \"running\";\n\t\t\t\tentry.dirty = true;\n\n\t\t\t\ttry {\n\t\t\t\t\tconst output = await config.run(branchCtx);\n\t\t\t\t\tbranchCtx.validateComplete();\n\n\t\t\t\t\tbranchStatus.status = \"completed\";\n\t\t\t\t\tbranchStatus.output = output;\n\t\t\t\t\tresults[branchName] = output;\n\t\t\t\t} catch (error) {\n\t\t\t\t\tbranchStatus.status = \"failed\";\n\t\t\t\t\tbranchStatus.error = String(error);\n\t\t\t\t\terrors[branchName] = error as Error;\n\t\t\t\t}\n\n\t\t\t\tentry.dirty = true;\n\t\t\t},\n\t\t);\n\n\t\t// Wait for ALL branches (no short-circuit on error)\n\t\tawait Promise.allSettled(branchPromises);\n\t\tawait this.flushStorage();\n\n\t\t// Throw if any branches failed\n\t\tif (Object.keys(errors).length > 0) {\n\t\t\tthrow new JoinError(errors);\n\t\t}\n\n\t\treturn results as { [K in keyof T]: BranchOutput<T[K]> };\n\t}\n\n\t// === Race ===\n\n\tasync race<T>(\n\t\tname: string,\n\t\tbranches: Array<{\n\t\t\tname: string;\n\t\t\trun: (ctx: WorkflowContextInterface) => Promise<T>;\n\t\t}>,\n\t): Promise<{ winner: string; value: T }> {\n\t\tthis.assertNotInProgress();\n\t\tthis.checkEvicted();\n\n\t\tthis.entryInProgress = true;\n\t\ttry {\n\t\t\treturn await this.executeRace(name, branches);\n\t\t} finally {\n\t\t\tthis.entryInProgress = false;\n\t\t}\n\t}\n\n\tprivate async executeRace<T>(\n\t\tname: string,\n\t\tbranches: Array<{\n\t\t\tname: string;\n\t\t\trun: (ctx: WorkflowContextInterface) => Promise<T>;\n\t\t}>,\n\t): Promise<{ winner: string; value: T }> {\n\t\t// Check for duplicate name in current execution\n\t\tthis.checkDuplicateName(name);\n\n\t\tconst location = appendName(this.storage, this.currentLocation, name);\n\t\tconst key = locationToKey(this.storage, location);\n\t\tconst existing = this.storage.history.entries.get(key);\n\n\t\t// Mark this entry as visited for validateComplete\n\t\tthis.markVisited(key);\n\n\t\tthis.stopRollbackIfMissing(existing);\n\n\t\tlet entry: Entry;\n\n\t\tif (existing) {\n\t\t\tif (existing.kind.type !== \"race\") {\n\t\t\t\tthrow new HistoryDivergedError(\n\t\t\t\t\t`Expected race \"${name}\" at ${key}, found ${existing.kind.type}`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tentry = existing;\n\n\t\t\t// Check if we already have a winner\n\t\t\tconst raceKind = existing.kind;\n\t\t\tif (raceKind.data.winner !== null) {\n\t\t\t\tconst winnerStatus =\n\t\t\t\t\traceKind.data.branches[raceKind.data.winner];\n\t\t\t\treturn {\n\t\t\t\t\twinner: raceKind.data.winner,\n\t\t\t\t\tvalue: winnerStatus.output as T,\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tthis.stopRollbackIfIncomplete(true);\n\t\t} else {\n\t\t\tentry = createEntry(location, {\n\t\t\t\ttype: \"race\",\n\t\t\t\tdata: {\n\t\t\t\t\twinner: null,\n\t\t\t\t\tbranches: Object.fromEntries(\n\t\t\t\t\t\tbranches.map((b) => [\n\t\t\t\t\t\t\tb.name,\n\t\t\t\t\t\t\t{ status: \"pending\" as const },\n\t\t\t\t\t\t]),\n\t\t\t\t\t),\n\t\t\t\t},\n\t\t\t});\n\t\t\tsetEntry(this.storage, location, entry);\n\t\t\tentry.dirty = true;\n\t\t\t// Flush immediately to persist entry before branches execute\n\t\t\tawait this.flushStorage();\n\t\t}\n\n\t\tif (entry.kind.type !== \"race\") {\n\t\t\tthrow new HistoryDivergedError(\"Entry type mismatch\");\n\t\t}\n\n\t\tconst raceData = entry.kind.data;\n\n\t\t// Create abort controller for cancellation\n\t\tconst raceAbortController = new AbortController();\n\n\t\t// Track all branch promises to wait for cleanup\n\t\tconst branchPromises: Promise<void>[] = [];\n\n\t\t// Track winner info\n\t\tlet winnerName: string | null = null;\n\t\tlet winnerValue: T | null = null;\n\t\tlet settled = false;\n\t\tlet pendingCount = branches.length;\n\t\tconst errors: Record<string, Error> = {};\n\t\tconst lateErrors: Array<{ name: string; error: string }> = [];\n\t\t// Track scheduler yield errors - we need to propagate these after allSettled\n\t\tlet yieldError: SleepError | MessageWaitError | null = null;\n\n\t\t// Check for replay winners first\n\t\tfor (const branch of branches) {\n\t\t\tconst branchStatus = raceData.branches[branch.name];\n\t\t\tif (\n\t\t\t\tbranchStatus.status !== \"pending\" &&\n\t\t\t\tbranchStatus.status !== \"running\"\n\t\t\t) {\n\t\t\t\tpendingCount--;\n\t\t\t\tif (branchStatus.status === \"completed\" && !settled) {\n\t\t\t\t\tsettled = true;\n\t\t\t\t\twinnerName = branch.name;\n\t\t\t\t\twinnerValue = branchStatus.output as T;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// If we found a replay winner, return immediately\n\t\tif (settled && winnerName !== null && winnerValue !== null) {\n\t\t\treturn { winner: winnerName, value: winnerValue };\n\t\t}\n\n\t\t// Execute branches that need to run\n\t\tfor (const branch of branches) {\n\t\t\tconst branchStatus = raceData.branches[branch.name];\n\n\t\t\t// Skip already completed/cancelled\n\t\t\tif (\n\t\t\t\tbranchStatus.status !== \"pending\" &&\n\t\t\t\tbranchStatus.status !== \"running\"\n\t\t\t) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst branchLocation = appendName(\n\t\t\t\tthis.storage,\n\t\t\t\tlocation,\n\t\t\t\tbranch.name,\n\t\t\t);\n\t\t\tconst branchCtx = this.createBranch(\n\t\t\t\tbranchLocation,\n\t\t\t\traceAbortController,\n\t\t\t);\n\n\t\t\tbranchStatus.status = \"running\";\n\t\t\tentry.dirty = true;\n\n\t\t\tconst branchPromise = branch.run(branchCtx).then(\n\t\t\t\tasync (output) => {\n\t\t\t\t\tif (settled) {\n\t\t\t\t\t\t// This branch completed after a winner was determined\n\t\t\t\t\t\t// Still record the completion for observability\n\t\t\t\t\t\tbranchStatus.status = \"completed\";\n\t\t\t\t\t\tbranchStatus.output = output;\n\t\t\t\t\t\tentry.dirty = true;\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tsettled = true;\n\t\t\t\t\twinnerName = branch.name;\n\t\t\t\t\twinnerValue = output;\n\n\t\t\t\t\tbranchCtx.validateComplete();\n\n\t\t\t\t\tbranchStatus.status = \"completed\";\n\t\t\t\t\tbranchStatus.output = output;\n\t\t\t\t\traceData.winner = branch.name;\n\t\t\t\t\tentry.dirty = true;\n\n\t\t\t\t\t// Cancel other branches\n\t\t\t\t\traceAbortController.abort();\n\t\t\t\t},\n\t\t\t\t(error) => {\n\t\t\t\t\tpendingCount--;\n\n\t\t\t\t\t// Track sleep/message errors - they need to bubble up to the scheduler\n\t\t\t\t\t// We'll re-throw after allSettled to allow cleanup\n\t\t\t\t\tif (error instanceof SleepError) {\n\t\t\t\t\t\t// Track the earliest deadline\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t!yieldError ||\n\t\t\t\t\t\t\t!(yieldError instanceof SleepError) ||\n\t\t\t\t\t\t\terror.deadline < yieldError.deadline\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\tyieldError = error;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbranchStatus.status = \"running\"; // Keep as running since we'll resume\n\t\t\t\t\t\tentry.dirty = true;\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tif (error instanceof MessageWaitError) {\n\t\t\t\t\t\t// Track message wait errors, prefer sleep errors with deadlines\n\t\t\t\t\t\tif (!yieldError || !(yieldError instanceof SleepError)) {\n\t\t\t\t\t\t\tif (!yieldError) {\n\t\t\t\t\t\t\t\tyieldError = error;\n\t\t\t\t\t\t\t} else if (yieldError instanceof MessageWaitError) {\n\t\t\t\t\t\t\t\t// Merge message names\n\t\t\t\t\t\t\t\tyieldError = new MessageWaitError([\n\t\t\t\t\t\t\t\t\t...yieldError.messageNames,\n\t\t\t\t\t\t\t\t\t...error.messageNames,\n\t\t\t\t\t\t\t\t]);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbranchStatus.status = \"running\"; // Keep as running since we'll resume\n\t\t\t\t\t\tentry.dirty = true;\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (\n\t\t\t\t\t\terror instanceof CancelledError ||\n\t\t\t\t\t\terror instanceof EvictedError\n\t\t\t\t\t) {\n\t\t\t\t\t\tbranchStatus.status = \"cancelled\";\n\t\t\t\t\t} else {\n\t\t\t\t\t\tbranchStatus.status = \"failed\";\n\t\t\t\t\t\tbranchStatus.error = String(error);\n\n\t\t\t\t\t\tif (settled) {\n\t\t\t\t\t\t\t// Track late errors for observability\n\t\t\t\t\t\t\tlateErrors.push({\n\t\t\t\t\t\t\t\tname: branch.name,\n\t\t\t\t\t\t\t\terror: String(error),\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\terrors[branch.name] = error;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tentry.dirty = true;\n\n\t\t\t\t\t// All branches failed (only if no winner yet)\n\t\t\t\t\tif (pendingCount === 0 && !settled) {\n\t\t\t\t\t\tsettled = true;\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t);\n\n\t\t\tbranchPromises.push(branchPromise);\n\t\t}\n\n\t\t// Wait for all branches to complete or be cancelled\n\t\tawait Promise.allSettled(branchPromises);\n\n\t\t// If any branch needs to yield to the scheduler (sleep/message wait),\n\t\t// save state and re-throw the error to exit the workflow execution\n\t\tif (yieldError && !settled) {\n\t\t\tawait this.flushStorage();\n\t\t\tthrow yieldError;\n\t\t}\n\n\t\t// Clean up entries from non-winning branches\n\t\tif (winnerName !== null) {\n\t\t\tfor (const branch of branches) {\n\t\t\t\tif (branch.name !== winnerName) {\n\t\t\t\t\tconst branchLocation = appendName(\n\t\t\t\t\t\tthis.storage,\n\t\t\t\t\t\tlocation,\n\t\t\t\t\t\tbranch.name,\n\t\t\t\t\t);\n\t\t\t\t\tawait deleteEntriesWithPrefix(\n\t\t\t\t\t\tthis.storage,\n\t\t\t\t\t\tthis.driver,\n\t\t\t\t\t\tbranchLocation,\n\t\t\t\t\t\tthis.historyNotifier,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Flush final state\n\t\tawait this.flushStorage();\n\n\t\t// Log late errors if any (these occurred after a winner was determined)\n\t\tif (lateErrors.length > 0) {\n\t\t\tconsole.warn(\n\t\t\t\t`Race \"${name}\" had ${lateErrors.length} branch(es) fail after winner was determined:`,\n\t\t\t\tlateErrors,\n\t\t\t);\n\t\t}\n\n\t\t// Return result or throw error\n\t\tif (winnerName !== null && winnerValue !== null) {\n\t\t\treturn { winner: winnerName, value: winnerValue };\n\t\t}\n\n\t\t// All branches failed\n\t\tthrow new RaceError(\n\t\t\t\"All branches failed\",\n\t\t\tObject.entries(errors).map(([name, error]) => ({\n\t\t\t\tname,\n\t\t\t\terror: String(error),\n\t\t\t})),\n\t\t);\n\t}\n\n\t// === Removed ===\n\n\tasync removed(name: string, originalType: EntryKindType): Promise<void> {\n\t\tthis.assertNotInProgress();\n\t\tthis.checkEvicted();\n\n\t\tthis.entryInProgress = true;\n\t\ttry {\n\t\t\tawait this.executeRemoved(name, originalType);\n\t\t} finally {\n\t\t\tthis.entryInProgress = false;\n\t\t}\n\t}\n\n\tprivate async executeRemoved(\n\t\tname: string,\n\t\toriginalType: EntryKindType,\n\t): Promise<void> {\n\t\t// Check for duplicate name in current execution\n\t\tthis.checkDuplicateName(name);\n\n\t\tconst location = appendName(this.storage, this.currentLocation, name);\n\t\tconst key = locationToKey(this.storage, location);\n\t\tconst existing = this.storage.history.entries.get(key);\n\n\t\t// Mark this entry as visited for validateComplete\n\t\tthis.markVisited(key);\n\n\t\tthis.stopRollbackIfMissing(existing);\n\n\t\tif (existing) {\n\t\t\t// Validate the existing entry matches what we expect\n\t\t\tif (\n\t\t\t\texisting.kind.type !== \"removed\" &&\n\t\t\t\texisting.kind.type !== originalType\n\t\t\t) {\n\t\t\t\tthrow new HistoryDivergedError(\n\t\t\t\t\t`Expected ${originalType} or removed at ${key}, found ${existing.kind.type}`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// If it's not already marked as removed, we just skip it\n\t\t\treturn;\n\t\t}\n\n\t\t// Create a removed entry placeholder\n\t\tconst entry = createEntry(location, {\n\t\t\ttype: \"removed\",\n\t\t\tdata: { originalType, originalName: name },\n\t\t});\n\t\tsetEntry(this.storage, location, entry);\n\t\tawait this.flushStorage();\n\t}\n}\n","import type { Logger } from \"pino\";\n\n// Types\n\n// Context\nexport {\n\tDEFAULT_LOOP_COMMIT_INTERVAL,\n\tDEFAULT_LOOP_HISTORY_EVERY,\n\tDEFAULT_LOOP_HISTORY_KEEP,\n\tDEFAULT_MAX_RETRIES,\n\tDEFAULT_RETRY_BACKOFF_BASE,\n\tDEFAULT_RETRY_BACKOFF_MAX,\n\tDEFAULT_STEP_TIMEOUT,\n\tWorkflowContextImpl,\n} from \"./context.js\";\n// Driver\nexport type { EngineDriver, KVEntry, KVWrite } from \"./driver.js\";\n// Errors\nexport {\n\tCancelledError,\n\tCriticalError,\n\tEntryInProgressError,\n\tEvictedError,\n\tHistoryDivergedError,\n\tJoinError,\n\tMessageWaitError,\n\tRaceError,\n\tRollbackCheckpointError,\n\tRollbackError,\n\tSleepError,\n\tStepExhaustedError,\n\tStepFailedError,\n} from \"./errors.js\";\n\n// Location utilities\nexport {\n\tappendLoopIteration,\n\tappendName,\n\temptyLocation,\n\tisLocationPrefix,\n\tisLoopIterationMarker,\n\tlocationsEqual,\n\tlocationToKey,\n\tparentLocation,\n\tregisterName,\n\tresolveName,\n} from \"./location.js\";\n\n// Storage utilities\nexport {\n\tcreateEntry,\n\tcreateHistorySnapshot,\n\tcreateStorage,\n\tdeleteEntriesWithPrefix,\n\tflush,\n\tgenerateId,\n\tgetEntry,\n\tgetOrCreateMetadata,\n\tloadMetadata,\n\tloadStorage,\n\tsetEntry,\n} from \"./storage.js\";\nexport type {\n\tBranchConfig,\n\tBranchOutput,\n\tBranchStatus,\n\tBranchStatusType,\n\tEntry,\n\tEntryKind,\n\tEntryKindType,\n\tEntryMetadata,\n\tEntryStatus,\n\tHistory,\n\tJoinEntry,\n\tLocation,\n\tLoopConfig,\n\tLoopEntry,\n\tLoopIterationMarker,\n\tLoopResult,\n\tMessage,\n\tMessageEntry,\n\tNameIndex,\n\tPathSegment,\n\tRaceEntry,\n\tRemovedEntry,\n\tWorkflowEntryMetadataSnapshot,\n\tWorkflowHistoryEntry,\n\tWorkflowHistorySnapshot,\n\tRollbackCheckpointEntry,\n\tRollbackContextInterface,\n\tRunWorkflowOptions,\n\tSleepEntry,\n\tSleepState,\n\tStepConfig,\n\tStepEntry,\n\tStorage,\n\tWorkflowContextInterface,\n\tWorkflowFunction,\n\tWorkflowHandle,\n\tWorkflowQueue,\n\tWorkflowQueueMessage,\n\tWorkflowQueueNextBatchOptions,\n\tWorkflowQueueNextOptions,\n\tWorkflowMessageDriver,\n\tWorkflowResult,\n\tWorkflowRunMode,\n\tWorkflowState,\n} from \"./types.js\";\n\n// Loop result helpers\nexport const Loop = {\n\tcontinue: <S>(state: S): { continue: true; state: S } => ({\n\t\tcontinue: true,\n\t\tstate,\n\t}),\n\tbreak: <T>(value: T): { break: true; value: T } => ({\n\t\tbreak: true,\n\t\tvalue,\n\t}),\n};\n\nimport {\n\tdeserializeEntryMetadata,\n\tdeserializeWorkflowInput,\n\tdeserializeWorkflowOutput,\n\tdeserializeWorkflowState,\n\tserializeEntryMetadata,\n\tserializeWorkflowInput,\n\tserializeWorkflowState,\n} from \"../schemas/serde.js\";\nimport { type RollbackAction, WorkflowContextImpl } from \"./context.js\";\n// Main workflow runner\nimport type { EngineDriver } from \"./driver.js\";\nimport {\n\tEvictedError,\n\tMessageWaitError,\n\tRollbackCheckpointError,\n\tRollbackStopError,\n\tSleepError,\n\tStepFailedError,\n} from \"./errors.js\";\nimport {\n\tbuildEntryMetadataPrefix,\n\tbuildWorkflowErrorKey,\n\tbuildWorkflowInputKey,\n\tbuildWorkflowOutputKey,\n\tbuildWorkflowStateKey,\n} from \"./keys.js\";\nimport {\n\tcreateHistorySnapshot,\n\tflush,\n\tgenerateId,\n\tloadMetadata,\n\tloadStorage,\n} from \"./storage.js\";\nimport type {\n\tRollbackContextInterface,\n\tRunWorkflowOptions,\n\tStorage,\n\tWorkflowHistorySnapshot,\n\tWorkflowFunction,\n\tWorkflowHandle,\n\tWorkflowMessageDriver,\n\tWorkflowResult,\n\tWorkflowRunMode,\n\tWorkflowState,\n} from \"./types.js\";\nimport { setLongTimeout } from \"./utils.js\";\n\n/**\n * Run a workflow and return a handle for managing it.\n *\n * The workflow starts executing immediately. Use the returned handle to:\n * - `handle.result` - Await workflow completion (or yield in `yield` mode)\n * - `handle.message()` - Send messages to the workflow\n * - `handle.wake()` - Wake the workflow early\n * - `handle.evict()` - Request graceful shutdown\n * - `handle.getOutput()` / `handle.getState()` - Query status\n */\ninterface LiveRuntime {\n\tsleepWaiter?: () => void;\n\tisSleeping: boolean;\n}\n\ntype HistoryNotifier = (() => void) | undefined;\n\nfunction createLiveRuntime(): LiveRuntime {\n\treturn {\n\t\tisSleeping: false,\n\t};\n}\n\nfunction createEvictionWait(signal: AbortSignal): {\n\tpromise: Promise<never>;\n\tcleanup: () => void;\n} {\n\tif (signal.aborted) {\n\t\treturn {\n\t\t\tpromise: Promise.reject(new EvictedError()),\n\t\t\tcleanup: () => {},\n\t\t};\n\t}\n\n\tlet onAbort: (() => void) | undefined;\n\tconst promise = new Promise<never>((_, reject) => {\n\t\tonAbort = () => {\n\t\t\treject(new EvictedError());\n\t\t};\n\t\tsignal.addEventListener(\"abort\", onAbort, { once: true });\n\t});\n\n\treturn {\n\t\tpromise,\n\t\tcleanup: () => {\n\t\t\tif (onAbort) {\n\t\t\t\tsignal.removeEventListener(\"abort\", onAbort);\n\t\t\t}\n\t\t},\n\t};\n}\n\nfunction createRollbackContext(\n\tworkflowId: string,\n\tabortController: AbortController,\n): RollbackContextInterface {\n\treturn {\n\t\tworkflowId,\n\t\tabortSignal: abortController.signal,\n\t\tisEvicted: () => abortController.signal.aborted,\n\t};\n}\n\nasync function awaitWithEviction<T>(\n\tpromise: Promise<T>,\n\tabortSignal: AbortSignal,\n): Promise<T> {\n\tconst { promise: evictionPromise, cleanup } =\n\t\tcreateEvictionWait(abortSignal);\n\ttry {\n\t\treturn await Promise.race([promise, evictionPromise]);\n\t} finally {\n\t\tcleanup();\n\t}\n}\n\nasync function executeRollback<TInput, TOutput>(\n\tworkflowId: string,\n\tworkflowFn: WorkflowFunction<TInput, TOutput>,\n\tinput: TInput,\n\tdriver: EngineDriver,\n\tmessageDriver: WorkflowMessageDriver,\n\tabortController: AbortController,\n\tstorage: Storage,\n\thistoryNotifier?: HistoryNotifier,\n\tlogger?: Logger,\n): Promise<void> {\n\tconst rollbackActions: RollbackAction[] = [];\n\tconst ctx = new WorkflowContextImpl(\n\t\tworkflowId,\n\t\tstorage,\n\t\tdriver,\n\t\tmessageDriver,\n\t\tundefined,\n\t\tabortController,\n\t\t\"rollback\",\n\t\trollbackActions,\n\t\tfalse,\n\t\thistoryNotifier,\n\t\tlogger,\n\t);\n\n\ttry {\n\t\tawait workflowFn(ctx, input);\n\t} catch (error) {\n\t\tif (error instanceof EvictedError) {\n\t\t\tthrow error;\n\t\t}\n\t\tif (error instanceof RollbackStopError) {\n\t\t\t// Stop replay once we hit incomplete history during rollback.\n\t\t} else {\n\t\t\t// Ignore workflow errors during rollback replay.\n\t\t}\n\t}\n\n\tif (rollbackActions.length === 0) {\n\t\treturn;\n\t}\n\n\tconst rollbackContext = createRollbackContext(workflowId, abortController);\n\n\tfor (let i = rollbackActions.length - 1; i >= 0; i--) {\n\t\tif (abortController.signal.aborted) {\n\t\t\tthrow new EvictedError();\n\t\t}\n\n\t\tconst action = rollbackActions[i];\n\t\tconst metadata = await loadMetadata(storage, driver, action.entryId);\n\t\tif (metadata.rollbackCompletedAt !== undefined) {\n\t\t\tcontinue;\n\t\t}\n\n\t\ttry {\n\t\t\tawait awaitWithEviction(\n\t\t\t\taction.rollback(rollbackContext, action.output),\n\t\t\t\tabortController.signal,\n\t\t\t);\n\t\t\tmetadata.rollbackCompletedAt = Date.now();\n\t\t\tmetadata.rollbackError = undefined;\n\t\t} catch (error) {\n\t\t\tif (error instanceof EvictedError) {\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\tmetadata.rollbackError =\n\t\t\t\terror instanceof Error ? error.message : String(error);\n\t\t\tthrow error;\n\t\t} finally {\n\t\t\tmetadata.dirty = true;\n\t\t\tawait flush(storage, driver, historyNotifier);\n\t\t}\n\t}\n}\n\nasync function setSleepState<TOutput>(\n\tstorage: Storage,\n\tdriver: EngineDriver,\n\tworkflowId: string,\n\tdeadline: number,\n\tmessageNames?: string[],\n\thistoryNotifier?: HistoryNotifier,\n): Promise<WorkflowResult<TOutput>> {\n\tstorage.state = \"sleeping\";\n\tawait flush(storage, driver, historyNotifier);\n\tawait driver.setAlarm(workflowId, deadline);\n\n\treturn {\n\t\tstate: \"sleeping\",\n\t\tsleepUntil: deadline,\n\t\twaitingForMessages: messageNames,\n\t};\n}\n\nasync function setMessageWaitState<TOutput>(\n\tstorage: Storage,\n\tdriver: EngineDriver,\n\tmessageNames: string[],\n\thistoryNotifier?: HistoryNotifier,\n): Promise<WorkflowResult<TOutput>> {\n\tstorage.state = \"sleeping\";\n\tawait flush(storage, driver, historyNotifier);\n\n\treturn { state: \"sleeping\", waitingForMessages: messageNames };\n}\n\nasync function setEvictedState<TOutput>(\n\tstorage: Storage,\n\tdriver: EngineDriver,\n\thistoryNotifier?: HistoryNotifier,\n): Promise<WorkflowResult<TOutput>> {\n\tawait flush(storage, driver, historyNotifier);\n\treturn { state: storage.state };\n}\n\nasync function setRetryState<TOutput>(\n\tstorage: Storage,\n\tdriver: EngineDriver,\n\tworkflowId: string,\n\thistoryNotifier?: HistoryNotifier,\n): Promise<WorkflowResult<TOutput>> {\n\tstorage.state = \"sleeping\";\n\tawait flush(storage, driver, historyNotifier);\n\n\tconst retryAt = Date.now() + 100;\n\tawait driver.setAlarm(workflowId, retryAt);\n\n\treturn { state: \"sleeping\", sleepUntil: retryAt };\n}\n\nasync function setFailedState(\n\tstorage: Storage,\n\tdriver: EngineDriver,\n\terror: unknown,\n\thistoryNotifier?: HistoryNotifier,\n): Promise<void> {\n\tstorage.state = \"failed\";\n\tstorage.error = extractErrorInfo(error);\n\tawait flush(storage, driver, historyNotifier);\n}\n\nasync function waitForSleep(\n\truntime: LiveRuntime,\n\tdeadline: number,\n\tabortSignal: AbortSignal,\n): Promise<void> {\n\twhile (true) {\n\t\tconst remaining = deadline - Date.now();\n\t\tif (remaining <= 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tlet timeoutHandle: ReturnType<typeof setLongTimeout> | undefined;\n\t\tconst timeoutPromise = new Promise<void>((resolve) => {\n\t\t\ttimeoutHandle = setLongTimeout(resolve, remaining);\n\t\t});\n\n\t\tconst wakePromise = new Promise<void>((resolve) => {\n\t\t\truntime.sleepWaiter = resolve;\n\t\t});\n\t\truntime.isSleeping = true;\n\n\t\ttry {\n\t\t\tawait awaitWithEviction(\n\t\t\t\tPromise.race([timeoutPromise, wakePromise]),\n\t\t\t\tabortSignal,\n\t\t\t);\n\t\t} finally {\n\t\t\truntime.isSleeping = false;\n\t\t\truntime.sleepWaiter = undefined;\n\t\t\ttimeoutHandle?.abort();\n\t\t}\n\n\t\tif (abortSignal.aborted) {\n\t\t\tthrow new EvictedError();\n\t\t}\n\n\t\tif (Date.now() >= deadline) {\n\t\t\treturn;\n\t\t}\n\t}\n}\n\nasync function executeLiveWorkflow<TInput, TOutput>(\n\tworkflowId: string,\n\tworkflowFn: WorkflowFunction<TInput, TOutput>,\n\tinput: TInput,\n\tdriver: EngineDriver,\n\tmessageDriver: WorkflowMessageDriver,\n\tabortController: AbortController,\n\truntime: LiveRuntime,\n\tonHistoryUpdated?: (history: WorkflowHistorySnapshot) => void,\n\tlogger?: Logger,\n): Promise<WorkflowResult<TOutput>> {\n\tlet lastResult: WorkflowResult<TOutput> | undefined;\n\n\twhile (true) {\n\t\tconst result = await executeWorkflow(\n\t\t\tworkflowId,\n\t\t\tworkflowFn,\n\t\t\tinput,\n\t\t\tdriver,\n\t\t\tmessageDriver,\n\t\t\tabortController,\n\t\t\tonHistoryUpdated,\n\t\t\tlogger,\n\t\t);\n\t\tlastResult = result;\n\n\t\tif (result.state !== \"sleeping\") {\n\t\t\treturn result;\n\t\t}\n\n\t\tconst hasMessages = result.waitingForMessages !== undefined;\n\t\tconst hasDeadline = result.sleepUntil !== undefined;\n\n\t\tif (hasMessages && hasDeadline) {\n\t\t\t// Wait for EITHER a message OR the deadline (for queue.next timeout)\n\t\t\ttry {\n\t\t\t\tconst messagePromise = awaitWithEviction(\n\t\t\t\t\tdriver.waitForMessages(\n\t\t\t\t\t\tresult.waitingForMessages!,\n\t\t\t\t\t\tabortController.signal,\n\t\t\t\t\t),\n\t\t\t\t\tabortController.signal,\n\t\t\t\t);\n\t\t\t\tconst sleepPromise = waitForSleep(\n\t\t\t\t\truntime,\n\t\t\t\t\tresult.sleepUntil!,\n\t\t\t\t\tabortController.signal,\n\t\t\t\t);\n\t\t\t\tawait Promise.race([messagePromise, sleepPromise]);\n\t\t\t} catch (error) {\n\t\t\t\tif (error instanceof EvictedError) {\n\t\t\t\t\treturn lastResult;\n\t\t\t\t}\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (hasMessages) {\n\t\t\ttry {\n\t\t\t\tawait awaitWithEviction(\n\t\t\t\t\tdriver.waitForMessages(\n\t\t\t\t\t\tresult.waitingForMessages!,\n\t\t\t\t\t\tabortController.signal,\n\t\t\t\t\t),\n\t\t\t\t\tabortController.signal,\n\t\t\t\t);\n\t\t\t} catch (error) {\n\t\t\t\tif (error instanceof EvictedError) {\n\t\t\t\t\treturn lastResult;\n\t\t\t\t}\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (hasDeadline) {\n\t\t\ttry {\n\t\t\t\tawait waitForSleep(\n\t\t\t\t\truntime,\n\t\t\t\t\tresult.sleepUntil!,\n\t\t\t\t\tabortController.signal,\n\t\t\t\t);\n\t\t\t} catch (error) {\n\t\t\t\tif (error instanceof EvictedError) {\n\t\t\t\t\treturn lastResult;\n\t\t\t\t}\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\treturn result;\n\t}\n}\n\nexport function runWorkflow<TInput, TOutput>(\n\tworkflowId: string,\n\tworkflowFn: WorkflowFunction<TInput, TOutput>,\n\tinput: TInput,\n\tdriver: EngineDriver,\n\toptions: RunWorkflowOptions = {},\n): WorkflowHandle<TOutput> {\n\tconst messageDriver = driver.messageDriver;\n\tconst abortController = new AbortController();\n\tconst mode: WorkflowRunMode = options.mode ?? \"yield\";\n\tconst liveRuntime = mode === \"live\" ? createLiveRuntime() : undefined;\n\n\tconst logger = options.logger;\n\n\tconst resultPromise =\n\t\tmode === \"live\" && liveRuntime\n\t\t\t? executeLiveWorkflow(\n\t\t\t\t\tworkflowId,\n\t\t\t\t\tworkflowFn,\n\t\t\t\t\tinput,\n\t\t\t\t\tdriver,\n\t\t\t\t\tmessageDriver,\n\t\t\t\t\tabortController,\n\t\t\t\t\tliveRuntime,\n\t\t\t\t\toptions.onHistoryUpdated,\n\t\t\t\t\tlogger,\n\t\t\t\t)\n\t\t\t: executeWorkflow(\n\t\t\t\t\tworkflowId,\n\t\t\t\t\tworkflowFn,\n\t\t\t\t\tinput,\n\t\t\t\t\tdriver,\n\t\t\t\t\tmessageDriver,\n\t\t\t\t\tabortController,\n\t\t\t\t\toptions.onHistoryUpdated,\n\t\t\t\t\tlogger,\n\t\t\t\t);\n\n\treturn {\n\t\tworkflowId,\n\t\tresult: resultPromise,\n\n\t\tasync message(name: string, data: unknown): Promise<void> {\n\t\t\tconst messageId = generateId();\n\t\t\tawait messageDriver.addMessage({\n\t\t\t\tid: messageId,\n\t\t\t\tname,\n\t\t\t\tdata,\n\t\t\t\tsentAt: Date.now(),\n\t\t\t});\n\t\t},\n\n\t\tasync wake(): Promise<void> {\n\t\t\tif (liveRuntime) {\n\t\t\t\tif (liveRuntime.isSleeping && liveRuntime.sleepWaiter) {\n\t\t\t\t\tliveRuntime.sleepWaiter();\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tawait driver.setAlarm(workflowId, Date.now());\n\t\t},\n\n\t\tasync recover(): Promise<void> {\n\t\t\tconst stateValue = await driver.get(buildWorkflowStateKey());\n\t\t\tconst state = stateValue\n\t\t\t\t? deserializeWorkflowState(stateValue)\n\t\t\t\t: \"pending\";\n\n\t\t\tif (state !== \"failed\") {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst metadataEntries = await driver.list(\n\t\t\t\tbuildEntryMetadataPrefix(),\n\t\t\t);\n\t\t\tconst writes: { key: Uint8Array; value: Uint8Array }[] = [];\n\n\t\t\tfor (const entry of metadataEntries) {\n\t\t\t\tconst metadata = deserializeEntryMetadata(entry.value);\n\t\t\t\tif (\n\t\t\t\t\tmetadata.status !== \"failed\" &&\n\t\t\t\t\tmetadata.status !== \"exhausted\"\n\t\t\t\t) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tmetadata.status = \"pending\";\n\t\t\t\tmetadata.attempts = 0;\n\t\t\t\tmetadata.lastAttemptAt = 0;\n\t\t\t\tmetadata.error = undefined;\n\t\t\t\tmetadata.dirty = false;\n\n\t\t\t\twrites.push({\n\t\t\t\t\tkey: entry.key,\n\t\t\t\t\tvalue: serializeEntryMetadata(metadata),\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tif (writes.length > 0) {\n\t\t\t\tawait driver.batch(writes);\n\t\t\t}\n\n\t\t\tawait driver.delete(buildWorkflowErrorKey());\n\t\t\tawait driver.set(\n\t\t\t\tbuildWorkflowStateKey(),\n\t\t\t\tserializeWorkflowState(\"sleeping\"),\n\t\t\t);\n\n\t\t\tif (liveRuntime) {\n\t\t\t\tif (liveRuntime.isSleeping && liveRuntime.sleepWaiter) {\n\t\t\t\t\tliveRuntime.sleepWaiter();\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tawait driver.setAlarm(workflowId, Date.now());\n\t\t},\n\n\t\tevict(): void {\n\t\t\tabortController.abort(new EvictedError());\n\t\t},\n\n\t\tasync cancel(): Promise<void> {\n\t\t\tabortController.abort(new EvictedError());\n\n\t\t\tawait driver.set(\n\t\t\t\tbuildWorkflowStateKey(),\n\t\t\t\tserializeWorkflowState(\"cancelled\"),\n\t\t\t);\n\n\t\t\tawait driver.clearAlarm(workflowId);\n\t\t},\n\n\t\tasync getOutput(): Promise<TOutput | undefined> {\n\t\t\tconst value = await driver.get(buildWorkflowOutputKey());\n\t\t\tif (!value) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t\treturn deserializeWorkflowOutput<TOutput>(value);\n\t\t},\n\n\t\tasync getState(): Promise<WorkflowState> {\n\t\t\tconst value = await driver.get(buildWorkflowStateKey());\n\t\t\tif (!value) {\n\t\t\t\treturn \"pending\";\n\t\t\t}\n\t\t\treturn deserializeWorkflowState(value);\n\t\t},\n\t};\n}\n\n/**\n * Internal: Execute the workflow and return the result.\n */\nasync function executeWorkflow<TInput, TOutput>(\n\tworkflowId: string,\n\tworkflowFn: WorkflowFunction<TInput, TOutput>,\n\tinput: TInput,\n\tdriver: EngineDriver,\n\tmessageDriver: WorkflowMessageDriver,\n\tabortController: AbortController,\n\tonHistoryUpdated?: (history: WorkflowHistorySnapshot) => void,\n\tlogger?: Logger,\n): Promise<WorkflowResult<TOutput>> {\n\tconst storage = await loadStorage(driver);\n\tconst historyNotifier: HistoryNotifier = onHistoryUpdated\n\t\t? () => onHistoryUpdated(createHistorySnapshot(storage))\n\t\t: undefined;\n\tif (historyNotifier) {\n\t\thistoryNotifier();\n\t}\n\n\tif (logger) {\n\t\tconst entryKeys = Array.from(storage.history.entries.keys());\n\t\tlogger.debug({\n\t\t\tmsg: \"loaded workflow storage\",\n\t\t\tstate: storage.state,\n\t\t\tentryCount: entryKeys.length,\n\t\t\tentries: entryKeys.slice(0, 10),\n\t\t\tnameRegistry: storage.nameRegistry,\n\t\t});\n\t}\n\n\t// Check if workflow was cancelled\n\tif (storage.state === \"cancelled\") {\n\t\tthrow new EvictedError();\n\t}\n\n\t// Input persistence: store on first run, use stored input on resume\n\tconst storedInputBytes = await driver.get(buildWorkflowInputKey());\n\tlet effectiveInput: TInput;\n\n\tif (storedInputBytes) {\n\t\t// Resume: use stored input for deterministic replay\n\t\teffectiveInput = deserializeWorkflowInput<TInput>(storedInputBytes);\n\t} else {\n\t\t// First run: store the input\n\t\teffectiveInput = input;\n\t\tawait driver.set(\n\t\t\tbuildWorkflowInputKey(),\n\t\t\tserializeWorkflowInput(input),\n\t\t);\n\t}\n\n\tif (storage.state === \"rolling_back\") {\n\t\ttry {\n\t\t\tawait executeRollback(\n\t\t\t\tworkflowId,\n\t\t\t\tworkflowFn,\n\t\t\t\teffectiveInput,\n\t\t\t\tdriver,\n\t\t\t\tmessageDriver,\n\t\t\t\tabortController,\n\t\t\t\tstorage,\n\t\t\t\thistoryNotifier,\n\t\t\t\tlogger,\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tif (error instanceof EvictedError) {\n\t\t\t\treturn { state: storage.state };\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\n\t\tstorage.state = \"failed\";\n\t\tawait flush(storage, driver, historyNotifier);\n\n\t\tconst storedError = storage.error\n\t\t\t? new Error(storage.error.message)\n\t\t\t: new Error(\"Workflow failed\");\n\t\tif (storage.error?.name) {\n\t\t\tstoredError.name = storage.error.name;\n\t\t}\n\t\tthrow storedError;\n\t}\n\n\tconst ctx = new WorkflowContextImpl(\n\t\tworkflowId,\n\t\tstorage,\n\t\tdriver,\n\t\tmessageDriver,\n\t\tundefined,\n\t\tabortController,\n\t\t\"forward\",\n\t\tundefined,\n\t\tfalse,\n\t\thistoryNotifier,\n\t\tlogger,\n\t);\n\n\tstorage.state = \"running\";\n\n\ttry {\n\t\tconst output = await workflowFn(ctx, effectiveInput);\n\n\t\tstorage.state = \"completed\";\n\t\tstorage.output = output;\n\t\tawait flush(storage, driver, historyNotifier);\n\t\tawait driver.clearAlarm(workflowId);\n\n\t\treturn { state: \"completed\", output };\n\t} catch (error) {\n\t\tif (error instanceof SleepError) {\n\t\t\treturn await setSleepState(\n\t\t\t\tstorage,\n\t\t\t\tdriver,\n\t\t\t\tworkflowId,\n\t\t\t\terror.deadline,\n\t\t\t\terror.messageNames,\n\t\t\t\thistoryNotifier,\n\t\t\t);\n\t\t}\n\n\t\tif (error instanceof MessageWaitError) {\n\t\t\treturn await setMessageWaitState(\n\t\t\t\tstorage,\n\t\t\t\tdriver,\n\t\t\t\terror.messageNames,\n\t\t\t\thistoryNotifier,\n\t\t\t);\n\t\t}\n\n\t\tif (error instanceof EvictedError) {\n\t\t\treturn await setEvictedState(storage, driver, historyNotifier);\n\t\t}\n\n\t\tif (error instanceof StepFailedError) {\n\t\t\treturn await setRetryState(\n\t\t\t\tstorage,\n\t\t\t\tdriver,\n\t\t\t\tworkflowId,\n\t\t\t\thistoryNotifier,\n\t\t\t);\n\t\t}\n\n\t\tif (error instanceof RollbackCheckpointError) {\n\t\t\tawait setFailedState(storage, driver, error, historyNotifier);\n\t\t\tthrow error;\n\t\t}\n\n\t\t// Unrecoverable error\n\t\tstorage.error = extractErrorInfo(error);\n\t\tstorage.state = \"rolling_back\";\n\t\tawait flush(storage, driver, historyNotifier);\n\n\t\ttry {\n\t\t\tawait executeRollback(\n\t\t\t\tworkflowId,\n\t\t\t\tworkflowFn,\n\t\t\t\teffectiveInput,\n\t\t\t\tdriver,\n\t\t\t\tmessageDriver,\n\t\t\t\tabortController,\n\t\t\t\tstorage,\n\t\t\t\thistoryNotifier,\n\t\t\t\tlogger,\n\t\t\t);\n\t\t} catch (rollbackError) {\n\t\t\tif (rollbackError instanceof EvictedError) {\n\t\t\t\treturn { state: storage.state };\n\t\t\t}\n\t\t\tthrow rollbackError;\n\t\t}\n\n\t\tstorage.state = \"failed\";\n\t\tawait flush(storage, driver, historyNotifier);\n\n\t\tthrow error;\n\t}\n}\n\n/**\n * Extract structured error information from an error.\n */\nfunction extractErrorInfo(error: unknown): {\n\tname: string;\n\tmessage: string;\n\tstack?: string;\n\tmetadata?: Record<string, unknown>;\n} {\n\tif (error instanceof Error) {\n\t\tconst result: {\n\t\t\tname: string;\n\t\t\tmessage: string;\n\t\t\tstack?: string;\n\t\t\tmetadata?: Record<string, unknown>;\n\t\t} = {\n\t\t\tname: error.name,\n\t\t\tmessage: error.message,\n\t\t\tstack: error.stack,\n\t\t};\n\n\t\t// Extract custom properties from error\n\t\tconst metadata: Record<string, unknown> = {};\n\t\tfor (const key of Object.keys(error)) {\n\t\t\tif (key !== \"name\" && key !== \"message\" && key !== \"stack\") {\n\t\t\t\tconst value = (error as unknown as Record<string, unknown>)[\n\t\t\t\t\tkey\n\t\t\t\t];\n\t\t\t\t// Only include serializable values\n\t\t\t\tif (\n\t\t\t\t\ttypeof value === \"string\" ||\n\t\t\t\t\ttypeof value === \"number\" ||\n\t\t\t\t\ttypeof value === \"boolean\" ||\n\t\t\t\t\tvalue === null\n\t\t\t\t) {\n\t\t\t\t\tmetadata[key] = value;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif (Object.keys(metadata).length > 0) {\n\t\t\tresult.metadata = metadata;\n\t\t}\n\n\t\treturn result;\n\t}\n\n\treturn {\n\t\tname: \"Error\",\n\t\tmessage: String(error),\n\t};\n}\n"]}
|
|
@@ -1602,6 +1602,7 @@ var WorkflowContextImpl = class _WorkflowContextImpl {
|
|
|
1602
1602
|
get queue() {
|
|
1603
1603
|
return {
|
|
1604
1604
|
next: async (name, opts) => await this.queueNext(name, opts),
|
|
1605
|
+
nextBatch: async (name, opts) => await this.queueNextBatch(name, opts),
|
|
1605
1606
|
send: async (name, body) => await this.queueSend(name, body)
|
|
1606
1607
|
};
|
|
1607
1608
|
}
|
|
@@ -2015,7 +2016,13 @@ var WorkflowContextImpl = class _WorkflowContextImpl {
|
|
|
2015
2016
|
iteration
|
|
2016
2017
|
);
|
|
2017
2018
|
const branchCtx = this.createBranch(iterationLocation);
|
|
2018
|
-
const
|
|
2019
|
+
const iterationResult = await config2.run(branchCtx, state);
|
|
2020
|
+
if (iterationResult === void 0 && state !== void 0) {
|
|
2021
|
+
throw new Error(
|
|
2022
|
+
`Loop "${config2.name}" returned undefined for a stateful iteration. Return Loop.continue(state) or Loop.break(value).`
|
|
2023
|
+
);
|
|
2024
|
+
}
|
|
2025
|
+
const result = iterationResult === void 0 ? { continue: true, state } : iterationResult;
|
|
2019
2026
|
branchCtx.validateComplete();
|
|
2020
2027
|
if ("break" in result && result.break) {
|
|
2021
2028
|
if (entry.kind.type === "loop") {
|
|
@@ -2218,16 +2225,29 @@ var WorkflowContextImpl = class _WorkflowContextImpl {
|
|
|
2218
2225
|
await this.messageDriver.addMessage(message);
|
|
2219
2226
|
}
|
|
2220
2227
|
async queueNext(name, opts) {
|
|
2228
|
+
const messages = await this.queueNextBatch(name, {
|
|
2229
|
+
...opts ?? {},
|
|
2230
|
+
count: 1
|
|
2231
|
+
});
|
|
2232
|
+
const message = messages[0];
|
|
2233
|
+
if (!message) {
|
|
2234
|
+
throw new Error(
|
|
2235
|
+
`queue.next("${name}") timed out before receiving a message. Use queue.nextBatch(...) for optional/time-limited reads.`
|
|
2236
|
+
);
|
|
2237
|
+
}
|
|
2238
|
+
return message;
|
|
2239
|
+
}
|
|
2240
|
+
async queueNextBatch(name, opts) {
|
|
2221
2241
|
this.assertNotInProgress();
|
|
2222
2242
|
this.checkEvicted();
|
|
2223
2243
|
this.entryInProgress = true;
|
|
2224
2244
|
try {
|
|
2225
|
-
return await this.
|
|
2245
|
+
return await this.executeQueueNextBatch(name, opts);
|
|
2226
2246
|
} finally {
|
|
2227
2247
|
this.entryInProgress = false;
|
|
2228
2248
|
}
|
|
2229
2249
|
}
|
|
2230
|
-
async
|
|
2250
|
+
async executeQueueNextBatch(name, opts) {
|
|
2231
2251
|
if (this.pendingCompletableMessageIds.size > 0) {
|
|
2232
2252
|
throw new Error(
|
|
2233
2253
|
"Previous completable queue message is not completed. Call `message.complete(...)` before receiving the next message."
|
|
@@ -3438,4 +3458,4 @@ export {
|
|
|
3438
3458
|
Loop,
|
|
3439
3459
|
runWorkflow
|
|
3440
3460
|
};
|
|
3441
|
-
//# sourceMappingURL=chunk-
|
|
3461
|
+
//# sourceMappingURL=chunk-WA4TXB6Y.js.map
|