@voltro/runtime 0.81.0 → 0.83.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.
@@ -4551,7 +4551,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
4551
4551
  SOFTWARE.
4552
4552
  ```
4553
4553
 
4554
- ## undici@8.10.0
4554
+ ## undici@8.11.2
4555
4555
 
4556
4556
  License: MIT
4557
4557
 
package/dist/index.d.ts CHANGED
@@ -68,16 +68,19 @@ import { MetricBoundaries } from 'effect';
68
68
  import { MetricReader } from '@opentelemetry/sdk-metrics';
69
69
  import { MutationIdempotencyScope } from '@voltro/protocol';
70
70
  import { NoRowFound } from '@voltro/protocol';
71
+ import { NoSuchResource } from '@voltro/protocol';
71
72
  import { PendingApproval } from '@voltro/protocol';
72
73
  import { PluginHttpRoute } from '@voltro/protocol';
73
74
  import { PluginHttpRouteByteStream } from '@voltro/protocol';
74
75
  import { PluginRefOrphanPolicy } from '@voltro/database';
75
76
  import { Predicate } from '@voltro/database';
77
+ import { ProcedureWireError } from '@voltro/protocol';
76
78
  import { PublicApiSpec } from '@voltro/protocol';
77
79
  import { Query } from '@voltro/database';
78
80
  import { QueryDescriptor } from '@voltro/database';
79
81
  import { Redis } from 'ioredis';
80
82
  import { registerRetention } from '@voltro/database';
83
+ import { ResourceMissing } from '@voltro/protocol';
81
84
  import { RestRouteDescriptor } from '@voltro/protocol/rest';
82
85
  import { RetentionConflict } from '@voltro/database';
83
86
  import { RetentionSource } from '@voltro/database';
@@ -132,6 +135,9 @@ import { WorkflowControlRequest } from '@voltro/workflow';
132
135
  import { WorkflowControlResult as WorkflowControlResult_2 } from '@voltro/protocol';
133
136
  import { WorkflowParentClosePolicy } from '@voltro/protocol';
134
137
  import { WorkflowQueuedCancellationResult } from '@voltro/protocol';
138
+ import { WorkflowRestartCommand } from '@voltro/protocol';
139
+ import { WorkflowRestartObservation } from '@voltro/protocol';
140
+ import { WorkflowRestartResult } from '@voltro/protocol';
135
141
  import { WorkflowRetryObservation } from '@voltro/protocol';
136
142
  import { WorkflowRunHandle } from '@voltro/protocol';
137
143
  import { WorkflowRunSnapshot as WorkflowRunSnapshot_2 } from '@voltro/protocol';
@@ -1793,7 +1799,7 @@ export declare const bindConnectionCredential: (clientId: number, credential: Co
1793
1799
  * interrupt registry subscriptions use — so one reconnect policy, one devtools
1794
1800
  * view, one connection lifecycle for both primitives.
1795
1801
  */
1796
- export declare const bindEvent: (input: BindEventInput) => Stream.Stream<EventStreamEvent<unknown>, ScopeError | Unauthenticated, SubjectService | ConnectionInfo>;
1802
+ export declare const bindEvent: (input: BindEventInput) => Stream.Stream<EventStreamEvent<unknown>, ScopeError | Unauthenticated | NoSuchResource, SubjectService | ConnectionInfo>;
1797
1803
 
1798
1804
  export declare interface BindEventInput {
1799
1805
  readonly bus: EventBus;
@@ -2639,6 +2645,12 @@ export declare interface CoordinatedScheduleDeps {
2639
2645
  * it holds. Without either, a REMOTE replica's enqueue produces no local
2640
2646
  * event, and a disarmed task would sleep through it forever. The backoff
2641
2647
  * ceiling exists for exactly that case and is the correct choice there.
2648
+ *
2649
+ * The task's half of the bargain: an idle tick disarms only when it returns
2650
+ * `nextDueInMs: null` ("nothing is scheduled"). Work that comes due on a
2651
+ * clock is not an arrival, so the tick reports its instant as `nextDueInMs`
2652
+ * and the task is armed for exactly then. An idle tick that says neither
2653
+ * backs off instead of disarming.
2642
2654
  */
2643
2655
  readonly disarmWhenIdle?: boolean;
2644
2656
  }
@@ -2705,16 +2717,25 @@ export declare interface CoordinatedTickOutcome {
2705
2717
  readonly idle: boolean;
2706
2718
  /**
2707
2719
  * Milliseconds until the earliest thing this task already knows is coming —
2708
- * a debounce window closing, a lease expiring. Caps the backoff, so a task
2709
- * that is idle RIGHT NOW but has a deadline in 400 ms is armed for 400 ms
2710
- * rather than for 30 s.
2720
+ * a debounce window closing, a lease expiring, a retry or a re-poll whose
2721
+ * time arrives. Caps the backoff, so a task that is idle RIGHT NOW but has a
2722
+ * deadline in 400 ms is armed for 400 ms rather than for 30 s.
2723
+ *
2724
+ * `null` is a statement, not an absence: "I looked, and nothing is scheduled
2725
+ * — the next piece of work can only arrive as a write". It is the ONLY idle
2726
+ * report that lets a `disarmWhenIdle` task stop ticking. Omitting the field
2727
+ * means "I did not say", and a task that did not say backs off toward the
2728
+ * ceiling instead of disarming.
2711
2729
  *
2712
- * This is the part a fixed interval cannot express and the part that makes
2713
- * the backoff safe: without it, backing off is a bet that nothing time-based
2714
- * is pending, and deferring controls are exactly the case where that bet is
2715
- * wrong.
2730
+ * The distinction exists because the failure is silent and permanent. Work
2731
+ * that becomes due on a CLOCK — a row released with a future `enqueuedAt`, a
2732
+ * lease that runs out — produces no write, so no change event, so no
2733
+ * `wake()`. A dispatcher that reported `{ idle: true }` while holding such a
2734
+ * row disarmed and never came back; the row sat until an unrelated write
2735
+ * happened to wake it. Making "nothing scheduled" an explicit answer turns a
2736
+ * forgotten deadline into a slower tick rather than a hang.
2716
2737
  */
2717
- readonly nextDueInMs?: number;
2738
+ readonly nextDueInMs?: number | null;
2718
2739
  }
2719
2740
 
2720
2741
  export declare type CoordinationOutcome = 'single' | 'wonLock' | 'lostLock' | 'external' | 'cluster';
@@ -3269,6 +3290,18 @@ export declare const decideApprovalInvocation: (input: {
3269
3290
  readonly status: "approved" | "rejected";
3270
3291
  }>;
3271
3292
 
3293
+ /**
3294
+ * `unknown` when the executor's failures are all declared; otherwise a type the
3295
+ * handler cannot satisfy, whose one property spells out the undeclared tag(s)
3296
+ * and the three ways to resolve them — that text is what the compile error at
3297
+ * the handler shows.
3298
+ */
3299
+ export declare type DeclaredFailureCheck<D extends ExecutorDescriptor, R> = [
3300
+ UndeclaredErrorTags<D, R>
3301
+ ] extends [never] ? unknown : {
3302
+ readonly undeclaredFailure: `'${UndeclaredErrorTags<D, R>}' is not in this procedure's wire union — add it to the descriptor's \`error:\`, register it through a plugin's \`errorSchemas\`, or map it away (Effect.orDie for a defect)`;
3303
+ };
3304
+
3272
3305
  /**
3273
3306
  * Decrypt a value produced by `encryptField` or by an `.encrypted()` column —
3274
3307
  * one encoding, so that sentence is now true in both directions.
@@ -3539,7 +3572,7 @@ export declare const defineEventTrigger: <EventPayload = unknown, WorkflowPayloa
3539
3572
  * Runtime identity — returns `fn` unchanged; the whole value is the compile-time
3540
3573
  * check. See the module header for the failure it prevents.
3541
3574
  */
