@dudousxd/nestjs-durable-core 0.77.0 → 0.79.0

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
@@ -195,6 +195,16 @@ interface WorkflowRegistration {
195
195
  /** The package that DECLARED the workflow (see `WorkflowRun.origin`). Absent = unknown; nothing
196
196
  * ever substitutes a default, because a wrong origin is worse than no origin. */
197
197
  origin?: string;
198
+ /**
199
+ * Where the engine routes a failed run of this workflow, by error `code` (`code` absent = the
200
+ * catch-all): the handler workflow it starts instead of failing the run. The one announced field
201
+ * the engine ACTS on, for a workflow it serves by convention rather than by local registration.
202
+ * Absent = not stated, which routes nothing.
203
+ */
204
+ onError?: {
205
+ code?: string;
206
+ workflow: string;
207
+ }[];
198
208
  }
199
209
  /**
200
210
  * A worker's (or control-plane's) advertised identity, wire-protocol support, feature capabilities
@@ -474,6 +484,230 @@ declare class WorkflowBlocked extends Error {
474
484
  */
475
485
  declare function planDispatch(requires: string[], liveDescriptors: readonly (RawWorkerDescriptor | WorkerDescriptor)[], cp: WorkerDescriptor, token: string): DispatchPlan;
476
486
 
487
+ /**
488
+ * A parallel fan (a `ctx.all`, a step fan, a polyglot `gather`) reduced to what a detail view needs
489
+ * to draw it: one node, its progress and its failures. A run detail with a 40,000-item fan otherwise
490
+ * carries every member — megabytes of JSON, and one rendered row (or fetched child) per member.
491
+ */
492
+ interface FanSummary {
493
+ /** The fan's `parallelGroup`. */
494
+ group: string;
495
+ /** The members' common step name, or `child runs` for a fan of child workflows. */
496
+ label: string;
497
+ firstSeq: number;
498
+ lastSeq: number;
499
+ /** Members started so far: steps, or child runs (a folded checkpoint counts as the children it stands for). */
500
+ size: number;
501
+ /**
502
+ * The fan's declared size, when its group carries it. More than `size` while waves are still to
503
+ * be sent (`concurrency`), and for good when a failFast fan stopped early.
504
+ */
505
+ total?: number | undefined;
506
+ /** `total - size`: members never started yet — or never to start, once the run has finished. */
507
+ notStarted?: number | undefined;
508
+ /** The fan stops at its first failure. */
509
+ failFast: boolean;
510
+ /** Members by status. A child that failed counts as `failed`, though its checkpoint is `completed`. */
511
+ counts: Partial<Record<StepCheckpoint['status'], number>>;
512
+ startedAt?: Date | undefined;
513
+ finishedAt?: Date | undefined;
514
+ /** The first {@link FAN_SUMMARY_FAILURES} failed members, so a failure shows without paging. */
515
+ failures: StepCheckpoint[];
516
+ }
517
+ /** A page of one fan's members, in seq order. */
518
+ interface FanPage {
519
+ items: StepCheckpoint[];
520
+ /** Members matching the query, across all pages. */
521
+ total: number;
522
+ /** A validator for this page, when the gateway can compute one without reading the members. */
523
+ etag?: string | undefined;
524
+ /**
525
+ * Set when the query's `ifNoneMatch` matched {@link etag}: the page has not changed, so nothing
526
+ * was read. `items` is empty and `total` is 0 as placeholders, not the fan's; keep the page the
527
+ * caller already holds.
528
+ */
529
+ notModified?: true | undefined;
530
+ }
531
+ interface FanPageQuery {
532
+ offset?: number | undefined;
533
+ limit?: number | undefined;
534
+ /** Only failed members (a failed step, or a child that failed). */
535
+ failedOnly?: boolean | undefined;
536
+ /** An HTTP `If-None-Match` value: a page whose `etag` it names comes back `notModified`. */
537
+ ifNoneMatch?: string | undefined;
538
+ }
539
+ declare const FAN_SUMMARY_FAILURES = 20;
540
+ /** The most children a summarized detail lists by id; `childCount` carries the rest. */
541
+ declare const SUMMARY_CHILD_LIMIT = 200;
542
+ /** How many children a folded `fan:` checkpoint stands for; undefined for any other checkpoint. */
543
+ declare function foldedCount(cp: StepCheckpoint): number | undefined;
544
+ /** A failed member: a failed step, or a child whose completion reports `ok: false`. */
545
+ declare function isFailedMember(cp: StepCheckpoint): boolean;
546
+ /** Summarize one fan's members (in seq order). */
547
+ declare function summarizeFan(group: string, members: StepCheckpoint[]): FanSummary;
548
+ /**
549
+ * Split a run's timeline into the checkpoints a detail view lists one by one and the fans it draws as
550
+ * one node each: every `parallelGroup` with more than `over` members, or declared wider than that,
551
+ * becomes a {@link FanSummary}, and its members leave the timeline. Smaller groups and ungrouped steps stay as they are.
552
+ */
553
+ declare function summarizeTimeline(timeline: StepCheckpoint[], over: number): {
554
+ timeline: StepCheckpoint[];
555
+ fans: FanSummary[];
556
+ };
557
+ /** One page of a fan's members out of a run's timeline. */
558
+ declare function pageFan(timeline: StepCheckpoint[], group: string, query: FanPageQuery): FanPage;
559
+ /** A {@link FanPageQuery}'s offset and limit, clamped to sane bounds. */
560
+ declare function fanPageBounds(query: FanPageQuery): {
561
+ offset: number;
562
+ limit: number;
563
+ };
564
+
565
+ /** A run as returned by the gateway's list — the durable run plus an optional {@link RunWaiting}
566
+ * descriptor the control plane resolves (what a suspended run is parked on), so the dashboard can
567
+ * name the wait in a list row without fetching each run's timeline. Additive: `waiting` is absent
568
+ * on a non-parked run and on gateways/versions that don't compute it. */
569
+ type RunListItem = WorkflowRun & {
570
+ waiting?: RunWaiting | undefined;
571
+ };
572
+ /** Which durable topology a gateway speaks for — surfaced in the dashboard so an operator can tell a
573
+ * control plane from a tenant at a glance (the store-backed gateway is the operator; the proxy is a
574
+ * tenant). Cheap, synchronous, local knowledge — no round-trip. */
575
+ interface DurableTopology {
576
+ role: 'control-plane' | 'tenant';
577
+ /** The tenant's isolation partition name; set only when `role` is 'tenant'. */
578
+ tenant?: string;
579
+ }
580
+ /** A run + its timeline + child ids — the detail view. Single source of truth: the dashboard server
581
+ * re-exports this instead of re-declaring it, and the dashboard client derives its wire mirror from
582
+ * it via {@link WireDates} instead of hand-mirroring field by field. */
583
+ interface RunDetail {
584
+ run: WorkflowRun;
585
+ /**
586
+ * Steps in execution order (local + remote). With {@link RunDetailOptions.summarizeFansOver}, the
587
+ * members of a summarized fan are left out — see {@link fans}.
588
+ */
589
+ timeline: StepCheckpoint[];
590
+ /** Ids of runs this run spawned (parent→children tree). Capped when summarized — see {@link childCount}. */
591
+ children: string[];
592
+ /** The fans drawn as one node each, when the detail was asked to summarize them. */
593
+ fans?: FanSummary[] | undefined;
594
+ /** How many children the run has, when `children` lists only the first of them. */
595
+ childCount?: number | undefined;
596
+ /**
597
+ * A validator for this detail, when the gateway can compute one without reading the timeline:
598
+ * it changes whenever the run or any of its checkpoints does. Absent when it cannot.
599
+ */
600
+ etag?: string | undefined;
601
+ /**
602
+ * Set when {@link RunDetailOptions.ifNoneMatch} matched {@link etag}: nothing changed, so only
603
+ * `run` was read — `timeline` and `children` are empty, not the run's.
604
+ */
605
+ notModified?: true | undefined;
606
+ }
607
+ /** How to shape a {@link RunDetail}. */
608
+ interface RunDetailOptions {
609
+ /**
610
+ * Summarize every fan with more than this many members into a {@link FanSummary} instead of
611
+ * listing them, and cap `children`. Unset returns the full timeline, as before. A view of a run
612
+ * with a wide fan should set it: the full detail of a 40k-member fan is megabytes.
613
+ */
614
+ summarizeFansOver?: number | undefined;
615
+ /**
616
+ * An HTTP `If-None-Match` value. When it names the detail's current {@link RunDetail.etag}, the
617
+ * gateway answers `notModified` without reading the timeline. A gateway that cannot tell ignores it.
618
+ */
619
+ ifNoneMatch?: string | undefined;
620
+ }
621
+ /**
622
+ * Maps every `Date` (and `Date | undefined`) field of `T` to its ISO-string wire form — the shape a
623
+ * JSON response actually carries once dates cross the wire (`JSON.stringify` already does this
624
+ * coercion; this just types it). Homomorphic: each field keeps its own optional modifier, so a
625
+ * required `Date` becomes a required `string` and an optional one stays optional. Lets a consumer
626
+ * derive its own wire-facing client type from a core server type (e.g. the dashboard's SPA `WorkflowRun`/
627
+ * `StepCheckpoint`/`RunDetail`) instead of hand-mirroring it field by field and drifting.
628
+ */
629
+ type WireDates<T> = {
630
+ [K in keyof T]: T[K] extends Date ? string : T[K] extends Date | undefined ? string | undefined : T[K];
631
+ };
632
+ /**
633
+ * The bounded read/control/stream surface a consumer (e.g. a controller) needs, satisfied by BOTH
634
+ * topologies: the control plane binds a store-backed impl (reuses `DashboardService`); a tenant binds
635
+ * a `ProxyRunGateway` that round-trips over the transport. Deliberately smaller than the full dashboard
636
+ * (no metrics/bulk/update/signal) — those stay control-plane-only. `workerHealth` IS on the port: the
637
+ * operator answers it scoped to the requester's own groups, so a tenant's Workers panel works too.
638
+ *
639
+ * Declared as an **abstract class** rather than an interface so it doubles as its own NestJS DI token
640
+ * (the idiomatic inject-by-type pattern): providers bind `{ provide: RunGateway, useClass/useFactory }`
641
+ * and consumers inject `constructor(private readonly gateway: RunGateway)` with no string/symbol token.
642
+ * `StoreRunGateway`/`ProxyRunGateway` `implements RunGateway`; abstract methods carry no body, so the
643
+ * emitted runtime class is an empty, non-instantiable shell used only as the token.
644
+ */
645
+ declare abstract class RunGateway {
646
+ /** This deployment's durable role (control plane vs tenant) — synchronous local metadata. */
647
+ abstract topology(): DurableTopology;
648
+ abstract getRunDetail(runId: string, options?: RunDetailOptions): Promise<RunDetail | null>;
649
+ /**
650
+ * One page of a fan's members, for a view that drew the fan from its {@link FanSummary}. Optional:
651
+ * a gateway without it serves summarized details whose fans cannot be expanded.
652
+ */
653
+ getFanMembers?(runId: string, group: string, query: FanPageQuery): Promise<FanPage | null>;
654
+ /**
655
+ * The run alone, without its timeline. Optional: a caller that only needs the run (an ownership
656
+ * check) falls back to {@link getRunDetail}, which reads every checkpoint.
657
+ */
658
+ getRun?(runId: string): Promise<WorkflowRun | null>;
659
+ /** List runs, each optionally carrying a {@link RunWaiting} descriptor (what a suspended run is
660
+ * parked on). The store-backed gateway resolves `waiting`; a proxy relays whatever the control
661
+ * plane sent. */
662
+ abstract listRuns(query: RunQuery): Promise<RunListItem[]>;
663
+ /**
664
+ * Counts of the runs matching `query`, grouped by `(status, origin)` — what a console's status and
665
+ * origin chips display. Separate from {@link listRuns} precisely so the list can be PAGINATED: the
666
+ * page bounds what is rendered, these counts stay whole-set exact. Zero-count cells are absent.
667
+ */
668
+ abstract runFacets(query: RunFacetQuery): Promise<RunFacetRow[]>;
669
+ /**
670
+ * The distinct values of one filter axis over the runs matching `query`, with counts — what fills a
671
+ * console's tenant/tag/attribute pickers. On the port (not control-plane-only) because the pickers
672
+ * belong to the same panel as {@link listRuns}: a tenant that can list its runs has to be able to
673
+ * see what it may filter them by, or its console offers a blank dropdown.
674
+ *
675
+ * Returns `[]` when the underlying store does not implement the enumeration — an empty picker with
676
+ * free-text entry still standing, not an error.
677
+ */
678
+ abstract runValueFacets(axis: RunValueAxis, query: RunFacetQuery, opts?: RunValueFacetOptions): Promise<RunValueFacetRow[]>;
679
+ /**
680
+ * Bulk-resolve {@link RunWaiting} for an arbitrary set of run ids — for a consumer with its OWN
681
+ * filtered/paginated run listing (so it isn't just `listRuns` under another name) that needs to know
682
+ * which of ITS runs are parked on a breakpoint (or any other event wait) without re-deriving the bulk
683
+ * waiter scan itself or reaching for raw SQL against `durable_step_checkpoints`. A `Record` (not a
684
+ * `Map`) because `ProxyRunGateway` serialises the reply over the transport as plain JSON. Entries are
685
+ * present ONLY for runs currently waiting — an unknown id, a non-suspended id, and a suspended id
686
+ * parked on something non-event (a bare `ctx.sleep`, an in-flight step) are simply absent, same as a
687
+ * `listRuns` row with no `waiting`.
688
+ */
689
+ abstract waitingFor(runIds: string[]): Promise<Record<string, RunWaiting>>;
690
+ /** Per-group worker health (queue backlog + live worker heartbeats). On the control plane this is
691
+ * every group; over a tenant proxy the operator scopes it to the tenant's own groups. */
692
+ abstract workerHealth(): Promise<GroupHealth[]>;
693
+ abstract cancel(runId: string, opts?: {
694
+ compensate?: boolean;
695
+ }): Promise<RunResult | null>;
696
+ abstract retry(runId: string): Promise<RunResult | null>;
697
+ abstract continue(runId: string): Promise<RunResult | null>;
698
+ /** Re-dispatch every remote step of a run stuck `pending` — the operator recovery for a LOST step
699
+ * dispatch (crashed worker / dropped job) that no automatic path re-drives. Returns the run's status
700
+ * plus how many steps were re-dispatched, or null if the run is unknown. */
701
+ abstract redispatchPending(runId: string): Promise<(RunResult & {
702
+ redispatched: number;
703
+ }) | null>;
704
+ abstract retryWithInput(runId: string, input: unknown): Promise<{
705
+ runId: string;
706
+ } | null>;
707
+ /** Live lifecycle events for one run; returns an unsubscribe fn. Framework-agnostic (no rxjs). */
708
+ abstract subscribe(runId: string, onEvent: (event: EngineEvent) => void): () => void;
709
+ }
710
+
477
711
  /**
478
712
  * Vendored subset of the Standard Schema spec (https://standardschema.dev) — the `~standard`
479
713
  * property protocol implemented by zod 3.24+, valibot, arktype, and others. Vendored (rather than
@@ -909,6 +1143,9 @@ interface StepError {
909
1143
  message: string;
910
1144
  /** Optional machine-readable code, e.g. `declined`, `timeout`. */
