@dudousxd/nestjs-durable-core 0.79.0 → 0.80.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/index.d.cts CHANGED
@@ -1169,6 +1169,21 @@ interface StateStore {
1169
1169
  tryAdmitSingleton?(runId: string, tag: string, workflow: string, limit: number, retryWakeAt?: number): Promise<boolean>;
1170
1170
  createRun(run: WorkflowRun): Promise<void>;
1171
1171
  updateRun(runId: string, patch: Partial<WorkflowRun>): Promise<void>;
1172
+ /**
1173
+ * {@link updateRun}, but only if the run's CURRENT status is one of `expectedStatuses`: a
1174
+ * compare-and-set on the status. Resolves whether the patch applied; never throws on a mismatch or
1175
+ * a missing run (both resolve `false`). The engine settles a turn's outcome (completed, failed,
1176
+ * suspended, blocked) through it, so a run that reached `cancelled`/`completed`/`dead` through
1177
+ * another path while the turn executed (an operator's `cancel()`, a timeout sweep, a dead-letter)
1178
+ * is never overwritten by the turn's stale outcome.
1179
+ *
1180
+ * For a SQL store the predicate must be part of the `UPDATE ... WHERE` itself; a read-then-write
1181
+ * in application code reintroduces the race this exists to close.
1182
+ *
1183
+ * Optional: a store that omits it gets the engine's read-then-write fallback, which narrows the
1184
+ * race to the gap between that read and the write but cannot close it.
1185
+ */
1186
+ updateRunIf?(runId: string, expectedStatuses: RunStatus[], patch: Partial<WorkflowRun>): Promise<boolean>;
1172
1187
  getRun(runId: string): Promise<WorkflowRun | null>;
1173
1188
  /**
1174
1189
  * Hard-delete a run and all of its rows — the run plus its checkpoints, signal waiters, and
@@ -1228,6 +1243,16 @@ interface StateStore {
1228
1243
  saveCheckpointsIfPending?(checkpoints: StepCheckpoint[]): Promise<boolean[]>;
1229
1244
  /** Used by recovery on boot to find runs to resume (crashed, left `running`). */
1230
1245
  listIncompleteRuns(namespace?: string): Promise<WorkflowRun[]>;
1246
+ /**
1247
+ * The ORPHANS a periodic recovery pass should reclaim: {@link listIncompleteRuns}'s runs
1248
+ * (`running` or `cancelling`) whose lease is free (`lockedUntil` unset or `<= nowMs`), oldest
1249
+ * (`createdAt`) first, at most `limit`. When `namespace` is given, restricted to that partition.
1250
+ *
1251
+ * Optional but recommended: without it the engine lists every incomplete run and filters the
1252
+ * leases in process, which on a busy fleet reads every healthy running run once per tick per
1253
+ * worker.
1254
+ */
1255
+ listOrphanedRuns?(nowMs: number, limit: number, namespace?: string): Promise<WorkflowRun[]>;
1231
1256
  /** The oldest `pending` runs awaiting dispatch (FIFO, by `createdAt`), capped at `limit`. */
1232
1257
  listPendingRuns(limit: number, namespace?: string): Promise<WorkflowRun[]>;
1233
1258
  /**
@@ -3969,6 +3994,18 @@ interface StartOptions {
3969
3994
  * workflow's registered `concurrency`. See {@link ConcurrencyQuota}.
3970
3995
  */
3971
3996
  concurrency?: ConcurrencyQuota | undefined;
3997
+ /**
3998
+ * Delayed start: don't execute before this time (epoch ms, or a `Date`), compared against the
3999
+ * engine's clock. The run is created `suspended` with its `wakeAt` set to it, which is the same
4000
+ * durable timer a `ctx.sleep` parks on: nothing is held in memory, it survives restarts, and the
4001
+ * timer poller (`resumeDueTimers`) starts it once due, on any instance. A time that is not in the
4002
+ * future starts the run at once, as if it were omitted.
4003
+ *
4004
+ * A delayed run reads `suspended` until it fires (so `start` returns `suspended`, and `waitForRun`
4005
+ * settles on that right away), and skips the `run.started` event's `pending → running` hop. It
4006
+ * counts as in flight for singleton back-pressure and concurrency quotas while it waits.
4007
+ */
4008
+ startAt?: number | Date | undefined;
3972
4009
  }