3542
- export declare const defineExecutor: <D extends ExecutorDescriptor, F extends (input: ExecutorInput<D>, ctx: AppContext) => ExecutorReturn<D, unknown, unknown>>(_descriptor: D, fn: F) => ((input: ExecutorInput<D>, ctx: AppContext) => ReturnType<F>);
3575
+ export declare const defineExecutor: <D extends ExecutorDescriptor, F extends (input: ExecutorInput<D>, ctx: AppContext) => ExecutorReturn<D, unknown, unknown>>(_descriptor: D, fn: F & DeclaredFailureCheck<D, ReturnType<F>>) => ((input: ExecutorInput<D>, ctx: AppContext) => ReturnType<F>);
3543
3576
 
3544
3577
  /**
3545
3578
  * Declare a data-quality expectation. Validates the shape at declaration time so
@@ -3843,6 +3876,9 @@ export declare class Dispatcher {
3843
3876
  /** Query labels already warned about for an undeclared raw read, so a hot
3844
3877
  * subscription logs once rather than once per subscriber. */
3845
3878
  private readonly rawReadWarned;
3879
+ /** The CRDT-managed columns of `table` (empty when it has none) — what a
3880
+ * subscription's backpressure outbox folds incrementally. */
3881
+ crdtColumnsFor(table: string): ReadonlySet<string>;
3846
3882
  constructor(deps: DispatcherDependencies);