911
1145
  code?: string | undefined;
1146
+ /** Structured, JSON-serializable detail of the failure (e.g. validation issues), from
1147
+ * `FatalError`'s third argument or a `details` on what a step handler threw. */
1148
+ details?: unknown;
912
1149
  /** Whether the engine should treat this as retryable. */
913
1150
  retryable?: boolean | undefined;
914
1151
  stack?: string | undefined;
@@ -979,6 +1216,16 @@ interface StateStore {
979
1216
  * Optional: a store that omits it falls back to {@link saveCheckpoint}, which keeps that race.
980
1217
  */
981
1218
  saveCheckpointIfPending?(checkpoint: StepCheckpoint): Promise<boolean>;
1219
+ /**
1220
+ * {@link saveCheckpointIfPending} for many checkpoints in one call: resolves, per entry and in
1221
+ * input order, whether it wrote. Same result as calling it on each entry in turn (a later entry for
1222
+ * the same `(runId, seq)` is compared against the earlier one's write), with each row's
1223
+ * compare-and-set still atomic. The call as a whole is atomic too: if it rejects, nothing was
1224
+ * written. The engine settles a batch of one run's step results through it, one call per batch.
1225
+ *
1226
+ * Optional: a store that omits it gets one {@link saveCheckpointIfPending} per entry.
1227
+ */
1228
+ saveCheckpointsIfPending?(checkpoints: StepCheckpoint[]): Promise<boolean[]>;
982
1229
  /** Used by recovery on boot to find runs to resume (crashed, left `running`). */
983
1230
  listIncompleteRuns(namespace?: string): Promise<WorkflowRun[]>;
984
1231
  /** The oldest `pending` runs awaiting dispatch (FIFO, by `createdAt`), capped at `limit`. */
@@ -1188,6 +1435,72 @@ interface StateStore {
1188
1435
  * and counts in JS, which loads the whole run on every result of a fan.
1189
1436
  */
1190
1437
  countCheckpoints?(runId: string, fromSeq: number, toSeq: number, statuses: StepCheckpoint['status'][]): Promise<number>;
1438
+ /**
1439
+ * The run's checkpoints aggregated into {@link CheckpointStat} buckets — one per
1440
+ * `(parallelGroup, status, nameKind)` present — with `opts.group` narrowing it to one group. A
1441
+ * `GROUP BY`, not a load: it is what lets a run detail draw a 40,000-member fan from a few rows.
1442
+ * Ungrouped checkpoints come back under `group: null`. Bucket order is unspecified.
1443
+ *
1444
+ * Optional: a store that omits it still works — the console's run detail then loads every
1445
+ * checkpoint and summarizes it in JS (`summarizeTimeline`), which is the same answer read the
1446
+ * expensive way. A store that implements it must implement {@link queryCheckpoints} too.
1447
+ */
1448
+ checkpointStats?(runId: string, opts?: {
1449
+ group?: string | undefined;
1450
+ }): Promise<CheckpointStat[]>;
1451
+ /**
1452
+ * The run's checkpoints that match `query`, in `seq` order (the order of {@link listCheckpoints}),
1453
+ * paged by `offset`/`limit`. Every filter is optional; an absent one does not narrow. An EMPTY
1454
+ * `statuses` or `namePrefixes` matches nothing; an empty `excludeGroups` excludes nothing.
1455
+ *
1456
+ * Optional, paired with {@link checkpointStats}: the run detail reads a fan's failures, its folded
1457
+ * checkpoints and one page of its members through it, instead of the run's whole history.
1458
+ */
1459
+ queryCheckpoints?(runId: string, query: CheckpointQuery): Promise<StepCheckpoint[]>;
1460
+ }
1461
+ /**
1462
+ * How a checkpoint's name classifies it, for {@link CheckpointStat}: an awaited child's
1463
+ * `signal:child:` checkpoint, a folded `fan:` checkpoint standing for many children, a `spawn:`
1464
+ * edge to a fire-and-forget child, or any other step.
1465
+ */
1466
+ type CheckpointNameKind = 'child' | 'folded' | 'spawn' | 'step';
1467
+ /** The {@link CheckpointNameKind} of a checkpoint name — what a store's SQL `CASE` must agree with. */
1468
+ declare function checkpointNameKind(name: string): CheckpointNameKind;
1469
+ /**
1470
+ * One bucket of {@link StateStore.checkpointStats}: the checkpoints of one run sharing a
1471
+ * `parallelGroup`, a `status` and a {@link CheckpointNameKind}, reduced to aggregates.
1472
+ */
1473
+ interface CheckpointStat {
1474
+ /** The bucket's `parallelGroup`, or `null` for ungrouped checkpoints. */
1475
+ group: string | null;
1476
+ status: StepCheckpoint['status'];
1477
+ nameKind: CheckpointNameKind;
1478
+ /** Rows in the bucket (at least 1). */
1479
+ count: number;
1480
+ minSeq: number;
1481
+ maxSeq: number;
1482
+ /** Smallest and largest `name`, by the database's string order. Equal when every row shares one. */
1483
+ minName: string;
1484
+ maxName: string;
1485
+ /** Earliest `enqueuedAt`, read as {@link StateStore.listCheckpoints} reads it (falling back to `startedAt`). */
1486
+ minEnqueuedAt: Date;
1487
+ minStartedAt: Date;
1488
+ maxStartedAt: Date;
1489
+ maxFinishedAt: Date;
1490
+ /** Sum of `attempts` — moves when a step is retried in place, so a change marker sees it. */
1491
+ sumAttempts: number;
1492
+ }
1493
+ /** What {@link StateStore.queryCheckpoints} selects. */
1494
+ interface CheckpointQuery {
1495
+ /** Only this `parallelGroup`'s checkpoints. */
1496
+ group?: string | undefined;
1497
+ /** Leave out these groups' checkpoints (ungrouped checkpoints are kept). */
1498
+ excludeGroups?: string[] | undefined;
1499
+ statuses?: StepCheckpoint['status'][] | undefined;
1500
+ /** Only names starting with one of these. */
1501
+ namePrefixes?: string[] | undefined;
1502
+ offset?: number | undefined;
1503
+ limit?: number | undefined;
1191
1504
  }
1192
1505
  /**
1193
1506
  * A persisted schedule as the STORE sees it: a handful of queryable columns plus two JSON documents
@@ -1513,6 +1826,26 @@ interface AllStepsOptions extends Omit<StepDispatchOpts, 'queue' | 'timeoutMs'>
1513
1826
  */
1514
1827
  concurrency?: number;
1515
1828
  }