3973
4010
  /**
3974
4011
  * Serialize runs of a workflow that share a key — a durable, FIFO mutex (e.g. one pipeline per base).
@@ -4283,6 +4320,18 @@ declare class WorkflowEngine {
4283
4320
  private readonly awaitedStepFans;
4284
4321
  /** Step fans whose join barrier this instance opened, by `runId:firstSeq` — see {@link settledHere}. */
4285
4322
  private readonly stepFansFiredHere;
4323
+ /**
4324
+ * The in-process execution gate, by run id: the execution of the run currently in flight in THIS
4325
+ * process (`tail`), and at most one resume queued behind it (`queued`). See {@link resumeRun}.
4326
+ *
4327
+ * The run lease is keyed by engine instance, so it fences OTHER processes only: to the store, a
4328
+ * second execution in this same process holds the very same lease (and {@link execute} skips
4329
+ * `tryLockRun` when its snapshot says this instance holds it). Without this gate, a resume landing
4330
+ * while this process was still executing the run (a signal, a late step result, a child wake, an
4331
+ * explicit `resume()`) went straight past the lease and ran the body concurrently: a
4332
+ * not-yet-checkpointed step executed twice.
4333
+ */
4334
+ private readonly runGates;
4286
4335
  /** The tail of each run's queue of results being handled on this instance — see {@link serializedPerRun}. */
4287
4336
  private readonly resultChains;
4288
4337
  /** Each run's results waiting to be settled on this instance — see {@link completeRemoteResult}. */