3847
3883
  /**
3848
3884
  * REL-14 — a raw read that nothing can invalidate, said out loud.
@@ -4100,7 +4136,10 @@ export declare interface DrainResult {
4100
4136
  */
4101
4137
  readonly scanned: number;
4102
4138
  /**
4103
- * When the earliest NOT-yet-due pending row comes due, as an epoch ms.
4139
+ * When the queue next has work that no write will announce, as an epoch ms:
4140
+ * the earliest NOT-yet-due pending row, or the earliest `delivering` claim
4141
+ * whose lease runs out (its deliverer may be gone, and the reclaim is due
4142
+ * then).
4104
4143
  *
4105
4144
  * `undefined` means nothing in the read window is waiting. A LOWER bound (the
4106
4145
  * window is capped by `batchSize`), which is the safe direction: understating
@@ -4108,7 +4147,10 @@ export declare interface DrainResult {
4108
4147
  *
4109
4148
  * This is what lets the runner arm for a backoff instead of polling until it
4110
4149
  * expires — the one thing in this loop that genuinely needs a clock, since a
4111
- * retry becoming due is not a write anybody can be notified about.
4150
+ * retry becoming due, or a lease running out, is not a write anybody can be
4151
+ * notified about. A runner that stopped ticking on an empty due window
4152
+ * without this would leave a lost deliverer's row claimed until something
4153
+ * unrelated wrote to the table.
4112
4154
  */
4113
4155
  readonly nextAttemptAt?: number;
4114
4156
  }
@@ -4700,8 +4742,13 @@ export declare interface ExecutorDescriptor {
4700
4742
  readonly kind: 'query' | 'mutation' | 'action';
4701
4743
  readonly input: Schema.Schema.Any;
4702
4744
  readonly output: Schema.Schema.Any;
4745
+ readonly error: Schema.Schema.All;
4703
4746
  }
4704
4747
 
4748
+ /** The failure type of an executor's return, when it returns an Effect. A
4749
+ * Promise's rejection is untyped and a plain value cannot fail. */
4750
+ declare type ExecutorFailure<R> = R extends Effect.Effect<infer _A, infer E, infer _R> ? E : never;
4751
+
4705
4752
  /** The decoded INPUT a handler receives (the Type side of the input schema). */
4706
4753
  export declare type ExecutorInput<D extends ExecutorDescriptor> = Schema.Schema.Type<D['input']>;
4707
4754
 
@@ -5304,6 +5351,14 @@ export declare type ExternalTriggerOutcome =
5304
5351
 
5305
5352
  export { extractDbCause }
5306
5353
 