1829
+ /** Options for {@link WorkflowCtx.allSettled} over child workflows: {@link AllOptions} without `mode`. */
1830
+ type AllSettledOptions = Omit<AllOptions, 'mode'>;
1831
+ /** Options for {@link WorkflowCtx.allSettled} over a `@Step`: {@link AllStepsOptions} without `mode`. */
1832
+ type AllStepsSettledOptions = Omit<AllStepsOptions, 'mode'>;
1833
+ /**
1834
+ * One item of a {@link WorkflowCtx.allSettled} fan, in input order. `id` is the child run id (child
1835
+ * fan) or the step id (step fan); `error` is the failure message the child or step settled with.
1836
+ */
1837
+ type Settled<T> = {
1838
+ status: 'fulfilled';
1839
+ value: T;
1840
+ } | {
1841
+ status: 'rejected';
1842
+ id: string;
1843
+ error: string;
1844
+ /** The failure's `code` (e.g. a `FatalError`'s), so a parent can tell its kinds apart. */
1845
+ code?: string | undefined;
1846
+ /** The failure's structured `details`, when it carried any. */
1847
+ details?: unknown;
1848
+ };
1516
1849
  /** One child of a fan as {@link StateStore.registerChildWaits} writes it. */
1517
1850
  interface ChildWait {
1518
1851
  waiter: SignalWaiter;
@@ -1569,6 +1902,12 @@ interface RunRequest {
1569
1902
  type RunRequestKind = {
1570
1903
  kind: 'getRunDetail';
1571
1904
  runId: string;
1905
+ options?: RunDetailOptions | undefined;
1906
+ } | {
1907
+ kind: 'getFanMembers';
1908
+ runId: string;
1909
+ group: string;
1910
+ query: FanPageQuery;
1572
1911
  } | {
1573
1912
  kind: 'listRuns';
1574
1913
  query: RunQuery;
@@ -2397,6 +2736,17 @@ interface WorkflowCtx<A extends SearchAttributes = SearchAttributes> {
2397
2736
  */
2398
2737
  all<TInput, TOutput>(step: StepRef<TInput, TOutput>, inputs: TInput[], opts?: AllStepsOptions): Promise<TOutput[]>;
2399
2738
  all<TOutput = unknown>(workflow: string, inputs: unknown[], opts?: AllOptions): Promise<TOutput[]>;
2739
+ /**
2740
+ * {@link all} that never throws for a failed item: waits for every child (or step) to settle, then
2741
+ * resolves with one {@link Settled} per input, in **input order** — the durable
2742
+ * `Promise.allSettled`. Same fan as `all` in `waitAll` mode (ids, `parallelGroup`, `concurrency`
2743
+ * waves, one parent turn per settled wave); only the ending differs. Use it when one item failing
2744
+ * is an expected outcome the parent handles (record it, dead-letter it) rather than a reason to
2745
+ * fail the whole run. Cancelling the parent still propagates.
2746
+ */
2747
+ allSettled<C extends WorkflowClass>(workflow: C, inputs: WorkflowInputOf<C>[], opts?: AllSettledOptions): Promise<Settled<WorkflowOutputOf<C>>[]>;
2748
+ allSettled<TInput, TOutput>(step: StepRef<TInput, TOutput>, inputs: TInput[], opts?: AllStepsSettledOptions): Promise<Settled<TOutput>[]>;
2749
+ allSettled<TOutput = unknown>(workflow: string, inputs: unknown[], opts?: AllSettledOptions): Promise<Settled<TOutput>[]>;
2400
2750
  /**
2401
2751
  * Pause the run at this point until a human resumes it from the dashboard (or
2402
2752
  * `engine.continue(runId)`). Records a visible `pending` checkpoint so the breakpoint shows up
@@ -2489,8 +2839,8 @@ interface WorkflowCtx<A extends SearchAttributes = SearchAttributes> {
2489
2839
  localStep<TOutput>(name: string, fn: (log: StepLogger) => Promise<TOutput>, options?: StepOptions): Promise<TOutput>;
2490
2840
  }
2491
2841
  /**
2492
- * {@link WorkflowCtx} with ONE signature per method: the string-addressed forms of the four overloaded
2493
- * methods (`step`, `child`, `startChild`, `all`), everything else unchanged.
2842
+ * {@link WorkflowCtx} with ONE signature per method: the string-addressed forms of the five overloaded
2843
+ * methods (`step`, `child`, `startChild`, `all`, `allSettled`), everything else unchanged.
2494
2844
  *
2495
2845
  * For code that drives the ctx DYNAMICALLY — an interpreter that runs a user-defined graph and only
2496
2846
  * ever knows workflow/step names as strings — and for test fakes. An overloaded method is awkward to
@@ -2509,7 +2859,7 @@ interface WorkflowCtx<A extends SearchAttributes = SearchAttributes> {
2509
2859
  * Every `WorkflowCtx<A>` is assignable to `DynamicWorkflowCtx<A>` (guarded by
2510
2860
  * `dynamic-workflow-ctx.type-test.ts`), and a `Pick` of it is a plain object literal in a test.
2511
2861
  */
2512
- interface DynamicWorkflowCtx<A extends SearchAttributes = SearchAttributes> extends Omit<WorkflowCtx<A>, 'step' | 'child' | 'startChild' | 'all'> {
2862
+ interface DynamicWorkflowCtx<A extends SearchAttributes = SearchAttributes> extends Omit<WorkflowCtx<A>, 'step' | 'child' | 'startChild' | 'all' | 'allSettled'> {
2513
2863
  /** {@link WorkflowCtx.step} by step name (a cross-runtime handler, or a `@Step` by its name). */
2514
2864
  step<TOutput = unknown, TInput = unknown>(name: string, input: TInput, opts?: StepDispatchOpts & {
2515
2865
  compensate?: string;
@@ -2520,6 +2870,8 @@ interface DynamicWorkflowCtx<A extends SearchAttributes = SearchAttributes> exte
2520
2870
  startChild(workflow: string, input: unknown, options?: string | ChildCallOptions): Promise<string>;
2521
2871
  /** {@link WorkflowCtx.all} by workflow name. */
2522
2872
  all<TOutput = unknown>(workflow: string, inputs: unknown[], opts?: AllOptions): Promise<TOutput[]>;
2873
+ /** {@link WorkflowCtx.allSettled} by workflow name. */
2874
+ allSettled<TOutput = unknown>(workflow: string, inputs: unknown[], opts?: AllSettledOptions): Promise<Settled<TOutput>[]>;
2523
2875
  }
2524
2876
  /** Result of executing or resuming a workflow run. */
2525
2877
  interface RunResult {
@@ -2542,7 +2894,7 @@ type UpdateResult = {
2542
2894
  accepted: true;
2543
2895
  run: RunResult | null;
2544
2896
  };
2545
- type EngineEventType = 'run.started' | 'run.completed' | 'run.failed' | 'run.suspended' | 'step.started' | 'step.completed' | 'step.failed' | 'step.progress' | 'run.blocked';
2897
+ type EngineEventType = 'run.started' | 'run.completed' | 'run.failed' | 'run.suspended' | 'step.started' | 'step.completed' | 'step.failed' | 'step.progress' | 'run.blocked' | 'run.routed' | 'run.unrouted';
2546
2898
  /**
2547
2899
  * A lifecycle event emitted by the engine. The observability surfaces (dashboard, OTel, the
2548
2900
  * Telescope integration) all subscribe to these rather than reaching into the store.
@@ -2582,6 +2934,8 @@ interface EngineEvent {
2582
2934
  * gap fired, how many live workers were considered, and both descriptors — enough for the health
2583
2935
  * panel/telescope to render the reason. Absent on all other event types. */
2584
2936
  diagnostics?: DispatchDiagnostics | undefined;
2937
+ /** Why a `run.unrouted` run's onError routes were not applied. */
2938
+ reason?: string | undefined;
2585
2939
  at: Date;
2586
2940
  }
2587
2941
  type EngineListener = (event: EngineEvent) => void;
@@ -2982,7 +3336,7 @@ interface WorkflowAnnouncement extends WorkflowRegistration {
2982
3336
  /** An axis on which the live announcers of one workflow do not agree. `values` holds every distinct
2983
3337
  * DECLARED value (sorted); an announcer that stated nothing on the axis contributes nothing. */
2984
3338
  interface Disagreement {
2985
- axis: 'group' | 'origin' | 'requires';
3339
+ axis: 'group' | 'origin' | 'requires' | 'onError';
2986
3340
  values: string[];
2987
3341
  }
2988
3342
  /**
@@ -3018,6 +3372,12 @@ interface AnnouncedWorkflow {
3018
3372
  /** Every distinct capability demand announced, each de-duplicated + sorted. Empty = nobody stated
3019
3373
  * one. Two entries here means two workers demand different capabilities for the same version. */
3020
3374
  requires: string[][];
3375
+ /** Every distinct set of `onError` routes announced, each in canonical order. Empty = nobody stated
3376
+ * one. Two entries here means the live workers route this workflow's failures differently. */
3377
+ onError: {
3378
+ code?: string;
3379
+ workflow: string;
3380
+ }[][];
3021
3381
  /** Runtimes of the live announcers (sorted, de-duplicated). EMPTY on an `'observed'` entry: a
3022
3382
  * heartbeat does not say what runtime wrote it, and the instance id's shape is a convention, not
3023
3383
  * a statement, so it is not read as one. */
@@ -3331,6 +3691,64 @@ type RoutingResolution = RoutableResolution | BlockedResolution;
3331
3691
  */
3332
3692
  declare function resolveRouting(handler: CapabilityRequirement, workers: readonly (RawWorkerDescriptor | WorkerDescriptor)[]): RoutingResolution;
3333
3693
 
3694
+ /**
3695
+ * Routes a failed run to a handler workflow instead of failing it: when a run of the workflow ends
3696
+ * `failed` with an error whose `code` matches (or with any error, for the route without a `code`), the
3697
+ * engine starts `workflow` with an {@link OnErrorInput} and the failed run waits for it. The run then
3698
+ * settles with the handler's outcome: its output on success, its error on failure.
3699
+ */
3700
+ interface OnErrorRoute {
3701
+ /** The error `code` to route. Omitted: routes any failure no other route's `code` matches. */
3702
+ code?: string | undefined;
3703
+ /** The registered handler workflow's name. */
3704
+ workflow: string;
3705
+ }
3706
+ /** The input an {@link OnErrorRoute} handler workflow is started with. */
3707
+ interface OnErrorInput<TInput = unknown> {
3708
+ /** The run that failed; it completes with this handler's output. */
3709
+ runId: string;
3710
+ /** The failed run's workflow. */
3711
+ workflow: string;
3712
+ /** The failed run's input. */
3713
+ input: TInput;
3714
+ /** The failure, as the run recorded it. */
3715
+ error: StepError;
3716
+ }
3717
+ /**
3718
+ * Handoff checkpoints live at seqs from here up, one per handoff, so a body that runs again after a
3719
+ * retry can never reach one. Fits a 32-bit `seq` column.
3720
+ */
3721
+ declare const HANDOFF_SEQ_BASE = 1000000000;
3722
+ /** The id of the handler run of a run's `attempt`-th handoff. */
3723
+ declare const onErrorRunId: (runId: string, attempt: number) => string;
3724
+ /** The waiter checkpoint a run waits on its handler under; renamed {@link retiredHandoffName} on retry. */
3725
+ declare const handoffName: (handlerId: string) => string;
3726
+ /** What a retry renames a handoff checkpoint to: kept in the timeline, never followed again. */
3727
+ declare const retiredHandoffName: (handlerId: string) => string;
3728
+ /** The handler run id a live handoff checkpoint of `runId` names, or undefined for any other one. */
3729
+ declare function handoffHandlerId(runId: string, cp: {
3730
+ seq: number;
3731
+ name: string;
3732
+ }): string | undefined;
3733
+ /** The run's live handoff (its latest, unretired one), if it handed a failure off. */
3734
+ declare function liveHandoff<C extends {
3735
+ seq: number;
3736
+ name: string;
3737
+ }>(runId: string, checkpoints: readonly C[]): C | undefined;
3738
+ /** The route a failure takes: the one for its exact code, else the catch-all, else none. */
3739
+ declare function routeFor(routes: OnErrorRoute[] | undefined, error: StepError): OnErrorRoute | undefined;
3740
+ /** Reject two routes for one code, or two catch-alls — ambiguous config, caught at registration. */
3741
+ declare function assertRoutes(workflow: string, routes: OnErrorRoute[]): void;
3742
+ /** The `code` carried by a thrown value: its own, a dispatched step's, or a thin-worker step's. */
3743
+ declare function codeOf(err: unknown): string | undefined;
3744
+ /** The `details` carried by a thrown value, from the same places as {@link codeOf}. */
3745
+ declare function detailsOf(err: unknown): unknown;
3746
+ /** `code` and `details` as optional keys, so an absent one is not written as `undefined`. */
3747
+ declare function codeAndDetails(err: unknown): {
3748
+ code?: string;
3749
+ details?: unknown;
3750
+ };
3751
+
3334
3752
  /**
3335
3753
  * A schedule definition — what `engine.schedules.create/upsert` take. Temporal-style: a persisted,
3336
3754
  * runtime-managed recurring start of `workflow` with `input`, fired by every driving engine's timer
@@ -3844,6 +4262,8 @@ declare class WorkflowEngine {
3844
4262
  private readonly updateValidators;
3845
4263
  /** Runs being cancelled WITH saga compensation — see `cancel({ compensate: true })`. */
3846
4264
  private readonly cancelRequested;
4265
+ /** {@link announcedRoutes} reads, by group + workflow + version. */
4266
+ private readonly announcedRoutesCache;
3847
4267
  /**
3848
4268
  * Seqs of the dispatched remote steps a turn suspended on, by run, while that turn executes on
3849
4269
  * THIS instance — so the turn can re-check them once its lease is released (see
@@ -3865,6 +4285,8 @@ declare class WorkflowEngine {
3865
4285
  private readonly stepFansFiredHere;
3866
4286
  /** The tail of each run's queue of results being handled on this instance — see {@link serializedPerRun}. */
3867
4287
  private readonly resultChains;
4288
+ /** Each run's results waiting to be settled on this instance — see {@link completeRemoteResult}. */
4289
+ private readonly resultQueues;
3868
4290
  /** Flow-control admission backend for remote steps (see {@link registerQueue}). */
3869
4291
  private readonly admission;
3870
4292
  /** Runs on THIS instance blocked on admission, by queue — woken early on a freed-slot signal. */
@@ -3939,6 +4361,8 @@ declare class WorkflowEngine {
3939
4361
  * when it cannot be derived with confidence: absent means UNKNOWN, and an absent origin is far
3940
4362
  * cheaper to live with than a wrong one. */
3941
4363
  origin?: string | undefined;
4364
+ /** Handler workflows a matching failure is routed to — see {@link OnErrorRoute}. */
4365
+ onError?: OnErrorRoute[] | undefined;
3942
4366
  }): void;
3943
4367
  /**
3944
4368
  * The retained in-process body for `name@version`, for an IN-APP worker that consumes this engine's
@@ -3968,6 +4392,8 @@ declare class WorkflowEngine {
3968
4392
  validateInput?: (input: unknown) => void | Promise<void>;
3969
4393
  /** Capabilities a live worker must advertise to run this remote workflow's turns (handshake §7.5). */
3970
4394
  requires?: string[];
4395
+ /** Handler workflows a matching failure is routed to — see {@link OnErrorRoute}. */
4396
+ onError?: OnErrorRoute[];
3971
4397
  }): void;
3972
4398
  /**
3973
4399
  * The convenience form of {@link registerRemote}: register a workflow whose body runs on a worker
@@ -3994,6 +4420,8 @@ declare class WorkflowEngine {
3994
4420
  validateInput?: (input: unknown) => void | Promise<void>;
3995
4421
  /** Capabilities a live worker must advertise to run this workflow's turns (handshake §7.5). */
3996
4422
  requires?: string[];
4423
+ /** Handler workflows a matching failure is routed to — see {@link OnErrorRoute}. */
4424
+ onError?: OnErrorRoute[];
3997
4425
  }): void;
3998
4426
  /**
3999
4427
  * Register a flow-control queue referenced by `ctx.step(step, input, { queue })`. Caps concurrent
@@ -4644,6 +5072,47 @@ declare class WorkflowEngine {
4644
5072
  * {@link runExecution}'s settle/suspend; the lease is held by {@link execute}. The result that lands
4645
5073
  * us back here (a remote step finished, a timer fired) goes through `resume` like any TS workflow.
4646
5074
  */
5075
+ /**
5076
+ * The registered onError routes whose handler workflow nothing can run: not registered on this
5077
+ * engine, and no live worker group serves it. Meant for a boot-time warning: a typo in a handler's
5078
+ * name would otherwise surface only when the first run fails.
5079
+ */
5080
+ unservedOnErrorRoutes(): Promise<{
5081
+ workflow: string;
5082
+ route: OnErrorRoute;
5083
+ }[]>;
5084
+ /** Validate a workflow's {@link OnErrorRoute}s at registration. */
5085
+ private checkedRoutes;
5086
+ /**
5087
+ * Route a failed run to its {@link OnErrorRoute} handler, read from the workflow's local registration
5088
+ * or, for one served by convention, from what its live workers announce. Starts the handler run and
5089
+ * waits for it the way a parent waits for a `ctx.child`: a `child:<handlerId>` waiter plus a
5090
+ * `running` placeholder checkpoint carrying the handler's name and input, so the handler's terminal
5091
+ * state wakes the run (buffered and reconciled like any child). From then on every execution of the
5092
+ * run only follows the handler ({@link followHandoff}); the body never runs again. Undefined when no
5093
+ * route matches: the run fails as usual.
5094
+ *
5095
+ * The placeholder sits past every seq the body used and is left out of {@link remoteHistory}.
5096
+ */
5097
+ private routeFailure;
5098
+ /** A run's handoff checkpoints, live and retired: the only ones at {@link HANDOFF_SEQ_BASE} and up. */
5099
+ private handoffCheckpoints;
5100
+ /**
5101
+ * Where a run that handed its failure off stands: the handler's outcome once it settled (from the
5102
+ * wake's checkpoint, or off the handler run when the wake never arrived), else still waiting. Starts
5103
+ * the handler if the turn that handed off crashed before its deferred start ran.
5104
+ */
5105
+ private followHandoff;
5106
+ /**
5107
+ * The onError routes the live workers announce for a workflow the engine serves by convention: the
5108
+ * one set they agree on, or none when they state none or cannot be read. Workers that announce
5109
+ * different sets (a rollout in progress) route nothing, and the run's failure is reported as a
5110
+ * `run.unrouted` event. Announcers of another version of the workflow are ignored. The read is
5111
+ * cached for {@link ANNOUNCED_ROUTES_TTL_MS}, so a burst of failures costs one descriptor read.
5112
+ */
5113
+ private announcedRoutes;
5114
+ /** Every distinct onError route set the live workers of `group` announce for the run's workflow. */
5115
+ private readAnnouncedRoutes;
4647
5116
  /**
4648
5117
  * Apply a terminal/suspended transition once: persist the new run status, emit the matching
4649
5118
  * lifecycle event, and (on completion/failure) wake a waiting parent. Both the TS and remote
@@ -4929,6 +5398,13 @@ declare class WorkflowEngine {
4929
5398
  private noteRecent;
4930
5399
  /** {@link StateStore.saveCheckpointIfPending}, or a plain save on a store without it. */
4931
5400
  private savePendingCheckpoint;
5401
+ /**
5402
+ * {@link savePendingCheckpoint} for checkpoints at distinct seqs of one run: one
5403
+ * {@link StateStore.saveCheckpointsIfPending} call when the store has it, else one write each.
5404
+ * Never rejects as a whole: a write that failed is reported as that entry's error, and the batch
5405
+ * call rejecting means it wrote nothing, so the entries are then written one by one.
5406
+ */
5407
+ private savePendingCheckpoints;
4932
5408
  /** Enqueue a remote step task to its worker group via the transport pool. Shared by the initial
4933
5409
  * dispatch, the opt-in self-heal re-dispatch (see `remoteRedispatchMs`), and the explicit
4934
5410
  * {@link redispatchPending}. Carries the current trace/context so a re-dispatch is traceable. */
@@ -4945,15 +5421,33 @@ declare class WorkflowEngine {
4945
5421
  * result (the dispatching one may be gone), so the run is crash/scale-safe. Resolves whether the
4946
5422
  * run should now be resumed: not for a duplicate or late delivery (the checkpoint isn't `pending`),
4947
5423
  * a run already finished, or a step fan whose barrier is still closed.
5424
+ *
5425
+ * Results of one run are settled in batches: the first starts a batch, and the ones that arrive
5426
+ * while it is being written form the next. Under load a wide fan's results are written by one
5427
+ * {@link StateStore.saveCheckpointsIfPending} call per batch, and the fan's barrier is asked once
5428
+ * per batch, not once per result. A result resolves only once its own write has committed, so the
5429
+ * transport acknowledges nothing that is not durable yet.
4948
5430
  */
4949
5431
  private completeRemoteResult;
5432
+ /** Settle `queue` (a run's queued results) batch by batch until it is empty, then retire it. */
5433
+ private drainResultQueue;
5434
+ /**
5435
+ * Settle a batch of one run's step results. At most one of them resolves `true` (resume the run):
5436
+ * that resume replays every write of the batch, so a second would only replay it again. A result
5437
+ * whose read or write failed resolves its error, and the transport redelivers just that one.
5438
+ */
5439
+ private completeRemoteResults;
4950
5440
  /**
4951
5441
  * The join barrier of a step fan: a result for one of its steps resumes the parent only once no
4952
5442
  * step of the fan is still `pending` (a settled wave), or on a failure (failFast surfaces it, and a
4953
5443
  * retry needs the parent to schedule it). Without it every result would replay the whole parent,
4954
- * which makes a fan of N steps cost O(N²) checkpoint reads.
5444
+ * which makes a fan of N steps cost O(N²) checkpoint reads. `barriers` holds the answer per fan
5445
+ * for the rest of a batch. A barrier that cannot be read counts as open: a spare resume replays and
5446
+ * re-suspends, a lost one strands the run.
4955
5447
  */
4956
5448
  private stepFanStillRunning;
5449
+ /** How many steps of a step fan's seq range are still `pending`. */
5450
+ private stepFanPending;
4957
5451
  /**
4958
5452
  * Apply a remote workflow-turn {@link WorkflowDecision} durably — runs on WHATEVER instance receives
4959
5453
  * it over the broker (the dispatching one may be gone, or a point-to-point broker handed it to a
@@ -5007,6 +5501,10 @@ declare class RemoteStepError extends Error {
5007
5501
  readonly stepError?: StepError | undefined;
5008
5502
  constructor(stepError?: StepError);
5009
5503
  }
5504
+ /** Checkpoint names that record a parent→child edge: an awaited child, a folded group of them, a spawn. */
5505
+ declare const CHILD_EDGE_PREFIXES: string[];
5506
+ /** The child run ids a parent's {@link CHILD_EDGE_PREFIXES} checkpoints point at (others are skipped). */
5507
+ declare function childIdsOf(checkpoints: StepCheckpoint[]): string[];
5010
5508
 
5011
5509
  /**
5012
5510
  * What the class-first statics need from whoever registered the workflow class: the engine, or a
@@ -5088,7 +5586,12 @@ declare function parseDuration(duration: string | number): number;
5088
5586
  */
5089
5587
  declare class FatalError extends Error {
5090
5588
  readonly code?: string | undefined;
5091
- constructor(message: string, code?: string);
5589
+ /** Structured, JSON-serializable detail (e.g. validation issues). It travels with the failure to
5590
+ * the run's error, a parent's `allSettled` item and an onError handler's input. */
5591
+ readonly details?: unknown;
5592
+ /** Read by the step result builders, so a dispatched step's retry policy honours it too. */
5593
+ readonly retryable = false;
5594
+ constructor(message: string, code?: string, details?: unknown);
5092
5595
  }
5093
5596
  /**
5094
5597
  * Thrown by `start` when a run would exceed its concurrency quota: `active` runs sharing the quota
@@ -5166,6 +5669,8 @@ declare class RemoteWorkflowTimeout extends Error {
5166
5669
  * breaking changes (old runs finish on the version they started on).
5167
5670
  */
5168
5671
  declare class NonDeterminismError extends Error {
5672
+ /** Marks the failure as a broken deploy, which an `onError` route never takes. */
5673
+ readonly code = "non_determinism";
5169
5674
  readonly runId: string;
5170
5675
  readonly seq: number;
5171
5676
  constructor(runId: string, seq: number, expected: string, recorded: string);
@@ -5196,17 +5701,17 @@ declare class NestedWorkflowCallError extends FatalError {
5196
5701
  * and the failing ids — the wait-all/fail-fast counterpart to a single child's FatalError. Mirrors
5197
5702
  * the Python SDK's `GatherFailed`.
5198
5703
  */
5704
+ /** One failed item of a fan: its input index, the child run or step id, and its failure. */
5705
+ interface GatherItemFailure {
5706
+ index: number;
5707
+ id: string;
5708
+ error: string;
5709
+ code?: string | undefined;
5710
+ details?: unknown;
5711
+ }
5199
5712
  declare class GatherError extends Error {
5200
- readonly failures: {
5201
- index: number;
5202
- id: string;
5203
- error: string;
5204
- }[];
5205
- constructor(failures: {
5206
- index: number;
5207
- id: string;
5208
- error: string;
5209
- }[], total?: number);
5713
+ readonly failures: GatherItemFailure[];
5714
+ constructor(failures: GatherItemFailure[], total?: number);
5210
5715
  }
5211
5716
  declare class WorkflowSuspended extends Error {
5212
5717
  /** Epoch ms to auto-resume (durable sleep), or undefined when waiting on an external signal. */
@@ -5437,110 +5942,48 @@ declare function mergeRunValueFacetRows(rows: readonly {
5437
5942
  */
5438
5943
  declare function runValueFacetsFromRuns(runs: readonly WorkflowRun[], axis: RunValueAxis, opts?: RunValueFacetOptions): RunValueFacetRow[];
5439
5944
 
5440
- /** A run as returned by the gateway's list — the durable run plus an optional {@link RunWaiting}
5441
- * descriptor the control plane resolves (what a suspended run is parked on), so the dashboard can
5442
- * name the wait in a list row without fetching each run's timeline. Additive: `waiting` is absent
5443
- * on a non-parked run and on gateways/versions that don't compute it. */
5444
- type RunListItem = WorkflowRun & {
5445
- waiting?: RunWaiting | undefined;
5446
- };
5447
- /** Which durable topology a gateway speaks for — surfaced in the dashboard so an operator can tell a
5448
- * control plane from a tenant at a glance (the store-backed gateway is the operator; the proxy is a
5449
- * tenant). Cheap, synchronous, local knowledge — no round-trip. */
5450
- interface DurableTopology {
5451
- role: 'control-plane' | 'tenant';
5452
- /** The tenant's isolation partition name; set only when `role` is 'tenant'. */
5453
- tenant?: string;
5454
- }
5455
- /** A run + its timeline + child ids — the detail view. Single source of truth: the dashboard server
5456
- * re-exports this instead of re-declaring it, and the dashboard client derives its wire mirror from
5457
- * it via {@link WireDates} instead of hand-mirroring field by field. */
5458
- interface RunDetail {
5459
- run: WorkflowRun;
5460
- /** Steps in execution order (local + remote). */
5461
- timeline: StepCheckpoint[];
5462
- /** Ids of runs this run spawned (parent→children tree). */
5463
- children: string[];
5464
- }
5945
+ /** A store that aggregates checkpoints itself: both halves of the pair are present. */
5946
+ type CheckpointAggregatingStore = StateStore & Required<Pick<StateStore, 'checkpointStats' | 'queryCheckpoints'>>;
5947
+ declare function aggregatesCheckpoints(store: StateStore): store is CheckpointAggregatingStore;
5465
5948
  /**
5466
- * Maps every `Date` (and `Date | undefined`) field of `T` to its ISO-string wire form — the shape a
5467
- * JSON response actually carries once dates cross the wire (`JSON.stringify` already does this
5468
- * coercion; this just types it). Homomorphic: each field keeps its own optional modifier, so a
5469
- * required `Date` becomes a required `string` and an optional one stays optional. Lets a consumer
5470
- * derive its own wire-facing client type from a core server type (e.g. the dashboard's SPA `WorkflowRun`/
5471
- * `StepCheckpoint`/`RunDetail`) instead of hand-mirroring it field by field and drifting.
5949
+ * {@link StateStore.checkpointStats} over checkpoints already in memory — the reference a store's
5950
+ * `GROUP BY` must agree with, and the in-memory store's implementation.
5472
5951
  */
5473
- type WireDates<T> = {
5474
- [K in keyof T]: T[K] extends Date ? string : T[K] extends Date | undefined ? string | undefined : T[K];
5475
- };
5952
+ declare function checkpointStatsOf(checkpoints: StepCheckpoint[], opts?: {
5953
+ group?: string | undefined;
5954
+ }): CheckpointStat[];
5955
+ /** {@link StateStore.queryCheckpoints} over checkpoints already in memory, sorted by `seq` here. */
5956
+ declare function queryCheckpointsOf(checkpoints: StepCheckpoint[], query: CheckpointQuery): StepCheckpoint[];
5476
5957
  /**
5477
- * The bounded read/control/stream surface a consumer (e.g. a controller) needs, satisfied by BOTH
5478
- * topologies: the control plane binds a store-backed impl (reuses `DashboardService`); a tenant binds
5479
- * a `ProxyRunGateway` that round-trips over the transport. Deliberately smaller than the full dashboard
5480
- * (no metrics/bulk/update/signal) — those stay control-plane-only. `workerHealth` IS on the port: the
5481
- * operator answers it scoped to the requester's own groups, so a tenant's Workers panel works too.
5958
+ * What `summarizeTimeline` plus `childIdsOf` make of a run's whole checkpoint list, read through the
5959
+ * store's aggregates instead: the checkpoints outside wide fans, one {@link FanSummary} per wide fan,
5960
+ * and the run's children capped at {@link SUMMARY_CHILD_LIMIT} with their count.
5482
5961
  *
5483
- * Declared as an **abstract class** rather than an interface so it doubles as its own NestJS DI token
5484
- * (the idiomatic inject-by-type pattern): providers bind `{ provide: RunGateway, useClass/useFactory }`
5485
- * and consumers inject `constructor(private readonly gateway: RunGateway)` with no string/symbol token.
5486
- * `StoreRunGateway`/`ProxyRunGateway` `implements RunGateway`; abstract methods carry no body, so the
5487
- * emitted runtime class is an empty, non-instantiable shell used only as the token.
5962
+ * What it reads besides the aggregates: the rows outside wide fans, every folded `fan:` checkpoint
5963
+ * (one per settled wave), up to {@link FAN_SUMMARY_FAILURES} failed rows per wide fan, the first
5964
+ * child-edge rows, and — while a wide child fan is in flight — that fan's completed `signal:child:`
5965
+ * rows, whose `ok: false` payload is what marks a failed child.
5966
+ *
5967
+ * `childCount` counts each `spawn:` checkpoint as one child: the engine always writes the child's id
5968
+ * as its output, which is what `childIdsOf` reads.
5488
5969
  */
5489
- declare abstract class RunGateway {
5490
- /** This deployment's durable role (control plane vs tenant) — synchronous local metadata. */
5491
- abstract topology(): DurableTopology;
5492
- abstract getRunDetail(runId: string): Promise<RunDetail | null>;
5493
- /** List runs, each optionally carrying a {@link RunWaiting} descriptor (what a suspended run is
5494
- * parked on). The store-backed gateway resolves `waiting`; a proxy relays whatever the control
5495
- * plane sent. */
5496
- abstract listRuns(query: RunQuery): Promise<RunListItem[]>;
5497
- /**
5498
- * Counts of the runs matching `query`, grouped by `(status, origin)` — what a console's status and
5499
- * origin chips display. Separate from {@link listRuns} precisely so the list can be PAGINATED: the
5500
- * page bounds what is rendered, these counts stay whole-set exact. Zero-count cells are absent.
5501
- */
5502
- abstract runFacets(query: RunFacetQuery): Promise<RunFacetRow[]>;
5503
- /**
5504
- * The distinct values of one filter axis over the runs matching `query`, with counts — what fills a
5505
- * console's tenant/tag/attribute pickers. On the port (not control-plane-only) because the pickers
5506
- * belong to the same panel as {@link listRuns}: a tenant that can list its runs has to be able to
5507
- * see what it may filter them by, or its console offers a blank dropdown.
5508
- *
5509
- * Returns `[]` when the underlying store does not implement the enumeration — an empty picker with
5510
- * free-text entry still standing, not an error.
5511
- */
5512
- abstract runValueFacets(axis: RunValueAxis, query: RunFacetQuery, opts?: RunValueFacetOptions): Promise<RunValueFacetRow[]>;
5513
- /**
5514
- * Bulk-resolve {@link RunWaiting} for an arbitrary set of run ids — for a consumer with its OWN
5515
- * filtered/paginated run listing (so it isn't just `listRuns` under another name) that needs to know
5516
- * which of ITS runs are parked on a breakpoint (or any other event wait) without re-deriving the bulk
5517
- * waiter scan itself or reaching for raw SQL against `durable_step_checkpoints`. A `Record` (not a
5518
- * `Map`) because `ProxyRunGateway` serialises the reply over the transport as plain JSON. Entries are
5519
- * present ONLY for runs currently waiting — an unknown id, a non-suspended id, and a suspended id
5520
- * parked on something non-event (a bare `ctx.sleep`, an in-flight step) are simply absent, same as a
5521
- * `listRuns` row with no `waiting`.
5522
- */
5523
- abstract waitingFor(runIds: string[]): Promise<Record<string, RunWaiting>>;
5524
- /** Per-group worker health (queue backlog + live worker heartbeats). On the control plane this is
5525
- * every group; over a tenant proxy the operator scopes it to the tenant's own groups. */
5526
- abstract workerHealth(): Promise<GroupHealth[]>;
5527
- abstract cancel(runId: string, opts?: {
5528
- compensate?: boolean;
5529
- }): Promise<RunResult | null>;
5530
- abstract retry(runId: string): Promise<RunResult | null>;
5531
- abstract continue(runId: string): Promise<RunResult | null>;
5532
- /** Re-dispatch every remote step of a run stuck `pending` — the operator recovery for a LOST step
5533
- * dispatch (crashed worker / dropped job) that no automatic path re-drives. Returns the run's status
5534
- * plus how many steps were re-dispatched, or null if the run is unknown. */
5535
- abstract redispatchPending(runId: string): Promise<(RunResult & {
5536
- redispatched: number;
5537
- }) | null>;
5538
- abstract retryWithInput(runId: string, input: unknown): Promise<{
5539
- runId: string;
5540
- } | null>;
5541
- /** Live lifecycle events for one run; returns an unsubscribe fn. Framework-agnostic (no rxjs). */
5542
- abstract subscribe(runId: string, onEvent: (event: EngineEvent) => void): () => void;
5543
- }
5970
+ declare function summarizeRunFromStore(store: CheckpointAggregatingStore, runId: string, over: number, stats?: CheckpointStat[]): Promise<{
5971
+ timeline: StepCheckpoint[];
5972
+ fans: FanSummary[];
5973
+ children: string[];
5974
+ childCount: number;
5975
+ }>;
5976
+ /** What `pageFan` makes of a run's whole checkpoint list, read one page at a time from the store. */
5977
+ declare function pageFanFromStore(store: CheckpointAggregatingStore, runId: string, group: string, query: FanPageQuery, stats?: CheckpointStat[]): Promise<FanPage>;
5978
+ /**
5979
+ * The ETag of a summarized run detail: the run row as read (so any run field that changes shows)
5980
+ * plus its checkpoint buckets, and the threshold it was summarized with.
5981
+ */
5982
+ declare function runDetailEtag(run: WorkflowRun, stats: CheckpointStat[], over: number): string;
5983
+ /** The ETag of one page of a fan: its group's buckets and the page asked for. */
5984
+ declare function fanPageEtag(group: string, stats: CheckpointStat[], query: FanPageQuery): string;
5985
+ /** Whether an `If-None-Match` header value names `etag` (weak comparison, as RFC 9110 asks for). */
5986
+ declare function etagMatches(ifNoneMatch: string | undefined, etag: string): boolean;
5544
5987
 
5545
5988
  /**
5546
5989
  * Resolve WHAT a suspended run is parked on from the token of the {@link SignalWaiter} it registered.
@@ -5573,9 +6016,10 @@ declare function indexWaitersByRun(waiters: readonly SignalWaiter[]): Map<string
5573
6016
 
5574
6017
  /**
5575
6018
  * The parent of a child run whose id the engine minted: a `ctx.all` child
5576
- * (`<parent>.all.<seq>.<i>`, or `.w<k>.<i>` under a `concurrency` limit) or a `ctx.child` /
5577
- * `ctx.startChild` child without an explicit id (`<parent>.child.<seq>`). Undefined for any other
5578
- * run, including a child started with a caller-chosen id.
6019
+ * (`<parent>.all.<seq>.<i>`, or `.w<k>.<i>` under a `concurrency` limit), a `ctx.child` /
6020
+ * `ctx.startChild` child without an explicit id (`<parent>.child.<seq>`), or the onError handler of
6021
+ * a failed run (`<parent>.onError.<attempt>`). Undefined for any other run, including a child started with a
6022
+ * caller-chosen id.
5579
6023
  */
5580
6024
  declare function parentRunIdOf(runId: string): string | undefined;
5581
6025
 
@@ -5622,11 +6066,21 @@ declare class CodecStateStore implements StateStore {
5622
6066
  /** Encodes like {@link saveCheckpoint}. Bound only when the inner store has it, so the engine's
5623
6067
  * plain-save fallback still kicks in through the wrapper. */
5624
6068
  readonly saveCheckpointIfPending?: (checkpoint: StepCheckpoint) => Promise<boolean>;
6069
+ /** Encodes each checkpoint like {@link saveCheckpoint}. Bound only when the inner store has it. */
6070
+ readonly saveCheckpointsIfPending?: (checkpoints: StepCheckpoint[]) => Promise<boolean[]>;
5625
6071
  /** Forwarded verbatim — a count reads no payload. Bound only when the inner store has it. */
5626
6072
  readonly countCheckpoints?: (runId: string, fromSeq: number, toSeq: number, statuses: StepCheckpoint['status'][]) => Promise<number>;
5627
6073
  /** Forwarded verbatim — retention selects by status/updatedAt/scope, never by payload. Bound only
5628
6074
  * when the inner store prunes, so the retention poller still sees (and warns about) its absence. */
5629
6075
  readonly pruneTerminalRuns?: (policy: RetentionPolicy, nowMs: number, limit: number) => Promise<number>;
6076
+ /** Forwarded verbatim — the buckets aggregate names, statuses and timestamps, never a payload.
6077
+ * Bound only when the inner store aggregates, so the run detail's fallback still applies. */
6078
+ readonly checkpointStats?: (runId: string, opts?: {
6079
+ group?: string | undefined;
6080
+ }) => Promise<CheckpointStat[]>;
6081
+ /** Filters on unencoded columns, then decodes the rows like {@link listCheckpoints}. Bound only
6082
+ * when the inner store has it. */
6083
+ readonly queryCheckpoints?: (runId: string, query: CheckpointQuery) => Promise<StepCheckpoint[]>;
5630
6084
  /** Forwarded verbatim — a count reads no payload. Bound only when the inner store counts, so the
5631
6085
  * engine's facet/listing fallback still applies through the wrapper. */
5632
6086
  readonly countRuns?: (query: Omit<RunQuery, 'limit' | 'offset'>) => Promise<number>;
@@ -5726,12 +6180,17 @@ declare function eventMatchOf(token: string): Record<string, unknown>;
5726
6180
  declare function eventMatches(payload: unknown, match: Record<string, unknown>): boolean;
5727
6181
 
5728
6182
  interface MetricsSnapshot {
6183
+ /** `routed`: failures handed to an onError handler; `unrouted`: routes the engine could not apply. */
5729
6184
  runs: {
5730
6185
  started: number;
5731
6186
  completed: number;
5732
6187
  failed: number;
5733
6188
  suspended: number;
6189
+ routed: number;
6190
+ unrouted: number;
5734
6191
  };
6192
+ /** Routed failures by error code (`*` for a failure without one). */
6193
+ routedByCode: Record<string, number>;
5735
6194
  steps: {
5736
6195
  started: number;
5737
6196
  completed: number;
@@ -6081,6 +6540,11 @@ declare class InMemoryStateStore implements StateStore {
6081
6540
  * so this lets the benchmark contrast "fetch N, scan in JS" against "fetch the k that match".
6082
6541
  */
6083
6542
  lastCheckpointRowsRead: number;
6543
+ /**
6544
+ * Test/observability hook: checkpoint rows materialized since construction, across every
6545
+ * checkpoint read that returns rows — what a run-detail benchmark compares between paths.
6546
+ */
6547
+ checkpointRowsRead: number;
6084
6548
  private key;
6085
6549
  /** Drop then re-add a run's normalized attribute rows so the index tracks its current attributes. */
6086
6550
  private reindexAttributes;
@@ -6094,6 +6558,7 @@ declare class InMemoryStateStore implements StateStore {
6094
6558
  getCheckpoint(runId: string, seq: number): Promise<StepCheckpoint | null>;
6095
6559
  saveCheckpoint(checkpoint: StepCheckpoint): Promise<void>;
6096
6560
  saveCheckpointIfPending(checkpoint: StepCheckpoint): Promise<boolean>;
6561
+ saveCheckpointsIfPending(checkpoints: StepCheckpoint[]): Promise<boolean[]>;
6097
6562
  listIncompleteRuns(namespace?: string): Promise<WorkflowRun[]>;
6098
6563
  listPendingRuns(limit: number, namespace?: string): Promise<WorkflowRun[]>;
6099
6564
  listDueTimers(nowMs: number, namespace?: string, limit?: number): Promise<WorkflowRun[]>;
@@ -6155,6 +6620,11 @@ declare class InMemoryStateStore implements StateStore {
6155
6620
  deleteSchedule(id: string): Promise<boolean>;
6156
6621
  listSchedules(query: ScheduleQuery): Promise<ScheduleRecord[]>;
6157
6622
  listCheckpoints(runId: string): Promise<StepCheckpoint[]>;
6623
+ private runCheckpoints;
6624
+ checkpointStats(runId: string, opts?: {
6625
+ group?: string | undefined;
6626
+ }): Promise<CheckpointStat[]>;
6627
+ queryCheckpoints(runId: string, query: CheckpointQuery): Promise<StepCheckpoint[]>;
6158
6628
  getLatestCheckpointByName(runId: string, name: string): Promise<StepCheckpoint | undefined>;
6159
6629
  countCheckpoints(runId: string, fromSeq: number, toSeq: number, statuses: StepCheckpoint['status'][]): Promise<number>;
6160
6630
  listCheckpointsByNamePrefix(runId: string, prefixes: string[]): Promise<StepCheckpoint[]>;
@@ -6200,4 +6670,4 @@ declare function singletonAdmissionDenialPatch(runs: WorkflowRun[], runId: strin
6200
6670
  updatedAt: Date;
6201
6671
  } | undefined;
6202
6672
 
6203
- export { type AccumulatorHost, type Admission, type AdmissionBackend, type AdmissionItem, type AllOptions, type AllStepsOptions, type AnnouncedWorkflow, type AnnouncementEvidence, type AttributeFilter, type AttributeOp, type AttributePredicateOperand, type AttributeValue, type BackoffStrategy, type BlockedDispatch, type BlockedResolution, CONTROL_FLOW_SIGNAL, CURRENT_PROTOCOL_VERSION, type CapabilityRequirement, type ChildCallOptions, type ChildWait, CodecStateStore, type ConcurrencyConfig, ConcurrencyLimitError, type ConcurrencyQuota, ContinueAsNew, type ControlMessage, type ControlPlane, DEFAULT_CONCURRENCY_STATUSES, DEFAULT_PARTITION, DURABLE_OPTIONS, DURABLE_OPTIONS_CANONICAL, DURABLE_STEP_CONFIG, DURABLE_STEP_NAME, type Disagreement, type DispatchDiagnostics, type DispatchPlan, type DurableExecution, type DurableExecutionWrapper, type DurableTopology, type DurableWebhook, DurableWorkflow, type DynamicWorkflowCtx, ENGINE_MINTED_TAG_PREFIXES, EVENT_BUFFER_SCAN_LIMIT, EVENT_TOKEN_PREFIX, type EngineEvent, type EngineEventType, type EngineListener, Entities, type EntityConfig, type EntityHandler, type EntityHost, EventAccumulators, type EventBatchConfig, type FanJoin, type FanWait, FatalError, GatherError, type GroupHealth, type Heartbeat, type HeartbeatSighting, type HeartbeatStatus, type HistoryEvent, InMemoryAdmissionBackend, InMemoryStateStore, InMemoryTransport, type InferSearchAttributes, LEGACY_V1_CAPABILITIES, LEGACY_V1_PROTOCOL, type MetricsCollector, type MetricsSnapshot, type NamedTransport, type NegotiateOptions, type NegotiationOutcome, type NegotiationReason, type NegotiationResult, NestedWorkflowCallError, NonDeterminismError, type PartitionSighting, type PayloadCodec, type QueueConfig, QueueController, RUN_VALUE_FACET_LIMIT, RUN_VALUE_FACET_SCAN, type RawWorkerDescriptor, RemoteStepError, RemoteStepTimeout, type RemoteTask, RemoteWorkflowExecutor, RemoteWorkflowTimeout, type RetentionPolicy, type RoutableDispatch, type RoutableResolution, type RoutingResolution, type RunAttributeRow, type RunDetail, type RunDispatcher, type RunFacetQuery, type RunFacetRow, RunGateway, type RunListItem, type RunQuery, type RunReply, type RunReplyResult, type RunRequest, type RunRequestKind, type RunResult, type RunSchedulesOptions, type RunScope, type RunStatus, type RunValueAxis, type RunValueFacetOptions, type RunValueFacetOrder, type RunValueFacetRow, type RunWaiting, SINGLETON_ACTIVE_STATUSES, SINGLETON_ADMITTED_TAG, STATE_STORE, STATE_STORE_CANONICAL, type ScalarAttributeFilter, ScheduleAlreadyExistsError, ScheduleClient, type ScheduleClientOptions, type ScheduleDescription, type ScheduleHost, type ScheduleListQuery, ScheduleNotFoundError, type ScheduleOptions, type ScheduleQuery, type ScheduleRecord, type ScheduledWorkflow, type SearchAttributes, type SearchAttributesSchema, SignalTimeoutError, type SignalWaiter, type SingletonConfig, SingletonQueueFullError, StandardSchemaV1, type StartOptions, type StartRunMessage, type StateStore, type StepCheckpoint, type StepConfig, type StepDef, type StepDispatchOpts, type StepError, type StepEvent, type StepHandler, type StepInterceptor, type StepInvocation, type StepKind, type StepLogger, type StepOptions, type StepRef, type StepResult, type StepScope, type StepUndo, type StoreTransaction, type SubProcessHandle, TERMINAL_RUN_STATUSES, TRANSPORT, TRANSPORT_CANONICAL, type TenantEvent, type Transport, type UndoOf, type UpdateResult, type UpdateValidator, VERSION_UNDECLARED_TAG, WORKFLOW_NAME_KEY, type WireDates, type WorkerAdjust, type WorkerConcurrencyStatus, type WorkerDescriptor, type WorkerHeartbeat, type WorkerLifecycle, type WorkerStatus, type WorkflowAnnouncement, WorkflowBlocked, type WorkflowClass, type WorkflowCommand, type WorkflowCtx, type WorkflowDecision, type WorkflowDirectory, WorkflowEngine, type WorkflowEngineDeps, type WorkflowExecutor, type WorkflowHandler, type WorkflowInputOf, type WorkflowOutputOf, type WorkflowRef, type WorkflowRegistration, type WorkflowRun, type WorkflowStartClient, type WorkflowStepEvent, WorkflowSuspended, type WorkflowTask, aggregateAnnouncements, announcementsOf, applyAttributeQuery, assertConcurrency, attributeColumnFor, attributeOperand, attributePredicateOperands, axisIsRunColumn, bindWorkflowClass, breakpointToken, buildWorkflowDirectory, canRoute, capableWorkers, classifyWaiterToken, clearDurableExecutionWrappers, clearTerminalSingletonAdmission, collectMetrics, concurrencyTag, controlPlaneDescriptor, countRuns, coveredTokens, createStepLogger, currentStep, currentStepScope, currentWorkflowCtx, debug, describeWorker, descriptorHash, error, eventMatchOf, eventMatches, eventNameOf, eventPrefix, eventToken, facetOrigin, hasDurableExecutionWrappers, heartbeatStatus, indexWaitersByRun, info, isEngineMintedTag, isEventToken, isLegacyDescriptor, isNonEmptyRunScope, isWorkflowControlFlowSignal, listSignalWaitersOfRuns, log, matchesAttributes, mergeRunFacetRows, mergeRunValueFacetRows, missingCapabilities, negotiate, nextCronFireMs, normalizeAttributeRows, normalizeDescriptor, observedAnnouncements, parentRunIdOf, parseDuration, partitionOfToken, planDispatch, prevCronFireMs, readSearchAttributes, requiredCapabilities, resolveConcurrency, resolveRouting, resolveRunWaiting, runDurableExecution, runInStepLogger, runInStepScope, runInWorkflowCtx, runOutsideWorkflowCtx, runSchedules, runStepHandler, runValueFacetsFromRuns, sanitizeQueueToken, scheduledRunId, singletonAdmissionDenialPatch, singletonAdmissionTags, sqlComparator, stepConfigOf, stepId, stepNameOf, sub, subEvent, subProcess, tenantGroup, useDurableExecution, warn, workflowName };
6673
+ export { type AccumulatorHost, type Admission, type AdmissionBackend, type AdmissionItem, type AllOptions, type AllSettledOptions, type AllStepsOptions, type AllStepsSettledOptions, type AnnouncedWorkflow, type AnnouncementEvidence, type AttributeFilter, type AttributeOp, type AttributePredicateOperand, type AttributeValue, type BackoffStrategy, type BlockedDispatch, type BlockedResolution, CHILD_EDGE_PREFIXES, CONTROL_FLOW_SIGNAL, CURRENT_PROTOCOL_VERSION, type CapabilityRequirement, type CheckpointAggregatingStore, type CheckpointNameKind, type CheckpointQuery, type CheckpointStat, type ChildCallOptions, type ChildWait, CodecStateStore, type ConcurrencyConfig, ConcurrencyLimitError, type ConcurrencyQuota, ContinueAsNew, type ControlMessage, type ControlPlane, DEFAULT_CONCURRENCY_STATUSES, DEFAULT_PARTITION, DURABLE_OPTIONS, DURABLE_OPTIONS_CANONICAL, DURABLE_STEP_CONFIG, DURABLE_STEP_NAME, type Disagreement, type DispatchDiagnostics, type DispatchPlan, type DurableExecution, type DurableExecutionWrapper, type DurableTopology, type DurableWebhook, DurableWorkflow, type DynamicWorkflowCtx, ENGINE_MINTED_TAG_PREFIXES, EVENT_BUFFER_SCAN_LIMIT, EVENT_TOKEN_PREFIX, type EngineEvent, type EngineEventType, type EngineListener, Entities, type EntityConfig, type EntityHandler, type EntityHost, EventAccumulators, type EventBatchConfig, FAN_SUMMARY_FAILURES, type FanJoin, type FanPage, type FanPageQuery, type FanSummary, type FanWait, FatalError, GatherError, type GatherItemFailure, type GroupHealth, HANDOFF_SEQ_BASE, type Heartbeat, type HeartbeatSighting, type HeartbeatStatus, type HistoryEvent, InMemoryAdmissionBackend, InMemoryStateStore, InMemoryTransport, type InferSearchAttributes, LEGACY_V1_CAPABILITIES, LEGACY_V1_PROTOCOL, type MetricsCollector, type MetricsSnapshot, type NamedTransport, type NegotiateOptions, type NegotiationOutcome, type NegotiationReason, type NegotiationResult, NestedWorkflowCallError, NonDeterminismError, type OnErrorInput, type OnErrorRoute, type PartitionSighting, type PayloadCodec, type QueueConfig, QueueController, RUN_VALUE_FACET_LIMIT, RUN_VALUE_FACET_SCAN, type RawWorkerDescriptor, RemoteStepError, RemoteStepTimeout, type RemoteTask, RemoteWorkflowExecutor, RemoteWorkflowTimeout, type RetentionPolicy, type RoutableDispatch, type RoutableResolution, type RoutingResolution, type RunAttributeRow, type RunDetail, type RunDetailOptions, type RunDispatcher, type RunFacetQuery, type RunFacetRow, RunGateway, type RunListItem, type RunQuery, type RunReply, type RunReplyResult, type RunRequest, type RunRequestKind, type RunResult, type RunSchedulesOptions, type RunScope, type RunStatus, type RunValueAxis, type RunValueFacetOptions, type RunValueFacetOrder, type RunValueFacetRow, type RunWaiting, SINGLETON_ACTIVE_STATUSES, SINGLETON_ADMITTED_TAG, STATE_STORE, STATE_STORE_CANONICAL, SUMMARY_CHILD_LIMIT, type ScalarAttributeFilter, ScheduleAlreadyExistsError, ScheduleClient, type ScheduleClientOptions, type ScheduleDescription, type ScheduleHost, type ScheduleListQuery, ScheduleNotFoundError, type ScheduleOptions, type ScheduleQuery, type ScheduleRecord, type ScheduledWorkflow, type SearchAttributes, type SearchAttributesSchema, type Settled, SignalTimeoutError, type SignalWaiter, type SingletonConfig, SingletonQueueFullError, StandardSchemaV1, type StartOptions, type StartRunMessage, type StateStore, type StepCheckpoint, type StepConfig, type StepDef, type StepDispatchOpts, type StepError, type StepEvent, type StepHandler, type StepInterceptor, type StepInvocation, type StepKind, type StepLogger, type StepOptions, type StepRef, type StepResult, type StepScope, type StepUndo, type StoreTransaction, type SubProcessHandle, TERMINAL_RUN_STATUSES, TRANSPORT, TRANSPORT_CANONICAL, type TenantEvent, type Transport, type UndoOf, type UpdateResult, type UpdateValidator, VERSION_UNDECLARED_TAG, WORKFLOW_NAME_KEY, type WireDates, type WorkerAdjust, type WorkerConcurrencyStatus, type WorkerDescriptor, type WorkerHeartbeat, type WorkerLifecycle, type WorkerStatus, type WorkflowAnnouncement, WorkflowBlocked, type WorkflowClass, type WorkflowCommand, type WorkflowCtx, type WorkflowDecision, type WorkflowDirectory, WorkflowEngine, type WorkflowEngineDeps, type WorkflowExecutor, type WorkflowHandler, type WorkflowInputOf, type WorkflowOutputOf, type WorkflowRef, type WorkflowRegistration, type WorkflowRun, type WorkflowStartClient, type WorkflowStepEvent, WorkflowSuspended, type WorkflowTask, aggregateAnnouncements, aggregatesCheckpoints, announcementsOf, applyAttributeQuery, assertConcurrency, assertRoutes, attributeColumnFor, attributeOperand, attributePredicateOperands, axisIsRunColumn, bindWorkflowClass, breakpointToken, buildWorkflowDirectory, canRoute, capableWorkers, checkpointNameKind, checkpointStatsOf, childIdsOf, classifyWaiterToken, clearDurableExecutionWrappers, clearTerminalSingletonAdmission, codeAndDetails, codeOf, collectMetrics, concurrencyTag, controlPlaneDescriptor, countRuns, coveredTokens, createStepLogger, currentStep, currentStepScope, currentWorkflowCtx, debug, describeWorker, descriptorHash, detailsOf, error, etagMatches, eventMatchOf, eventMatches, eventNameOf, eventPrefix, eventToken, facetOrigin, fanPageBounds, fanPageEtag, foldedCount, handoffHandlerId, handoffName, hasDurableExecutionWrappers, heartbeatStatus, indexWaitersByRun, info, isEngineMintedTag, isEventToken, isFailedMember, isLegacyDescriptor, isNonEmptyRunScope, isWorkflowControlFlowSignal, listSignalWaitersOfRuns, liveHandoff, log, matchesAttributes, mergeRunFacetRows, mergeRunValueFacetRows, missingCapabilities, negotiate, nextCronFireMs, normalizeAttributeRows, normalizeDescriptor, observedAnnouncements, onErrorRunId, pageFan, pageFanFromStore, parentRunIdOf, parseDuration, partitionOfToken, planDispatch, prevCronFireMs, queryCheckpointsOf, readSearchAttributes, requiredCapabilities, resolveConcurrency, resolveRouting, resolveRunWaiting, retiredHandoffName, routeFor, runDetailEtag, runDurableExecution, runInStepLogger, runInStepScope, runInWorkflowCtx, runOutsideWorkflowCtx, runSchedules, runStepHandler, runValueFacetsFromRuns, sanitizeQueueToken, scheduledRunId, singletonAdmissionDenialPatch, singletonAdmissionTags, sqlComparator, stepConfigOf, stepId, stepNameOf, sub, subEvent, subProcess, summarizeFan, summarizeRunFromStore, summarizeTimeline, tenantGroup, useDurableExecution, warn, workflowName };