@@ -4487,7 +4536,49 @@ declare class WorkflowEngine {
4487
4536
  * stale waiter or a late result left behind by a failed run silently re-executes its body.
4488
4537
  */
4489
4538
  private resumeImplicit;
4539
+ /**
4540
+ * One execution of a run at a time in this process. A resume that lands while the run executes
4541
+ * here neither joins that execution (the double-run) nor no-ops against its held lease (a lost
4542
+ * wake: its checkpoint may postdate the running turn's snapshot): it is QUEUED, and re-drives the
4543
+ * run once the running execution has settled and released its lease, re-reading the run then
4544
+ * (terminal: echoed, never re-executed). Resumes landing while one is already queued coalesce
4545
+ * into it: it has not started yet, so it will observe every write they made. Their callers get
4546
+ * the queued execution's result, i.e. the run's state after their own wake was applied.
4547
+ *
4548
+ * Across processes, exclusion stays the lease's job: {@link execute} still `tryLockRun`s when it
4549
+ * does not hold the lease.
4550
+ */
4490
4551
  private resumeRun;
4552
+ /** Drop `gate` once `tail` settles, unless another execution queued behind it meanwhile. */
4553
+ private closeGateAfter;
4554
+ /**
4555
+ * Release a run's lease AFTER its outcome is decided (persisted, or about to be returned). Best
4556
+ * effort, and that matters most on the failure path: the thing that failed the run is frequently
4557
+ * the very store this release talks to (a step that violated a DB constraint leaves Postgres
4558
+ * refusing every further statement on that connection), so the release throws too. A throwing
4559
+ * release in a `finally` REPLACES the run's real outcome with a lease write nobody asked about,
4560
+ * skips the post-turn re-drives after it, and, for a turn driven as a background resume, surfaces
4561
+ * as an unhandled rejection instead of a failed run.
4562
+ *
4563
+ * Letting it go is safe: the lease expires on its own and `recoverIncomplete` re-drives whatever
4564
+ * is still held. A lost release costs one lease window of latency; a masked error costs the
4565
+ * diagnosis.
4566
+ */
4567
+ private releaseLeaseBestEffort;
4568
+ /**
4569
+ * The run's persisted state as a {@link RunResult}, without executing anything: the answer to a
4570
+ * resume issued from inside the run's own execution, and to a settle whose compare-and-set lost
4571
+ * (the path that won already emitted and notified). A run that is gone reads as `cancelled`, the
4572
+ * safest terminal reading, never a fabricated success.
4573
+ */
4574
+ private echoCurrentStatus;
4575
+ /**
4576
+ * The engine's stand-in for {@link StateStore.updateRunIf} on a store without it, called with the
4577
+ * store as `this`: read-then-write, which narrows the race to the gap between the read and the
4578
+ * write (the pre-CAS behavior, now applied to every settle) but cannot close it.
4579
+ */
4580
+ private updateRunIfFallback;
4581
+ private resumeRunNow;
4491
4582
  /**
4492
4583
  * The registration for an UNREGISTERED run, INHERITED from its nearest REMOTE ancestor — or
4493
4584
  * `undefined` if it has none (the skew-protection error case in {@link resume}). Callers check the
@@ -4616,6 +4707,16 @@ declare class WorkflowEngine {
4616
4707
  * replay from their checkpoints, so only the work that had not finished runs again.
4617
4708
  */
4618
4709
  recoverIncomplete(nowMs?: number): Promise<RunResult[]>;
4710
+ /**
4711
+ * The runs {@link recoverIncomplete} should try to reclaim: incomplete runs whose lease is free or
4712
+ * expired, never the healthy ones a live turn is renewing. Every worker runs recovery on every
4713
+ * timer tick, so listing every running run and lock-probing each (one doomed UPDATE per healthy
4714
+ * run per worker per tick) was pure database load. The store answers it directly when it can
4715
+ * ({@link StateStore.listOrphanedRuns}, bounded by {@link RECOVERY_BATCH}); else the full list is
4716
+ * filtered here, which still spares the probes. Shuffled, like the due-timer pass, so instances
4717
+ * recovering at once spread over the batch instead of contending for the same leases.
4718
+ */
4719
+ private orphanedRuns;
4619
4720
  /**
4620
4721
  * The remote step this run dispatched and is still awaiting a result for, if any — the signature
4621
4722
  * that tells {@link recoverIncomplete} "this run's work is ON THE TRANSPORT, not in a crashed
@@ -6063,6 +6164,12 @@ declare class CodecStateStore implements StateStore {
6063
6164
  /** Forwarded verbatim (deletes touch no payload). Bound only when the inner store has it, so the
6064
6165
  * engine's per-run fallback still kicks in through the wrapper. */
6065
6166
  readonly deleteRuns?: (runIds: string[]) => Promise<void>;
6167
+ /** Decodes the runs like {@link listIncompleteRuns}. Bound only when the inner store has it, so
6168
+ * the engine's list-and-filter fallback still kicks in through the wrapper. */
6169
+ readonly listOrphanedRuns?: (nowMs: number, limit: number, namespace?: string) => Promise<WorkflowRun[]>;
6170
+ /** Encodes the patch like {@link updateRun}. Bound only when the inner store has it, so the
6171
+ * engine's read-then-write fallback still kicks in through the wrapper. */
6172
+ readonly updateRunIf?: (runId: string, expectedStatuses: RunStatus[], patch: Partial<WorkflowRun>) => Promise<boolean>;
6066
6173
  /** Encodes like {@link saveCheckpoint}. Bound only when the inner store has it, so the engine's
6067
6174
  * plain-save fallback still kicks in through the wrapper. */
6068
6175
  readonly saveCheckpointIfPending?: (checkpoint: StepCheckpoint) => Promise<boolean>;
@@ -6112,6 +6219,7 @@ declare class CodecStateStore implements StateStore {
6112
6219
  ensureSchema(): Promise<void>;
6113
6220
  createRun(run: WorkflowRun): Promise<void>;
6114
6221
  updateRun(runId: string, patch: Partial<WorkflowRun>): Promise<void>;
6222
+ private encRunPatch;
6115
6223
  getRun(runId: string): Promise<WorkflowRun | null>;
6116
6224
  deleteRun(runId: string): Promise<void>;
6117
6225
  getCheckpoint(runId: string, seq: number): Promise<StepCheckpoint | null>;
@@ -6551,6 +6659,8 @@ declare class InMemoryStateStore implements StateStore {
6551
6659
  tryAdmitSingleton(runId: string, tag: string, workflow: string, limit: number, retryWakeAt?: number): Promise<boolean>;
6552
6660
  createRun(run: WorkflowRun): Promise<void>;
6553
6661
  updateRun(runId: string, inputPatch: Partial<WorkflowRun>): Promise<void>;
6662
+ updateRunIf(runId: string, expectedStatuses: RunStatus[], patch: Partial<WorkflowRun>): Promise<boolean>;
6663
+ private applyRunPatch;
6554
6664
  getRun(runId: string): Promise<WorkflowRun | null>;
6555
6665
  deleteRun(runId: string): Promise<void>;
6556
6666
  deleteRuns(runIds: string[]): Promise<void>;
@@ -6559,6 +6669,7 @@ declare class InMemoryStateStore implements StateStore {
6559
6669
  saveCheckpoint(checkpoint: StepCheckpoint): Promise<void>;
6560
6670
  saveCheckpointIfPending(checkpoint: StepCheckpoint): Promise<boolean>;
6561
6671
  saveCheckpointsIfPending(checkpoints: StepCheckpoint[]): Promise<boolean[]>;
6672
+ listOrphanedRuns(nowMs: number, limit: number, namespace?: string): Promise<WorkflowRun[]>;
6562
6673
  listIncompleteRuns(namespace?: string): Promise<WorkflowRun[]>;
6563
6674
  listPendingRuns(limit: number, namespace?: string): Promise<WorkflowRun[]>;
6564
6675
  listDueTimers(nowMs: number, namespace?: string, limit?: number): Promise<WorkflowRun[]>;
package/dist/index.d.ts CHANGED
@@ -1169,6 +1169,21 @@ interface StateStore {
1169
1169
  tryAdmitSingleton?(runId: string, tag: string, workflow: string, limit: number, retryWakeAt?: number): Promise<boolean>;
1170
1170
  createRun(run: WorkflowRun): Promise<void>;
1171
1171
  updateRun(runId: string, patch: Partial<WorkflowRun>): Promise<void>;
1172
+ /**
1173
+ * {@link updateRun}, but only if the run's CURRENT status is one of `expectedStatuses`: a
1174
+ * compare-and-set on the status. Resolves whether the patch applied; never throws on a mismatch or
1175
+ * a missing run (both resolve `false`). The engine settles a turn's outcome (completed, failed,
1176
+ * suspended, blocked) through it, so a run that reached `cancelled`/`completed`/`dead` through
1177
+ * another path while the turn executed (an operator's `cancel()`, a timeout sweep, a dead-letter)
1178
+ * is never overwritten by the turn's stale outcome.
1179
+ *
1180
+ * For a SQL store the predicate must be part of the `UPDATE ... WHERE` itself; a read-then-write
1181
+ * in application code reintroduces the race this exists to close.
1182
+ *
1183
+ * Optional: a store that omits it gets the engine's read-then-write fallback, which narrows the
1184
+ * race to the gap between that read and the write but cannot close it.
1185
+ */
1186
+ updateRunIf?(runId: string, expectedStatuses: RunStatus[], patch: Partial<WorkflowRun>): Promise<boolean>;
1172
1187
  getRun(runId: string): Promise<WorkflowRun | null>;
1173
1188
  /**
1174
1189
  * Hard-delete a run and all of its rows — the run plus its checkpoints, signal waiters, and
@@ -1228,6 +1243,16 @@ interface StateStore {
1228
1243
  saveCheckpointsIfPending?(checkpoints: StepCheckpoint[]): Promise<boolean[]>;
1229
1244
  /** Used by recovery on boot to find runs to resume (crashed, left `running`). */
1230
1245
  listIncompleteRuns(namespace?: string): Promise<WorkflowRun[]>;
1246
+ /**
1247
+ * The ORPHANS a periodic recovery pass should reclaim: {@link listIncompleteRuns}'s runs
1248
+ * (`running` or `cancelling`) whose lease is free (`lockedUntil` unset or `<= nowMs`), oldest
1249
+ * (`createdAt`) first, at most `limit`. When `namespace` is given, restricted to that partition.
1250
+ *
1251
+ * Optional but recommended: without it the engine lists every incomplete run and filters the
1252
+ * leases in process, which on a busy fleet reads every healthy running run once per tick per
1253
+ * worker.
1254
+ */
1255
+ listOrphanedRuns?(nowMs: number, limit: number, namespace?: string): Promise<WorkflowRun[]>;
1231
1256
  /** The oldest `pending` runs awaiting dispatch (FIFO, by `createdAt`), capped at `limit`. */
1232
1257
  listPendingRuns(limit: number, namespace?: string): Promise<WorkflowRun[]>;
1233
1258
  /**
@@ -3969,6 +3994,18 @@ interface StartOptions {
3969
3994
  * workflow's registered `concurrency`. See {@link ConcurrencyQuota}.
3970
3995
  */
3971
3996
  concurrency?: ConcurrencyQuota | undefined;
3997
+ /**
3998
+ * Delayed start: don't execute before this time (epoch ms, or a `Date`), compared against the
3999
+ * engine's clock. The run is created `suspended` with its `wakeAt` set to it, which is the same
4000
+ * durable timer a `ctx.sleep` parks on: nothing is held in memory, it survives restarts, and the
4001
+ * timer poller (`resumeDueTimers`) starts it once due, on any instance. A time that is not in the
4002
+ * future starts the run at once, as if it were omitted.
4003
+ *
4004
+ * A delayed run reads `suspended` until it fires (so `start` returns `suspended`, and `waitForRun`
4005
+ * settles on that right away), and skips the `run.started` event's `pending → running` hop. It
4006
+ * counts as in flight for singleton back-pressure and concurrency quotas while it waits.
4007
+ */
4008
+ startAt?: number | Date | undefined;
3972
4009
  }
3973
4010
  /**
3974
4011
  * Serialize runs of a workflow that share a key — a durable, FIFO mutex (e.g. one pipeline per base).
@@ -4283,6 +4320,18 @@ declare class WorkflowEngine {
4283
4320
  private readonly awaitedStepFans;
4284
4321
  /** Step fans whose join barrier this instance opened, by `runId:firstSeq` — see {@link settledHere}. */
4285
4322
  private readonly stepFansFiredHere;
4323
+ /**
4324
+ * The in-process execution gate, by run id: the execution of the run currently in flight in THIS
4325
+ * process (`tail`), and at most one resume queued behind it (`queued`). See {@link resumeRun}.
4326
+ *
4327
+ * The run lease is keyed by engine instance, so it fences OTHER processes only: to the store, a
4328
+ * second execution in this same process holds the very same lease (and {@link execute} skips
4329
+ * `tryLockRun` when its snapshot says this instance holds it). Without this gate, a resume landing
4330
+ * while this process was still executing the run (a signal, a late step result, a child wake, an
4331
+ * explicit `resume()`) went straight past the lease and ran the body concurrently: a
4332
+ * not-yet-checkpointed step executed twice.
4333
+ */
4334
+ private readonly runGates;
4286
4335
  /** The tail of each run's queue of results being handled on this instance — see {@link serializedPerRun}. */
4287
4336
  private readonly resultChains;
4288
4337
  /** Each run's results waiting to be settled on this instance — see {@link completeRemoteResult}. */
@@ -4487,7 +4536,49 @@ declare class WorkflowEngine {
4487
4536
  * stale waiter or a late result left behind by a failed run silently re-executes its body.
4488
4537
  */
4489
4538
  private resumeImplicit;
4539
+ /**
4540
+ * One execution of a run at a time in this process. A resume that lands while the run executes
4541
+ * here neither joins that execution (the double-run) nor no-ops against its held lease (a lost
4542
+ * wake: its checkpoint may postdate the running turn's snapshot): it is QUEUED, and re-drives the
4543
+ * run once the running execution has settled and released its lease, re-reading the run then
4544
+ * (terminal: echoed, never re-executed). Resumes landing while one is already queued coalesce
4545
+ * into it: it has not started yet, so it will observe every write they made. Their callers get
4546
+ * the queued execution's result, i.e. the run's state after their own wake was applied.
4547
+ *
4548
+ * Across processes, exclusion stays the lease's job: {@link execute} still `tryLockRun`s when it
4549
+ * does not hold the lease.
4550
+ */
4490
4551
  private resumeRun;
4552
+ /** Drop `gate` once `tail` settles, unless another execution queued behind it meanwhile. */
4553
+ private closeGateAfter;
4554
+ /**
4555
+ * Release a run's lease AFTER its outcome is decided (persisted, or about to be returned). Best
4556
+ * effort, and that matters most on the failure path: the thing that failed the run is frequently
4557
+ * the very store this release talks to (a step that violated a DB constraint leaves Postgres
4558
+ * refusing every further statement on that connection), so the release throws too. A throwing
4559
+ * release in a `finally` REPLACES the run's real outcome with a lease write nobody asked about,
4560
+ * skips the post-turn re-drives after it, and, for a turn driven as a background resume, surfaces
4561
+ * as an unhandled rejection instead of a failed run.
4562
+ *
4563
+ * Letting it go is safe: the lease expires on its own and `recoverIncomplete` re-drives whatever
4564
+ * is still held. A lost release costs one lease window of latency; a masked error costs the
4565
+ * diagnosis.
4566
+ */
4567
+ private releaseLeaseBestEffort;
4568
+ /**
4569
+ * The run's persisted state as a {@link RunResult}, without executing anything: the answer to a
4570
+ * resume issued from inside the run's own execution, and to a settle whose compare-and-set lost
4571
+ * (the path that won already emitted and notified). A run that is gone reads as `cancelled`, the
4572
+ * safest terminal reading, never a fabricated success.
4573
+ */
4574
+ private echoCurrentStatus;
4575
+ /**
4576
+ * The engine's stand-in for {@link StateStore.updateRunIf} on a store without it, called with the
4577
+ * store as `this`: read-then-write, which narrows the race to the gap between the read and the
4578
+ * write (the pre-CAS behavior, now applied to every settle) but cannot close it.
4579
+ */
4580
+ private updateRunIfFallback;
4581
+ private resumeRunNow;
4491
4582
  /**
4492
4583
  * The registration for an UNREGISTERED run, INHERITED from its nearest REMOTE ancestor — or
4493
4584
  * `undefined` if it has none (the skew-protection error case in {@link resume}). Callers check the
@@ -4616,6 +4707,16 @@ declare class WorkflowEngine {
4616
4707
  * replay from their checkpoints, so only the work that had not finished runs again.
4617
4708
  */
4618
4709
  recoverIncomplete(nowMs?: number): Promise<RunResult[]>;
4710
+ /**
4711
+ * The runs {@link recoverIncomplete} should try to reclaim: incomplete runs whose lease is free or
4712
+ * expired, never the healthy ones a live turn is renewing. Every worker runs recovery on every
4713
+ * timer tick, so listing every running run and lock-probing each (one doomed UPDATE per healthy
4714
+ * run per worker per tick) was pure database load. The store answers it directly when it can
4715
+ * ({@link StateStore.listOrphanedRuns}, bounded by {@link RECOVERY_BATCH}); else the full list is
4716
+ * filtered here, which still spares the probes. Shuffled, like the due-timer pass, so instances
4717
+ * recovering at once spread over the batch instead of contending for the same leases.
4718
+ */
4719
+ private orphanedRuns;
4619
4720
  /**
4620
4721
  * The remote step this run dispatched and is still awaiting a result for, if any — the signature
4621
4722
  * that tells {@link recoverIncomplete} "this run's work is ON THE TRANSPORT, not in a crashed
@@ -6063,6 +6164,12 @@ declare class CodecStateStore implements StateStore {
6063
6164
  /** Forwarded verbatim (deletes touch no payload). Bound only when the inner store has it, so the
6064
6165
  * engine's per-run fallback still kicks in through the wrapper. */
6065
6166
  readonly deleteRuns?: (runIds: string[]) => Promise<void>;
6167
+ /** Decodes the runs like {@link listIncompleteRuns}. Bound only when the inner store has it, so
6168
+ * the engine's list-and-filter fallback still kicks in through the wrapper. */
6169
+ readonly listOrphanedRuns?: (nowMs: number, limit: number, namespace?: string) => Promise<WorkflowRun[]>;
6170
+ /** Encodes the patch like {@link updateRun}. Bound only when the inner store has it, so the
6171
+ * engine's read-then-write fallback still kicks in through the wrapper. */
6172
+ readonly updateRunIf?: (runId: string, expectedStatuses: RunStatus[], patch: Partial<WorkflowRun>) => Promise<boolean>;
6066
6173
  /** Encodes like {@link saveCheckpoint}. Bound only when the inner store has it, so the engine's
6067
6174
  * plain-save fallback still kicks in through the wrapper. */
6068
6175
  readonly saveCheckpointIfPending?: (checkpoint: StepCheckpoint) => Promise<boolean>;
@@ -6112,6 +6219,7 @@ declare class CodecStateStore implements StateStore {
6112
6219
  ensureSchema(): Promise<void>;
6113
6220
  createRun(run: WorkflowRun): Promise<void>;
6114
6221
  updateRun(runId: string, patch: Partial<WorkflowRun>): Promise<void>;
6222
+ private encRunPatch;
6115
6223
  getRun(runId: string): Promise<WorkflowRun | null>;
6116
6224
  deleteRun(runId: string): Promise<void>;
6117
6225
  getCheckpoint(runId: string, seq: number): Promise<StepCheckpoint | null>;
@@ -6551,6 +6659,8 @@ declare class InMemoryStateStore implements StateStore {
6551
6659
  tryAdmitSingleton(runId: string, tag: string, workflow: string, limit: number, retryWakeAt?: number): Promise<boolean>;
6552
6660
  createRun(run: WorkflowRun): Promise<void>;
6553
6661
  updateRun(runId: string, inputPatch: Partial<WorkflowRun>): Promise<void>;
6662
+ updateRunIf(runId: string, expectedStatuses: RunStatus[], patch: Partial<WorkflowRun>): Promise<boolean>;
6663
+ private applyRunPatch;
6554
6664
  getRun(runId: string): Promise<WorkflowRun | null>;
6555
6665
  deleteRun(runId: string): Promise<void>;
6556
6666
  deleteRuns(runIds: string[]): Promise<void>;
@@ -6559,6 +6669,7 @@ declare class InMemoryStateStore implements StateStore {
6559
6669
  saveCheckpoint(checkpoint: StepCheckpoint): Promise<void>;
6560
6670
  saveCheckpointIfPending(checkpoint: StepCheckpoint): Promise<boolean>;
6561
6671
  saveCheckpointsIfPending(checkpoints: StepCheckpoint[]): Promise<boolean[]>;
6672
+ listOrphanedRuns(nowMs: number, limit: number, namespace?: string): Promise<WorkflowRun[]>;
6562
6673
  listIncompleteRuns(namespace?: string): Promise<WorkflowRun[]>;
6563
6674
  listPendingRuns(limit: number, namespace?: string): Promise<WorkflowRun[]>;
6564
6675
  listDueTimers(nowMs: number, namespace?: string, limit?: number): Promise<WorkflowRun[]>;