5354
+ /** The literal `_tag`s of a failure type. `any` contributes none (nothing can
5355
+ * be proven about it); `UnknownException` — Effect's wrapper for a failure it
5356
+ * could not type, e.g. `Effect.tryPromise` without `catch` — counts as
5357
+ * untagged, which is what it means. */
5358
+ declare type FailureTag<E> = 0 extends (1 & E) ? never : E extends {
5359
+ readonly _tag: infer T;
5360
+ } ? T extends 'UnknownException' ? never : T extends string ? T : never : never;
5361
+
5307
5362
  export declare interface FieldChange {
5308
5363
  readonly from: unknown;
5309
5364
  readonly to: unknown;
@@ -6660,8 +6715,18 @@ export declare const makeEventPublisher: (ctx: EventPublishContext) => EventPubl
6660
6715
 
6661
6716
  export declare const makeEventsFacade: (options: EventsFacadeOptions) => EventsAppContext;
6662
6717
 
6663
- /** Convenience: derive a key from a passphrase and build the cipher. */
6664
- export declare const makeFieldCipher: (passphrase: string) => FieldCipher;
6718
+ /**
6719
+ * Derive a key from a passphrase and build the cipher — with the keys a
6720
+ * ROTATION retires, when there are any.
6721
+ *
6722
+ * Writes use the current key; reads try the current one, then each previous
6723
+ * one. GCM authenticates, so a wrong key fails its tag rather than producing
6724
+ * garbage, and trying them in turn is safe. Without this, a key change made
6725
+ * every value written before it unreadable — measured: every sleeping or
6726
+ * suspended run of an `encrypted: true` workflow failed its replay with
6727
+ * `MalformedMessage`, and every `.encrypted()` column read failed.
6728
+ */
6729
+ export declare const makeFieldCipher: (passphrase: string, previous?: ReadonlyArray<string>) => FieldCipher;
6665
6730
 
6666
6731
  /** Build the fluent `select` / `update` / `delete` entry functions over a
6667
6732
  * backend + scope. Wired into `wrapStoreWithMixinBehaviour` so they hang
@@ -7103,6 +7168,16 @@ declare interface MemoryRywOptions {
7103
7168
  */
7104
7169
  export declare const memoryRywPositionStore: (options?: MemoryRywOptions) => RywPositionStore;
7105
7170
 
7171
+ /**
7172
+ * Merge a compression result's headers onto a response's own. `Vary` is a
7173
+ * LIST: a route that already varies (`Vary: Authorization, Cookie` — a
7174
+ * cached answer that differs per credential) keeps its fields and gains
7175
+ * `Accept-Encoding`. Spreading the two objects instead let the lower-case
7176
+ * `vary` replace the route's `Vary` (HTTP header names are case-insensitive),
7177
+ * and a shared cache could then serve one caller's answer to another.
7178
+ */
7179
+ export declare const mergeCompressionHeaders: <V>(own: Readonly<Record<string, V>>, compression: Readonly<Record<string, string>>) => Record<string, V | string>;
7180
+
7106
7181
  /**
7107
7182
  * Merge a name→value map into a `Cookie` header string, replacing same-named
7108
7183
  * pairs and preserving every other cookie the connection carries.
@@ -7847,6 +7922,10 @@ export declare interface OutboxFacadeDeps {
7847
7922
  readonly afterCommit?: (work: () => Promise<unknown>) => void;
7848
7923
  /** Wake the drain loop. */
7849
7924
  readonly nudge?: () => void;
7925
+ /** The declared handler's `maxAttempts` for an effect. The row carries its
7926
+ * attempt budget from the moment it is enqueued, so this is where a
7927
+ * handler's `maxAttempts` takes effect; an enqueue's own option wins. */
7928
+ readonly maxAttemptsOf?: (effect: string) => number | undefined;
7850
7929
  readonly now?: () => Date;
7851
7930
  }
7852
7931
 
@@ -8857,7 +8936,7 @@ export declare const recordTableAccess: (table: string, op: ObservedOp) => void;
8857
8936
 
8858
8937
  /** Feed a committed change into the process recorder (gated + loop-safe). The
8859
8938
  * serve paths call this from their `store.onChange` tap. */
