@rivetkit/workflow-engine 2.1.7 → 2.1.8

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.
@@ -248,6 +248,13 @@ function parseNameKey(key) {
248
248
  }
249
249
  return elements[1];
250
250
  }
251
+ function parseEntryMetadataKey(key) {
252
+ const elements = unpack2(key);
253
+ if (elements.length !== 2 || elements[0] !== KEY_PREFIX.ENTRY_METADATA) {
254
+ throw new Error("Invalid entry metadata key");
255
+ }
256
+ return elements[1];
257
+ }
251
258
  function keyStartsWith(key, prefix) {
252
259
  if (key.length < prefix.length) {
253
260
  return false;
@@ -1472,6 +1479,13 @@ async function loadStorage(driver) {
1472
1479
  const key = locationToKey(storage, parsed.location);
1473
1480
  storage.history.entries.set(key, parsed);
1474
1481
  }
1482
+ const metadataEntries = await driver.list(buildEntryMetadataPrefix());
1483
+ for (const entry of metadataEntries) {
1484
+ const entryId = parseEntryMetadataKey(entry.key);
1485
+ const metadata = deserializeEntryMetadata(entry.value);
1486
+ metadata.dirty = false;
1487
+ storage.entryMetadata.set(entryId, metadata);
1488
+ }
1475
1489
  const stateValue = await driver.get(buildWorkflowStateKey());
1476
1490
  if (stateValue) {
1477
1491
  storage.state = deserializeWorkflowState(stateValue);
@@ -2033,16 +2047,11 @@ var WorkflowContextImpl = class _WorkflowContextImpl {
2033
2047
  retryBackoffMax
2034
2048
  );
2035
2049
  const retryAt = metadata.lastAttemptAt + retryDelay;
2036
- await this.notifyStepError(
2037
- config2,
2038
- metadata.attempts,
2039
- error,
2040
- {
2041
- willRetry: true,
2042
- retryDelay,
2043
- retryAt
2044
- }
2045
- );
2050
+ await this.notifyStepError(config2, metadata.attempts, error, {
2051
+ willRetry: true,
2052
+ retryDelay,
2053
+ retryAt
2054
+ });
2046
2055
  throw new StepFailedError(
2047
2056
  config2.name,
2048
2057
  error,
@@ -2053,12 +2062,9 @@ var WorkflowContextImpl = class _WorkflowContextImpl {
2053
2062
  const exhaustedError = markErrorReported(
2054
2063
  new StepExhaustedError(config2.name, String(error))
2055
2064
  );
2056
- await this.notifyStepError(
2057
- config2,
2058
- metadata.attempts,
2059
- error,
2060
- { willRetry: false }
2061
- );
2065
+ await this.notifyStepError(config2, metadata.attempts, error, {
2066
+ willRetry: false
2067
+ });
2062
2068
  throw exhaustedError;
2063
2069
  }
2064
2070
  }
@@ -3501,6 +3507,91 @@ function runWorkflow(workflowId, workflowFn, input, driver, options = {}) {
3501
3507
  }
3502
3508
  };
3503
3509
  }
3510
+ async function replayWorkflowFromStep(workflowId, driver, entryId, options) {
3511
+ const storage = await loadStorage(driver);
3512
+ const entries = await Promise.all(
3513
+ Array.from(storage.history.entries.entries()).map(
3514
+ async ([key, entry]) => ({
3515
+ key,
3516
+ entry,
3517
+ metadata: await loadMetadata(storage, driver, entry.id)
3518
+ })
3519
+ )
3520
+ );
3521
+ const ordered = [...entries].sort((a, b) => {
3522
+ if (a.metadata.createdAt !== b.metadata.createdAt) {
3523
+ return a.metadata.createdAt - b.metadata.createdAt;
3524
+ }
3525
+ return a.key.localeCompare(b.key);
3526
+ });
3527
+ let entriesToDelete = ordered;
3528
+ if (entryId !== void 0) {
3529
+ const target = entries.find(({ entry }) => entry.id === entryId);
3530
+ if (!target) {
3531
+ throw new Error(`Workflow step not found: ${entryId}`);
3532
+ }
3533
+ if (target.entry.kind.type !== "step") {
3534
+ throw new Error("Workflow replay target must be a step");
3535
+ }
3536
+ const replayBoundary = findReplayBoundaryEntry(entries, target);
3537
+ const targetIndex = ordered.findIndex(
3538
+ ({ entry }) => entry.id === replayBoundary.entry.id
3539
+ );
3540
+ entriesToDelete = ordered.slice(targetIndex);
3541
+ }
3542
+ const entryIdsToDelete = new Set(
3543
+ entriesToDelete.map(({ entry }) => entry.id)
3544
+ );
3545
+ if (entries.some(
3546
+ ({ entry, metadata }) => metadata.status === "running" && !entryIdsToDelete.has(entry.id)
3547
+ )) {
3548
+ throw new Error(
3549
+ "Cannot replay a workflow while a step is currently running"
3550
+ );
3551
+ }
3552
+ await Promise.all(
3553
+ entriesToDelete.flatMap(({ entry }) => [
3554
+ driver.delete(buildHistoryKey(entry.location)),
3555
+ driver.delete(buildEntryMetadataKey(entry.id))
3556
+ ])
3557
+ );
3558
+ for (const { key, entry } of entriesToDelete) {
3559
+ storage.history.entries.delete(key);
3560
+ storage.entryMetadata.delete(entry.id);
3561
+ }
3562
+ storage.output = void 0;
3563
+ storage.flushedOutput = void 0;
3564
+ storage.error = void 0;
3565
+ storage.flushedError = void 0;
3566
+ storage.state = "sleeping";
3567
+ storage.flushedState = "sleeping";
3568
+ await Promise.all([
3569
+ driver.delete(buildWorkflowOutputKey()),
3570
+ driver.delete(buildWorkflowErrorKey()),
3571
+ driver.set(buildWorkflowStateKey(), serializeWorkflowState("sleeping"))
3572
+ ]);
3573
+ if ((options == null ? void 0 : options.scheduleAlarm) ?? true) {
3574
+ await driver.setAlarm(workflowId, Date.now());
3575
+ }
3576
+ return createHistorySnapshot(storage);
3577
+ }
3578
+ function findReplayBoundaryEntry(entries, target) {
3579
+ let boundary = target;
3580
+ let boundaryDepth = -1;
3581
+ for (const candidate of entries) {
3582
+ if (candidate.entry.kind.type !== "loop") {
3583
+ continue;
3584
+ }
3585
+ if (candidate.entry.location.length >= target.entry.location.length || !isLocationPrefix(candidate.entry.location, target.entry.location)) {
3586
+ continue;
3587
+ }
3588
+ if (candidate.entry.location.length > boundaryDepth) {
3589
+ boundary = candidate;
3590
+ boundaryDepth = candidate.entry.location.length;
3591
+ }
3592
+ }
3593
+ return boundary;
3594
+ }
3504
3595
  async function executeWorkflow(workflowId, workflowFn, input, driver, messageDriver, abortController, onHistoryUpdated, onError, logger) {
3505
3596
  var _a;
3506
3597
  const storage = await loadStorage(driver);
@@ -3711,6 +3802,7 @@ export {
3711
3802
  DEFAULT_STEP_TIMEOUT,
3712
3803
  WorkflowContextImpl,
3713
3804
  Loop,
3714
- runWorkflow
3805
+ runWorkflow,
3806
+ replayWorkflowFromStep
3715
3807
  };
3716
- //# sourceMappingURL=chunk-MMWB37UG.js.map
3808
+ //# sourceMappingURL=chunk-4ME2JBMC.js.map