8860
- export declare const recordTimelineEvent: (change: CdcChange & {
8939
+ export declare const recordTimelineEvent: (change: CdcChange & Pick<ChangeEvent, "oversized" | "netChange"> & {
8861
8940
  readonly tenantId?: string | null;
8862
8941
  }) => void;
8863
8942
 
@@ -10691,10 +10770,13 @@ export declare type ScheduleFireInterceptor = (next: () => Promise<void>, ctx: S
10691
10770
  * thing that silently did nothing. Same bridge a file-based migration's `up`
10692
10771
  * has carried since it shipped.
10693
10772
  *
10694
- * The app supplies its outbound HttpClient, including its tracing and SSRF
10695
- * policy. Other requirements must be provided by the handler.
10773
+ * The app supplies its outbound HttpClient (tracing and SSRF policy
10774
+ * included) AND the same service layer a mutation handler runs under —
10775
+ * plugin services such as `MailService`, the app's own layers — so a schedule
10776
+ * may `yield*` them. Both `voltro dev` and `voltro serve` build the runner
10777
+ * from that layer; the type is open on requirements for exactly that reason.
10696
10778
  */
10697
- export declare type ScheduleHandler = (ctx: ScheduleContext) => void | Promise<void> | Effect.Effect<unknown, unknown, HttpClient.HttpClient>;
10779
+ export declare type ScheduleHandler = (ctx: ScheduleContext) => void | Promise<void> | Effect.Effect<unknown, unknown, HttpClient.HttpClient | unknown>;
10698
10780
 
10699
10781
  /** What happens when a firing arrives while the previous run of the
10700
10782
  * same schedule is still in flight. */
@@ -11792,6 +11874,19 @@ export declare interface SubscribeContext {
11792
11874
  * mutation instead — there it rides the commit.
11793
11875
  */
11794
11876
  readonly publish?: EventPublisher['publish'];
11877
+ /**
11878
+ * Durable delivery from a table change: a mail, a notification, a webhook
11879
+ * call. The same `_voltro_outbox` the request path's `ctx.outbox` writes, and
11880
+ * the same `*.outbox.ts` handlers deliver it, with retries.
11881
+ *
11882
+ * Present only when the app declares at least one `*.outbox.ts` handler, as
11883
+ * on the request path. The enqueue is NOT coupled to the change's commit —
11884
+ * that already happened — so it is durable from the enqueue on, not from the
11885
+ * write that triggered it. On more than one replica, pair it with `once:`, or
11886
+ * every replica enqueues the effect; or pass an `idempotencyKey` built from
11887
+ * the changed row.
11888
+ */
11889
+ readonly outbox?: OutboxFacade;
11795
11890
  }
11796
11891
 
11797
11892
  /** Event shape passed to a subscriber handler. Same as the
@@ -11899,6 +11994,19 @@ export declare interface SubscriptionBackpressureOptions {
11899
11994
  readonly oversizedEventBytes: number;
11900
11995
  /** Query tag for logs + metrics. */
11901
11996
  readonly label: string;
11997
+ /**
11998
+ * The subscription's CRDT columns (plan 18), when its table has any. Its
11999
+ * deltas carry those cells as INCREMENTAL updates (`mergeCells`), so the
12000
+ * rows kept here fold them into the held cells (`merge`), and a coalesced
12001
+ * patch diffs them incrementally again (`incremental`). Without it a held
12002
+ * cell would become the last increment, and a coalesced patch would REPLACE
12003
+ * the client's whole text with it.
12004
+ */
12005
+ readonly crdt?: {
12006
+ readonly columns: ReadonlySet<string>;
12007
+ readonly merge: (column: string, held: unknown, update: unknown) => unknown;
12008
+ readonly incremental: (column: string, prevValue: unknown, nextValue: unknown) => unknown | undefined;
12009
+ };
11902
12010
  readonly now?: () => number;
11903
12011
  readonly warn?: (message: string, fields: Record<string, unknown>) => void;
11904
12012
  }
@@ -12159,6 +12267,9 @@ export declare const TERMINAL_RUN_STATUSES: ReadonlySet<string>;
12159
12267
  export declare type TimeBucket = 'minute' | 'hour' | 'day' | 'week' | 'month';
12160
12268
 
12161
12269
  export declare interface TimelineEvent {
12270
+ /** Preserves the store's warning that images are not original commit images. */
12271
+ readonly oversized?: ChangeEvent['oversized'];
12272
+ readonly netChange?: ChangeEvent['netChange'];
12162
12273
  /** Monotonic per-process sequence — the scrubber's x-axis. */
12163
12274
  readonly seq: number;
12164
12275
  /** Wall-clock ms when recorded. */
@@ -12192,13 +12303,18 @@ export declare class TimelineRecorder {
12192
12303
  private readonly mode;
12193
12304
  private readonly capacity;
12194
12305
  private readonly now;
12306
+ /** Identity of this bounded history; sequence numbers are only meaningful within it. */
12307
+ private historyId;
12308
+ get recorderId(): string;
12309
+ /** A proven delivery gap makes every earlier reconstruction unsafe. */
12310
+ invalidate(): void;
12195
12311
  private readonly ring;
12196
12312
  private seqCounter;
12197
12313
  constructor(mode?: TimelineMode, capacity?: number, now?: () => number);
12198
12314
  get enabled(): boolean;
12199
12315
  /** Record one change (assigns the next seq, redacts, applies the mode gate +
12200
12316
  * the no-feedback skip). Returns the assigned seq, or -1 when skipped. */
12201
- record(change: CdcChange & {
12317
+ record(change: CdcChange & Pick<ChangeEvent, 'oversized' | 'netChange'> & {
12202
12318
  readonly tenantId?: string | null;
12203
12319
  }): number;
12204
12320
  /** The highest seq recorded so far (the scrubber's "now"). */
@@ -12482,6 +12598,17 @@ export declare const tryClaimWakeup: (store: DataStore, ref: WakeupRef) => Promi
12482
12598
  * `_voltro_rebac_tuples`; an app whose relationships live in its own tables
12483
12599
  * (a `teamMembers` row, say) registers its own instead of copying data into a
12484
12600
  * framework table.
12601
+ *
12602
+ * Return `'missing'` when the resource itself does not exist for this caller:
12603
+ * the guard then refuses with the typed `NoSuchResource` instead of
12604
+ * `ScopeError`, so an id-route can answer "not found" before its executor runs.
12605
+ * The source is the only place that can know — an empty tuple list means "no
12606
+ * relation", never "no row", because inferring absence from it would tell any
12607
+ * caller which ids exist. Decide the disclosure yourself: answer `'missing'`
12608
+ * from a tenant-scoped read (a row in another tenant then reads as missing, not
12609
+ * as "exists, not yours"), and never for a resource the caller could not have
12610
+ * learnt about otherwise. An anonymous caller never receives it, whatever the
12611
+ * source answers.
12485
12612
  */
12486
12613
  export declare type TupleSource = (req: {
12487
12614
  readonly subjectId: string | null;
@@ -12527,7 +12654,7 @@ export declare type TupleSource = (req: {
12527
12654
  * legitimately have no request.
12528
12655
  */
12529
12656
  readonly load: DataLoader | undefined;
12530
- }) => Promise<ReadonlyArray<RelationTuple>> | ReadonlyArray<RelationTuple>;
12657
+ }) => Promise<ReadonlyArray<RelationTuple> | ResourceMissing> | ReadonlyArray<RelationTuple> | ResourceMissing;
12531
12658
 
12532
12659
  /** The mutation runner's key for opening the read-version map on a transaction
12533
12660
  * view it obtained from the dialect store directly. */
@@ -12546,6 +12673,32 @@ declare interface TypedUpsertOptions<T extends AnyWritableTable> {
12546
12673
  */
12547
12674
  export declare const unbindConnection: (clientId: number) => void;
12548
12675
 
12676
+ /**
12677
+ * The tagged failures an executor can produce that its procedure's wire union
12678
+ * does not carry.
12679
+ *
12680
+ * Such a failure does not reach the caller as itself. On a mutation or action
12681
+ * the server refuses to encode a tag its union cannot represent and sends
12682
+ * `InternalError` instead; on a query it arrives under a tag the client's typed
12683
+ * union does not know. Either way the error the author raised is not the error
12684
+ * the caller can match on — and before this check, widening a shared helper's
12685
+ * error type compiled at every call site while every one of them started
12686
+ * failing that way.
12687
+ *
12688
+ * UNTAGGED failures (`Error`, `unknown`) are not reported: they never claimed to
12689
+ * be a typed outcome, and the runtime treats them as defects by construction.
12690
+ *
12691
+ * Nor are the STORE's refusals (`StoreError`: `ConstraintViolation`,
12692
+ * `TenantScopeViolation`, …). The framework raises them, not the handler's
12693
+ * author, and what an undeclared one does is a documented contract: it reaches
12694
+ * the caller as `InternalError` carrying its own sentence; declare it to surface
12695
+ * it typed. Every `EffectStore` write carries the whole set in its failure
12696
+ * channel, so counting them made the check fire on every write executor —
12697
+ * measured on one app: 550 of 564 findings, burying the 14 that were the
12698
+ * app's own tags, which is what this check exists to find.
12699
+ */
12700
+ export declare type UndeclaredErrorTags<D extends ExecutorDescriptor, R> = Exclude<FailureTag<ExecutorFailure<R>>, FailureTag<ProcedureWireError<D>> | FailureTag<StoreError>>;
12701
+
12549
12702
  export declare class UndeclaredTableAccess extends Error {
12550
12703
  readonly table: string;
12551
12704
  readonly operation: string;
@@ -13213,11 +13366,10 @@ export declare interface WorkflowFacadeOptions {
13213
13366
  * Inspect HTTP + the `voltro workflows retry` CLI delegate to the same
13214
13367
  * implementation. */
13215
13368
  readonly retry?: (runId: string, options: WorkflowRetryOptions) => Promise<WorkflowRetryResult>;
13216
- /** Backs {@link WorkflowsAppContext.redrive}. Supplied by the CLI's facade
13217
- * builder, which owns the runs/steps store query + the cluster journal
13218
- * adapter. Inspect HTTP + `voltro workflows redrive` delegate to the same
13219
- * implementation. */
13220
- readonly redrive?: (runId: string) => Promise<WorkflowRedriveResult>;
13369
+ /** Shared resident-authorized restart command and receipt adapters. */
13370
+ readonly restart?: (command: WorkflowRestartCommand) => Promise<WorkflowRestartResult>;
13371
+ readonly readRestart?: (target: Pick<WorkflowRestartCommand, 'runId' | 'requestId'>) => Promise<WorkflowRestartObservation>;
13372
+ readonly withdrawRestart?: (command: WorkflowRestartCommand) => Promise<WorkflowRestartObservation>;
13221
13373
  /** Fired (fire-and-forget) right after a workflow is ENQUEUED — a start,
13222
13374
  * child, or run. The CLI wires this to a cross-replica "wake" broadcast so
13223
13375
  * the replica that OWNS the new run's shard polls immediately instead of
@@ -13261,10 +13413,11 @@ export declare interface WorkflowFacadeOptions {
13261
13413
  * the failure this option exists to rule out.
13262
13414
  */
13263
13415
  readonly parkDelayedStart?: (input: {
13416
+ readonly requestId?: string;
13264
13417
  readonly workflowName: string;
13265
13418
  readonly payload: unknown;
13266
13419
  readonly callerContext: WorkflowCallerContext | undefined;
13267
- /** Epoch ms. Always strictly in the future — the facade handles the past. */
13420
+ /** Epoch ms. May be in the past for an identified, recoverable start. */
13268
13421
  readonly at: number;
13269
13422
  }) => Promise<{
13270
13423
  readonly receiptId: string;
@@ -13395,16 +13548,6 @@ export declare interface WorkflowReadCtx {
13395
13548
  } | undefined;
13396
13549
  }
13397
13550
 
13398
- /** Result of {@link WorkflowsAppContext.redrive} — whether the failed run's
13399
- * durable journal was re-driven, how many failed step attempts were reset so
13400
- * they re-execute, and a `reason` when it declined (no journal / still
13401
- * running / already succeeded). */
13402
- export declare interface WorkflowRedriveResult {
13403
- readonly redriven: boolean;
13404
- readonly activitiesReset: number;
13405
- readonly reason: string | null;
13406
- }
13407
-
13408
13551
  /** Options for {@link WorkflowsAppContext.retry}. */
13409
13552
  export declare interface WorkflowRetryOptions {
13410
13553
  /** Persist once per deliberate retry and reuse after a lost response. */
@@ -13592,14 +13735,13 @@ export declare interface WorkflowsAppContext {
13592
13735
  retry(runId: string, options: WorkflowRetryOptions): Promise<WorkflowRetryResult>;
13593
13736
  /** Observe a durable retry intent without submitting another attempt. */
13594
13737
  readRetry(runId: string, requestId: string): Promise<WorkflowRetryObservation>;
13595
- /** Re-drive a terminally-`failed` run from the step it died on, reusing
13596
- * its durable journal — the counterpart to {@link retry} (fresh execution,
13597
- * empty journal) and to {@link resume} (which only re-drives a *suspended*
13598
- * run). Addressed by run id (`wfrun_…`). Completed steps replay from the
13599
- * journal; only the failed steps re-execute. Fix the downstream cause
13600
- * first, then redrive. Refuses a run that is not a not-yet-discarded
13601
- * failure. */
13602
- redrive(runId: string): Promise<WorkflowRedriveResult>;
13738
+ /** Restart a failed run with its recorded successful steps. Persist the request
13739
+ * ID and selection before submitting; a pending receipt is not engine entry. */
13740
+ restart(runId: string, options: Omit<WorkflowRestartCommand, 'runId'>): Promise<WorkflowRestartResult>;
13741
+ /** Read a saved restart request without dispatching work. */
13742
+ readRestart(runId: string, requestId: string): Promise<WorkflowRestartObservation>;
13743
+ /** Permanently fence an unreserved request. Accepted work is returned unchanged. */
13744
+ withdrawRestart(runId: string, options: Omit<WorkflowRestartCommand, 'runId'>): Promise<WorkflowRestartObservation>;
13603
13745
  }
13604
13746
 
13605
13747
  export declare interface WorkflowSignalTarget {
@@ -13672,6 +13814,11 @@ export declare type WorkflowStartObservation = {
13672
13814
  };
13673
13815
 
13674
13816
  export declare interface WorkflowStartOptions {
13817
+ /** Stable caller intent for a recoverable durable start. Requires an explicit,
13818
+ * unchanged `at` instant on every retry. The same identity, workflow, tenant,
13819
+ * encoded payload and instant resolve to the original receipt.
13820
+ * Cannot be combined with a transactional or already-admitted start. */
13821
+ readonly requestId?: string;
13675
13822
  /* Excluded from this release type: preparedExecutionId */
13676
13823
  readonly wait?: boolean;
13677
13824
  /* Excluded from this release type: enqueueStart */
@@ -13693,7 +13840,7 @@ export declare interface WorkflowStartOptions {
13693
13840
  * judges it as of that moment; `at` never bypasses a control. The returned
13694
13841
  * handle has `status: 'queued'` with `deferral: { mode: 'delayed', dueAt }`.
13695
13842
  *
13696
- * An `at` in the past (or now) starts immediately — the caller said "no
13843
+ * Without `requestId`, an `at` in the past (or now) starts immediately — the caller said "no
13697
13844
  * earlier than", and that is already true. With `wait: true`, follow the
13698
13845
  * durable caller receipt through the delayed arrival and any further
13699
13846
  * admission deferral, then wait for the accepted execution's result.