@ai-digital-factory/state-flow-runtime 0.0.0-stage → 0.1.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.
@@ -0,0 +1,739 @@
1
+ import { z } from 'zod';
2
+
3
+ /** Base class for durable runtime rejections (infrastructure, defects, invalid input). */
4
+ declare class DurableRuntimeError extends Error {
5
+ constructor(message: string, options?: {
6
+ cause?: unknown;
7
+ });
8
+ }
9
+ /** Another runtime already owns the database (ADR 0047). */
10
+ declare class DurableOwnershipError extends DurableRuntimeError {
11
+ }
12
+ /** The runtime is closing or closed and admits no new work (ADR 0061). */
13
+ declare class DurableRuntimeClosedError extends DurableRuntimeError {
14
+ }
15
+ /**
16
+ * `close({ timeoutMs })` elapsed while callbacks were still running. The runtime keeps the
17
+ * database lock; exit the process to release it (ADR 0075).
18
+ */
19
+ declare class DurableShutdownTimeoutError extends DurableRuntimeError {
20
+ }
21
+ /** A compiled module failed startup validation before any handler ran (ADR 0046). */
22
+ declare class DurableDefinitionError extends DurableRuntimeError {
23
+ readonly problems: readonly string[];
24
+ constructor(chartName: string, problems: readonly string[]);
25
+ }
26
+ /** Input that cannot become trusted durable data (IDs, payloads, transitions). */
27
+ declare class DurableInputError extends DurableRuntimeError {
28
+ }
29
+ /** The database was written by a newer State Flow schema. */
30
+ declare class DurableSchemaError extends DurableRuntimeError {
31
+ }
32
+ /** A non-applied dispatch outcome routed to the application's shared failure handler. */
33
+ declare class DurableDispatchError extends DurableRuntimeError {
34
+ readonly outcome: Exclude<DispatchOutcome, "applied">;
35
+ readonly instanceId: InstanceId;
36
+ readonly context: unknown;
37
+ readonly phase: "dispatch";
38
+ constructor(outcome: Exclude<DispatchOutcome, "applied">, instanceId: InstanceId, context: unknown);
39
+ }
40
+ /** Runtime operation failures retain the original exception as cause. */
41
+ declare class DurableOperationError extends DurableRuntimeError {
42
+ readonly phase: "create-flow" | "ensure-instance" | "dispatch";
43
+ readonly outcome: "error";
44
+ constructor(phase: "create-flow" | "ensure-instance" | "dispatch", cause: unknown);
45
+ }
46
+ /** Stored instances remain untouched when their definition or handler revision is incompatible. */
47
+ declare class DurableDefinitionMismatchError extends DurableRuntimeError {
48
+ readonly context: DefinitionMismatchContext;
49
+ readonly phase: "ensure-instance";
50
+ readonly outcome: "definition-mismatch";
51
+ constructor(context: DefinitionMismatchContext);
52
+ }
53
+
54
+ /** Shared runtime contract for manual actions, also used by companion transports. */
55
+ declare const resolveInputSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
56
+ action: z.ZodLiteral<"retry">;
57
+ operationId: z.ZodPipe<z.ZodString, z.ZodTransform<OperationId, string>>;
58
+ expectedAttempts: z.ZodNumber;
59
+ reason: z.ZodString;
60
+ }, z.core.$strict>, z.ZodObject<{
61
+ action: z.ZodLiteral<"terminate">;
62
+ operationId: z.ZodPipe<z.ZodString, z.ZodTransform<OperationId, string>>;
63
+ expectedAttempts: z.ZodNumber;
64
+ reason: z.ZodString;
65
+ }, z.core.$strict>, z.ZodDiscriminatedUnion<[z.ZodObject<{
66
+ action: z.ZodLiteral<"confirm-completed">;
67
+ callback: z.ZodLiteral<"guard">;
68
+ result: z.ZodBoolean;
69
+ operationId: z.ZodPipe<z.ZodString, z.ZodTransform<OperationId, string>>;
70
+ expectedAttempts: z.ZodNumber;
71
+ reason: z.ZodString;
72
+ }, z.core.$strict>, z.ZodObject<{
73
+ action: z.ZodLiteral<"confirm-completed">;
74
+ callback: z.ZodLiteral<"resolve-start-state">;
75
+ result: z.ZodString;
76
+ operationId: z.ZodPipe<z.ZodString, z.ZodTransform<OperationId, string>>;
77
+ expectedAttempts: z.ZodNumber;
78
+ reason: z.ZodString;
79
+ }, z.core.$strict>, z.ZodPipe<z.ZodObject<{
80
+ action: z.ZodLiteral<"confirm-completed">;
81
+ callback: z.ZodEnum<{
82
+ "on-enter": "on-enter";
83
+ "on-exit": "on-exit";
84
+ "on-transition": "on-transition";
85
+ }>;
86
+ result: z.ZodOptional<z.ZodNull>;
87
+ operationId: z.ZodPipe<z.ZodString, z.ZodTransform<OperationId, string>>;
88
+ expectedAttempts: z.ZodNumber;
89
+ reason: z.ZodString;
90
+ }, z.core.$strict>, z.ZodTransform<{
91
+ action: "confirm-completed";
92
+ callback: "on-enter" | "on-exit" | "on-transition";
93
+ operationId: OperationId;
94
+ expectedAttempts: number;
95
+ reason: string;
96
+ }, {
97
+ action: "confirm-completed";
98
+ callback: "on-enter" | "on-exit" | "on-transition";
99
+ operationId: OperationId;
100
+ expectedAttempts: number;
101
+ reason: string;
102
+ result?: null | undefined;
103
+ }>>], "callback">], "action">;
104
+ type ParsedResolveInput = z.output<typeof resolveInputSchema>;
105
+ /** Parses untrusted input; graph membership and stale-target validation follow at execution. */
106
+ declare function parseResolveInput(value: unknown): ResolveInput<string>;
107
+
108
+ /**
109
+ * Public types for the durable runtime (ADRs 0046–0075).
110
+ *
111
+ * Handler authors use the callback types (`DurableGuard`, `DurableTransitionCallback`, …).
112
+ * Services use the outcome-handler, snapshot, and resolve types through `DurableRuntime`.
113
+ */
114
+ declare const durableIdKind: unique symbol;
115
+ type DurableId<Kind extends string> = string & {
116
+ readonly [durableIdKind]: Kind;
117
+ };
118
+ /** Application-supplied flow instance identity. Build with `instanceId(...)`. */
119
+ type InstanceId = DurableId<"instance">;
120
+ /** Application-supplied dispatch request identity. Build with `requestId(...)`. */
121
+ type RequestId = DurableId<"request">;
122
+ /** State Flow-generated logical callback operation identity, stable across attempts. */
123
+ type OperationId = DurableId<"operation">;
124
+ /** State Flow-generated identity of one execution or recovery attempt. */
125
+ type AttemptId = DurableId<"attempt">;
126
+ type JsonPrimitive = string | number | boolean | null;
127
+ type JsonValue = JsonPrimitive | readonly JsonValue[] | {
128
+ readonly [key: string]: JsonValue;
129
+ };
130
+ /**
131
+ * Maps `T` to its JSON-compatible shape. Members that cannot be persisted
132
+ * (functions, symbols, bigint, `undefined`, class instances with methods)
133
+ * become `never`, so `T` is only assignable to the result when it is JSON-compatible.
134
+ */
135
+ type JsonCompatible<T> = T extends JsonPrimitive ? T : T extends (...args: never[]) => unknown ? never : T extends bigint | symbol | undefined ? never : T extends readonly (infer Item)[] ? readonly JsonCompatible<Item>[] : T extends object ? {
136
+ [K in keyof T]: JsonCompatible<T[K]>;
137
+ } : never;
138
+ type IsJsonCompatible<T> = [unknown] extends [T] ? false : [T] extends [JsonCompatible<T>] ? true : false;
139
+ /** Transition names whose payload types are not JSON-compatible. */
140
+ type NonJsonPayloadTransitions<Payloads> = {
141
+ [T in keyof Payloads]: IsJsonCompatible<Payloads[T]> extends true ? never : T;
142
+ }[keyof Payloads];
143
+ type RecoveryStrategy = "safe-replay" | "reconcile" | "manual";
144
+ type DurableOperationInfo = {
145
+ readonly operationId: OperationId;
146
+ readonly attemptId: AttemptId;
147
+ /** 1 for the first run; increases with each run or reconciliation attempt. */
148
+ readonly attempt: number;
149
+ };
150
+ /** Fields State Flow adds to every durable callback context. */
151
+ type DurableExecutionContext = {
152
+ readonly instanceId: InstanceId;
153
+ readonly operation: DurableOperationInfo;
154
+ /** Cooperative cancellation, for example during runtime close (ADR 0068). */
155
+ readonly signal: AbortSignal;
156
+ };
157
+ type DurableContext<Context> = Context & DurableExecutionContext;
158
+ type RecoveryCause = "failed" | "interrupted";
159
+ type ReconcileContext<Context> = DurableContext<Context> & {
160
+ readonly recovery: {
161
+ /** `interrupted` when the process stopped while `run` was in flight. */
162
+ readonly cause: RecoveryCause;
163
+ readonly lastError: string | null;
164
+ };
165
+ };
166
+ /** `completed` carries the callback's result, except for callbacks that return nothing. */
167
+ type CompletedDecision<Result> = [Result] extends [void] ? {
168
+ readonly decision: "completed";
169
+ readonly result?: never;
170
+ } : {
171
+ readonly decision: "completed";
172
+ readonly result: Result;
173
+ };
174
+ /** Explicit reconciliation decisions (ADR 0064). */
175
+ type ReconcileDecision<Result> = CompletedDecision<Result> | {
176
+ readonly decision: "safe-to-retry";
177
+ } | {
178
+ readonly decision: "pending";
179
+ } | {
180
+ readonly decision: "needs-attention";
181
+ readonly reason: string;
182
+ };
183
+ /** Discriminated recovery declaration: only `reconcile` carries a reconcile function. */
184
+ type RecoveryDeclaration<Context, Args extends readonly unknown[], Result> = {
185
+ readonly strategy: "safe-replay";
186
+ readonly reconcile?: never;
187
+ } | {
188
+ readonly strategy: "manual";
189
+ readonly reconcile?: never;
190
+ } | {
191
+ readonly strategy: "reconcile";
192
+ readonly reconcile: (context: ReconcileContext<Context>, ...args: Args) => ReconcileDecision<Result> | Promise<ReconcileDecision<Result>>;
193
+ };
194
+ /** One implemented callback: its execution and its recovery declared together. */
195
+ type DurableCallback<Context, Args extends readonly unknown[], Result> = {
196
+ readonly run: (context: DurableContext<Context>, ...args: Args) => Result | Promise<Result>;
197
+ readonly recovery: RecoveryDeclaration<Context, Args, Result>;
198
+ };
199
+ /** `onEnter` / `onExit` in a durable state handler. */
200
+ type DurableStateCallback<Context> = DurableCallback<Context, [], void>;
201
+ /** `guard` in a durable transition handler. */
202
+ type DurableGuard<Context, Payload> = DurableCallback<Context, [
203
+ payload: Payload
204
+ ], boolean>;
205
+ /** `onTransition` in a durable transition handler. */
206
+ type DurableTransitionCallback<Context, Payload> = DurableCallback<Context, [
207
+ payload: Payload
208
+ ], void>;
209
+ /** `resolveStartState` in a durable creation handler. Return the initial state for ordinary creation. */
210
+ type DurableStartStateResolver<Context, StateName extends string> = DurableCallback<Context, [], StateName>;
211
+ /**
212
+ * `onEnter` receives the incoming transition (or `"default"` at creation); `onExit` receives the
213
+ * outgoing transition, so the two callbacks have different context types.
214
+ */
215
+ type DurableStateHooks<EntryContext, ExitContext> = {
216
+ readonly onEnter?: DurableStateCallback<EntryContext>;
217
+ readonly onExit?: DurableStateCallback<ExitContext>;
218
+ };
219
+ type DurableTransitionHooks<Context, Payload> = {
220
+ readonly guard?: DurableGuard<Context, Payload>;
221
+ readonly onTransition?: DurableTransitionCallback<Context, Payload>;
222
+ };
223
+ type DurableCreationHooks<Context, StateName extends string> = {
224
+ readonly resolveStartState?: DurableStartStateResolver<Context, StateName>;
225
+ };
226
+ type EndpointMapFor<StateName extends string> = Record<string, {
227
+ fromState: StateName;
228
+ toState: StateName;
229
+ }>;
230
+ type DurableHookTable = {
231
+ readonly states: Readonly<Record<string, DurableStateHooks<any, any> | null>>;
232
+ readonly transitions: Readonly<Record<string, DurableTransitionHooks<any, any> | null>>;
233
+ readonly creation: DurableCreationHooks<any, string> | null;
234
+ };
235
+ type DurableCompiledFlowModule<StateName extends string, TransitionPayloads extends Record<string, unknown>, FlowConfig, EndpointMap extends EndpointMapFor<StateName>, Hooks extends DurableHookTable> = {
236
+ readonly execution: "durable";
237
+ readonly chartName: string;
238
+ readonly initialStateId: string;
239
+ readonly states: ReadonlyArray<{
240
+ readonly id: string;
241
+ readonly name: StateName;
242
+ }>;
243
+ readonly transitions: ReadonlyArray<{
244
+ readonly fromId: string;
245
+ readonly fromName: StateName;
246
+ readonly toId: string;
247
+ readonly toName: StateName;
248
+ readonly name: Extract<keyof TransitionPayloads, string>;
249
+ readonly description: string;
250
+ }>;
251
+ readonly transitionEndpointMap: EndpointMap;
252
+ /** Runtime payload contracts; generated from each transition module's payloadSchema. */
253
+ readonly payloadSchemas: {
254
+ readonly [T in keyof TransitionPayloads]: z.ZodType<TransitionPayloads[T], TransitionPayloads[T]>;
255
+ };
256
+ readonly hooks: Hooks;
257
+ /**
258
+ * Hash of the chart's handler sources, written by compile. Unresolved work started under a
259
+ * different revision is not resumed (ADR 0049, 0075). `null` for hand-built modules.
260
+ */
261
+ readonly handlerRevision?: string | null;
262
+ readonly transitionPayloadSamples?: Readonly<Record<string, unknown>>;
263
+ readonly transitionPayloadTypeLabels?: Readonly<Record<string, string>>;
264
+ readonly __flowConfigBrand?: FlowConfig;
265
+ readonly __transitionPayloadsBrand?: TransitionPayloads;
266
+ } & DurablePayloadCheck<TransitionPayloads>;
267
+ /** Rejects a compiled module whose transition payloads are not JSON-compatible. */
268
+ type DurablePayloadCheck<TransitionPayloads> = [
269
+ NonJsonPayloadTransitions<TransitionPayloads>
270
+ ] extends [never] ? unknown : {
271
+ readonly "State Flow: transition payloads must be JSON-compatible": NonJsonPayloadTransitions<TransitionPayloads>;
272
+ };
273
+ /** States that have at least one outgoing transition. */
274
+ type StatesWithOutgoing<StateName extends string, EndpointMap extends EndpointMapFor<StateName>> = EndpointMap[keyof EndpointMap]["fromState"];
275
+ type OutgoingFrom<EndpointMap extends EndpointMapFor<string>, From extends string> = {
276
+ [K in keyof EndpointMap]: EndpointMap[K]["fromState"] extends From ? K & string : never;
277
+ }[keyof EndpointMap];
278
+ /** Dispatch input for a scoped dispatcher. Narrowing `transition` narrows `payload`. */
279
+ type DurableDispatchInput<TransitionPayloads extends Record<string, unknown>, EndpointMap extends EndpointMapFor<string>, From extends string> = {
280
+ [T in OutgoingFrom<EndpointMap, From>]: {
281
+ readonly requestId: RequestId;
282
+ readonly transition: T;
283
+ readonly payload: TransitionPayloads[T];
284
+ };
285
+ }[OutgoingFrom<EndpointMap, From>];
286
+ type CallbackRef<StateName extends string, TransitionName extends string> = {
287
+ readonly kind: "resolve-start-state";
288
+ } | {
289
+ readonly kind: "on-enter";
290
+ readonly state: StateName;
291
+ } | {
292
+ readonly kind: "on-exit";
293
+ readonly state: StateName;
294
+ } | {
295
+ readonly kind: "guard";
296
+ readonly transition: TransitionName;
297
+ } | {
298
+ readonly kind: "on-transition";
299
+ readonly transition: TransitionName;
300
+ };
301
+ type CallbackKind = CallbackRef<string, string>["kind"];
302
+ /** The unresolved callback blocking an instance. */
303
+ type UnresolvedWork<StateName extends string, TransitionName extends string> = {
304
+ readonly operationId: OperationId;
305
+ /** `null` while the instance is being created. */
306
+ readonly requestId: RequestId | null;
307
+ readonly callback: CallbackRef<StateName, TransitionName>;
308
+ readonly strategy: RecoveryStrategy;
309
+ readonly attempts: number;
310
+ readonly lastError: string | null;
311
+ /** ISO timestamp of the next automatic attempt, or `null` when none is scheduled. */
312
+ readonly nextAttemptAt: string | null;
313
+ };
314
+ type ExecutionStatus<StateName extends string, TransitionName extends string> = {
315
+ readonly kind: "ready";
316
+ } | {
317
+ readonly kind: "running";
318
+ readonly requestId: RequestId | null;
319
+ } | {
320
+ readonly kind: "recovering";
321
+ readonly work: UnresolvedWork<StateName, TransitionName>;
322
+ } | {
323
+ readonly kind: "needs-attention";
324
+ readonly work: UnresolvedWork<StateName, TransitionName>;
325
+ readonly reason: string;
326
+ } | {
327
+ readonly kind: "terminated";
328
+ readonly reason: string;
329
+ };
330
+ type DurableSnapshot<StateName extends string, TransitionName extends string> = {
331
+ readonly instanceId: InstanceId;
332
+ readonly chartName: string;
333
+ /** The committed authored state. Stays visible while post-commit work recovers (ADR 0060). */
334
+ readonly state: StateName;
335
+ /** Increases with every committed state or status change. */
336
+ readonly revision: number;
337
+ readonly status: ExecutionStatus<StateName, TransitionName>;
338
+ /**
339
+ * Set when an infrastructure error (for example a failing disk) stopped this instance's
340
+ * execution in this process. `status` then shows where it stopped; call `restartRecovery()`
341
+ * or open the instance again to resume from persisted state (ADR 0076).
342
+ */
343
+ readonly stall: {
344
+ readonly error: string;
345
+ readonly at: string;
346
+ } | null;
347
+ };
348
+ type HistoryEventType = "instance-created" | "execution-started" | "callback-started" | "callback-completed" | "callback-failed" | "recovery-scheduled" | "recovery-interrupted" | "state-committed" | "execution-applied" | "execution-blocked" | "needs-attention" | "manual-resolution" | "instance-terminated";
349
+ type HistoryEvent = {
350
+ readonly sequence: number;
351
+ readonly at: string;
352
+ readonly type: HistoryEventType;
353
+ readonly requestId: RequestId | null;
354
+ readonly operationId: OperationId | null;
355
+ readonly attemptId: AttemptId | null;
356
+ readonly data: JsonValue;
357
+ };
358
+ /** Bounded history query. Pages are in sequence order. */
359
+ type HistoryQuery = {
360
+ /** Return events after this sequence number (exclusive). Defaults to 0. */
361
+ readonly afterSequence?: number;
362
+ /** Defaults to 100; at most 1000. */
363
+ readonly limit?: number;
364
+ };
365
+ type HistoryPage = {
366
+ readonly events: readonly HistoryEvent[];
367
+ /** Pass as `afterSequence` for the next page; `null` when this page is the last. */
368
+ readonly nextAfterSequence: number | null;
369
+ };
370
+ type ExecutionStatusKind = ExecutionStatus<string, string>["kind"];
371
+ /** One row of an instance listing, read from storage without opening the instance. */
372
+ type InstanceSummary = {
373
+ readonly instanceId: InstanceId;
374
+ readonly chartName: string;
375
+ readonly state: string;
376
+ readonly status: ExecutionStatusKind;
377
+ /** Needs-attention or termination reason. */
378
+ readonly statusReason: string | null;
379
+ readonly revision: number;
380
+ readonly createdAt: string;
381
+ readonly updatedAt: string;
382
+ };
383
+ type InstanceQuery = {
384
+ readonly chartName?: string;
385
+ readonly status?: ExecutionStatusKind | readonly ExecutionStatusKind[];
386
+ /** Cursor from a previous page's `next`. */
387
+ readonly after?: string;
388
+ /** Defaults to 50; at most 500. */
389
+ readonly limit?: number;
390
+ };
391
+ type InstancePage = {
392
+ readonly instances: readonly InstanceSummary[];
393
+ /** Pass as `after` for the next page; `null` when this page is the last. */
394
+ readonly next: string | null;
395
+ };
396
+ type OutcomeHandler<Context> = (context: Context) => unknown;
397
+ /** Rejects handler keys outside the expected outcome set. */
398
+ type ExactHandlers<Handlers, Expected> = Handlers & {
399
+ readonly [K in Exclude<keyof Handlers, keyof Expected>]: never;
400
+ };
401
+ type HandlerResult<Handlers> = Awaited<{
402
+ [K in keyof Handlers]: Handlers[K] extends (...args: never[]) => infer R ? R : never;
403
+ }[keyof Handlers]>;
404
+ /** A rejected or historic payload has not been validated against the current contract. */
405
+ type UnvalidatedDispatchInput<Input> = Input extends unknown ? Omit<Input, "payload"> & {
406
+ readonly payload: unknown;
407
+ } : never;
408
+ type CompletedDispatchContext<Input, StateName extends string, TransitionName extends string> = {
409
+ readonly snapshot: DurableSnapshot<StateName, TransitionName>;
410
+ } & ({
411
+ readonly duplicate: false;
412
+ readonly input: Input;
413
+ } | {
414
+ readonly duplicate: true;
415
+ readonly input: UnvalidatedDispatchInput<Input>;
416
+ });
417
+ type DispatchOutcomeHandlers<StateName extends string, TransitionName extends string, Input, From extends StateName> = {
418
+ readonly applied: OutcomeHandler<CompletedDispatchContext<Input, StateName, TransitionName>>;
419
+ readonly "invalid-payload": OutcomeHandler<{
420
+ readonly input: UnvalidatedDispatchInput<Input>;
421
+ readonly issues: readonly {
422
+ readonly path: readonly PropertyKey[];
423
+ readonly message: string;
424
+ }[];
425
+ }>;
426
+ readonly blocked: OutcomeHandler<CompletedDispatchContext<Input, StateName, TransitionName>>;
427
+ readonly busy: OutcomeHandler<{
428
+ readonly input: Input;
429
+ readonly snapshot: DurableSnapshot<StateName, TransitionName>;
430
+ }>;
431
+ readonly "recovery-pending": OutcomeHandler<{
432
+ readonly input: Input;
433
+ readonly snapshot: DurableSnapshot<StateName, TransitionName>;
434
+ readonly work: UnresolvedWork<StateName, TransitionName>;
435
+ }>;
436
+ readonly "needs-attention": OutcomeHandler<{
437
+ readonly input: Input;
438
+ readonly snapshot: DurableSnapshot<StateName, TransitionName>;
439
+ readonly work: UnresolvedWork<StateName, TransitionName>;
440
+ readonly reason: string;
441
+ }>;
442
+ readonly "state-mismatch": OutcomeHandler<{
443
+ readonly input: Input;
444
+ readonly expectedState: From;
445
+ readonly actualState: StateName;
446
+ readonly snapshot: DurableSnapshot<StateName, TransitionName>;
447
+ }>;
448
+ readonly "request-conflict": OutcomeHandler<{
449
+ readonly input: UnvalidatedDispatchInput<Input>;
450
+ readonly recorded: {
451
+ readonly fromState: StateName;
452
+ readonly transition: TransitionName;
453
+ readonly payload: JsonValue;
454
+ };
455
+ }>;
456
+ readonly terminated: OutcomeHandler<{
457
+ readonly input: Input;
458
+ readonly snapshot: DurableSnapshot<StateName, TransitionName>;
459
+ readonly reason: string;
460
+ }>;
461
+ };
462
+ type DispatchOutcome = keyof DispatchOutcomeHandlers<string, string, unknown, string>;
463
+ /** Success information returned by direct awaited dispatch. */
464
+ type AppliedDispatchContext<Input, StateName extends string, TransitionName extends string> = CompletedDispatchContext<Input, StateName, TransitionName>;
465
+ /** A non-applied outcome, with its context correlated to its discriminator. */
466
+ type DispatchFailure<StateName extends string, TransitionName extends string, Input, From extends StateName> = {
467
+ [Outcome in Exclude<DispatchOutcome, "applied">]: DurableDispatchError & {
468
+ readonly outcome: Outcome;
469
+ readonly context: Parameters<DispatchOutcomeHandlers<StateName, TransitionName, Input, From>[Outcome]>[0];
470
+ };
471
+ }[Exclude<DispatchOutcome, "applied">];
472
+ /** Shared application policy for setup, acquisition and non-applied dispatch outcomes. */
473
+ type FlowFailure<StateName extends string, TransitionName extends string, Input, From extends StateName> = DurableOperationError | DurableDefinitionMismatchError | DispatchFailure<StateName, TransitionName, Input, From>;
474
+ type CreateOutcomeHandlers<Instance, StateName extends string, TransitionName extends string> = {
475
+ readonly created: OutcomeHandler<{
476
+ readonly instance: Instance;
477
+ readonly snapshot: DurableSnapshot<StateName, TransitionName>;
478
+ }>;
479
+ readonly "already-exists": OutcomeHandler<{
480
+ readonly instanceId: InstanceId;
481
+ }>;
482
+ readonly "recovery-pending": OutcomeHandler<{
483
+ readonly instance: Instance;
484
+ readonly snapshot: DurableSnapshot<StateName, TransitionName>;
485
+ readonly work: UnresolvedWork<StateName, TransitionName>;
486
+ }>;
487
+ readonly "needs-attention": OutcomeHandler<{
488
+ readonly instance: Instance;
489
+ readonly snapshot: DurableSnapshot<StateName, TransitionName>;
490
+ readonly work: UnresolvedWork<StateName, TransitionName>;
491
+ readonly reason: string;
492
+ }>;
493
+ };
494
+ type OpenOutcomeHandlers<Instance, StateName extends string, TransitionName extends string> = {
495
+ /** Recovery of interrupted work has started (not finished) when this runs (ADR 0050). */
496
+ readonly opened: OutcomeHandler<{
497
+ readonly instance: Instance;
498
+ readonly snapshot: DurableSnapshot<StateName, TransitionName>;
499
+ }>;
500
+ readonly "not-found": OutcomeHandler<{
501
+ readonly instanceId: InstanceId;
502
+ }>;
503
+ readonly "definition-mismatch": OutcomeHandler<{
504
+ /** The chart graph or recovery declarations changed. */
505
+ readonly reason: "definition";
506
+ readonly instanceId: InstanceId;
507
+ readonly message: string;
508
+ readonly storedChartName: string;
509
+ readonly storedDefinitionId: string;
510
+ readonly currentDefinitionId: string;
511
+ } | {
512
+ /** Handler code changed while this instance had unresolved work. */
513
+ readonly reason: "handler-revision";
514
+ readonly instanceId: InstanceId;
515
+ readonly message: string;
516
+ readonly storedHandlerRevision: string | null;
517
+ readonly currentHandlerRevision: string | null;
518
+ }>;
519
+ };
520
+ type DefinitionMismatchContext = Parameters<OpenOutcomeHandlers<unknown, string, string>["definition-mismatch"]>[0];
521
+ /** Acquisition does not imply readiness; dispatch maps execution statuses exhaustively. */
522
+ type EnsureOutcomeHandlers = {
523
+ /** Must throw/reject or transfer control; an incompatible instance cannot be returned. */
524
+ readonly "definition-mismatch": (mismatch: Parameters<OpenOutcomeHandlers<unknown, string, string>["definition-mismatch"]>[0]) => never | Promise<never>;
525
+ };
526
+ type ResolveInput<StateName extends string> = Exclude<ParsedResolveInput, {
527
+ callback: "resolve-start-state";
528
+ }> | (Omit<Extract<ParsedResolveInput, {
529
+ callback: "resolve-start-state";
530
+ }>, "result"> & {
531
+ readonly result: StateName;
532
+ });
533
+ type ResolveRejection =
534
+ /** Inspector only: no registered flow can load this instance (unknown chart or definition mismatch). */
535
+ "unavailable"
536
+ /**
537
+ * The operation is not the instance's current unresolved work awaiting attention, or it has
538
+ * had attempts since `expectedAttempts`.
539
+ */
540
+ | "stale"
541
+ /** `callback` does not match the unresolved callback. */
542
+ | "callback-mismatch"
543
+ /** `result` does not satisfy the callback's result contract. */
544
+ | "invalid-result";
545
+ type ResolveResult<StateName extends string, TransitionName extends string> = {
546
+ readonly outcome: "accepted";
547
+ readonly snapshot: DurableSnapshot<StateName, TransitionName>;
548
+ } | {
549
+ readonly outcome: "rejected";
550
+ readonly reason: ResolveRejection;
551
+ readonly message: string;
552
+ };
553
+ /** Application mapping for each manual-resolution outcome. */
554
+ type ResolveOutcomeHandlers<StateName extends string, TransitionName extends string> = {
555
+ readonly accepted: (context: Extract<ResolveResult<StateName, TransitionName>, {
556
+ outcome: "accepted";
557
+ }>) => unknown;
558
+ readonly rejected: (context: Extract<ResolveResult<StateName, TransitionName>, {
559
+ outcome: "rejected";
560
+ }>) => unknown;
561
+ };
562
+ type RestartOutcomeHandlers = {
563
+ readonly restarted: () => unknown;
564
+ readonly "not-restarted": () => unknown;
565
+ };
566
+
567
+ type DurableRuntimeOptions = {
568
+ /** Persistent SQLite file owned by State Flow, or `":memory:"` for disposable runs. */
569
+ readonly databasePath: string;
570
+ /** Receives subscriber failures, which never affect execution (ADR 0059). Defaults to console.error. */
571
+ readonly onObserverError?: (error: unknown) => void;
572
+ /**
573
+ * Receives infrastructure errors from background recovery, which has no caller to reject.
574
+ * The affected instance resumes recovery when it is opened again. Defaults to console.error.
575
+ */
576
+ readonly onRecoveryError?: (error: unknown) => void;
577
+ };
578
+ type DurableRuntime = {
579
+ /** Prepare flow registration; no definition validation or registration happens until run(). */
580
+ createFlow<StateName extends string, TransitionPayloads extends Record<string, unknown>, FlowConfig, EndpointMap extends EndpointMapFor<StateName>, Hooks extends DurableHookTable>(compiled: DurableCompiledFlowModule<StateName, TransitionPayloads, FlowConfig, EndpointMap, Hooks> & DurablePayloadCheck<TransitionPayloads>, config: FlowConfig): CreateFlowBuilder<StateName, TransitionPayloads, EndpointMap>;
581
+ /**
582
+ * Registers a durable compiled module with its dependencies. Validates every handler's
583
+ * recovery declaration before any handler runs (ADR 0046).
584
+ */
585
+ flow<StateName extends string, TransitionPayloads extends Record<string, unknown>, FlowConfig, EndpointMap extends EndpointMapFor<StateName>, Hooks extends DurableHookTable>(compiled: DurableCompiledFlowModule<StateName, TransitionPayloads, FlowConfig, EndpointMap, Hooks> & DurablePayloadCheck<TransitionPayloads>, config: FlowConfig): DurableFlow<StateName, TransitionPayloads, EndpointMap>;
586
+ /**
587
+ * Stops admission and recovery scheduling, aborts handler signals, lets active work checkpoint,
588
+ * and releases the database (ADR 0061). With `timeoutMs`, rejects with
589
+ * `DurableShutdownTimeoutError` if callbacks are still running; the lock is kept until they
590
+ * settle or the process exits.
591
+ */
592
+ close(options?: {
593
+ readonly timeoutMs?: number;
594
+ }): Promise<void>;
595
+ /**
596
+ * Cross-instance access for operator tools such as the companion UI: listing, snapshots and
597
+ * history straight from storage, runtime-wide subscriptions, and manual resolution. The
598
+ * application authorizes every resolve call it forwards (ADR 0062, 0063).
599
+ */
600
+ readonly inspector: DurableInspector;
601
+ /** Explicit operator capability; pass inspector alone to read-only tools. */
602
+ readonly controls: DurableControls;
603
+ };
604
+ type DurableInspector = {
605
+ listInstances(query?: InstanceQuery): InstancePage;
606
+ /** `null` when no instance has this ID. */
607
+ getSnapshot(instanceId: InstanceId): DurableSnapshot<string, string> | null;
608
+ history(instanceId: InstanceId, query?: HistoryQuery): HistoryPage;
609
+ /** Snapshots of every instance this runtime executes, after each change. */
610
+ subscribe(listener: (snapshot: DurableSnapshot<string, string>) => unknown): () => void;
611
+ };
612
+ type DurableControls = {
613
+ /**
614
+ * Resolves unresolved work using the flow registered for the instance's chart, opening the
615
+ * instance if needed. When no registered flow can load it (unknown chart, definition or
616
+ * handler-revision mismatch), only `terminate` is accepted, and it runs no handler; other
617
+ * actions return `unavailable`.
618
+ */
619
+ resolve(instanceId: InstanceId, input: ResolveInput<string>): Promise<ResolveResult<string, string>>;
620
+ /** Restarts recovery of a stalled instance this runtime has loaded. False if nothing to restart. */
621
+ restartRecovery(instanceId: InstanceId): boolean;
622
+ };
623
+ type TransitionNameOf<TransitionPayloads> = Extract<keyof TransitionPayloads, string>;
624
+ type CreateFlowBuilder<StateName extends string, TransitionPayloads extends Record<string, unknown>, EndpointMap extends EndpointMapFor<StateName>> = {
625
+ handleFailure(onFailure: (failure: FlowFailure<StateName, TransitionNameOf<TransitionPayloads>, DurableDispatchInput<TransitionPayloads, EndpointMap, StatesWithOutgoing<StateName, EndpointMap>>, StatesWithOutgoing<StateName, EndpointMap>>) => never | Promise<never>): {
626
+ run(): Promise<DurableFlow<StateName, TransitionPayloads, EndpointMap, true, true>>;
627
+ };
628
+ };
629
+ type EnsureInstanceBuilder<StateName extends string, TransitionPayloads extends Record<string, unknown>, EndpointMap extends EndpointMapFor<StateName>> = {
630
+ run(): Promise<DurableInstance<StateName, TransitionPayloads, EndpointMap, true>>;
631
+ handleEnsureInstance<Handlers extends EnsureOutcomeHandlers>(handlers: ExactHandlers<Handlers, EnsureOutcomeHandlers>): {
632
+ run(): Promise<DurableInstance<StateName, TransitionPayloads, EndpointMap, true>>;
633
+ };
634
+ };
635
+ type DurableFlow<StateName extends string, TransitionPayloads extends Record<string, unknown>, EndpointMap extends EndpointMapFor<StateName>, HasDispatchPolicy extends boolean = false, HasFlowFailurePolicy extends boolean = false> = {
636
+ readonly chartName: string;
637
+ readonly definitionId: string;
638
+ /** Prepare acquisition using the inherited failure policy. */
639
+ ensureInstance: HasFlowFailurePolicy extends true ? (input: {
640
+ readonly instanceId: InstanceId;
641
+ }) => EnsureInstanceBuilder<StateName, TransitionPayloads, EndpointMap> : never;
642
+ /** Configure one shared handler for every non-applied direct dispatch outcome. */
643
+ handleDispatch: HasDispatchPolicy extends true ? never : (onFailure: (failure: DispatchFailure<StateName, TransitionNameOf<TransitionPayloads>, DurableDispatchInput<TransitionPayloads, EndpointMap, StatesWithOutgoing<StateName, EndpointMap>>, StatesWithOutgoing<StateName, EndpointMap>>) => never | Promise<never>) => DurableFlow<StateName, TransitionPayloads, EndpointMap, true, HasFlowFailurePolicy>;
644
+ /** Opens an existing instance or creates it once, starting recovery when needed. */
645
+ handleEnsure<Handlers extends EnsureOutcomeHandlers>(handlers: ExactHandlers<Handlers, EnsureOutcomeHandlers>): {
646
+ ensure(input: {
647
+ readonly instanceId: InstanceId;
648
+ }): Promise<DurableInstance<StateName, TransitionPayloads, EndpointMap, HasDispatchPolicy>>;
649
+ };
650
+ /** Prepares reusable instance creation with every creation outcome handled (ADR 0067). */
651
+ handleCreate<Handlers extends CreateOutcomeHandlers<DurableInstance<StateName, TransitionPayloads, EndpointMap, HasDispatchPolicy>, StateName, TransitionNameOf<TransitionPayloads>>>(handlers: ExactHandlers<Handlers, CreateOutcomeHandlers<unknown, StateName, TransitionNameOf<TransitionPayloads>>>): {
652
+ create(input: {
653
+ readonly instanceId: InstanceId;
654
+ /** Skip `resolveStartState` and start (or restore) at this state. */
655
+ readonly startState?: StateName;
656
+ }): Promise<HandlerResult<Handlers>>;
657
+ };
658
+ /** Prepares reusable instance opening with every opening outcome handled (ADR 0067). */
659
+ handleOpen<Handlers extends OpenOutcomeHandlers<DurableInstance<StateName, TransitionPayloads, EndpointMap, HasDispatchPolicy>, StateName, TransitionNameOf<TransitionPayloads>>>(handlers: ExactHandlers<Handlers, OpenOutcomeHandlers<unknown, StateName, TransitionNameOf<TransitionPayloads>>>): {
660
+ open(instanceId: InstanceId): Promise<HandlerResult<Handlers>>;
661
+ };
662
+ };
663
+ type DurableInstance<StateName extends string, TransitionPayloads extends Record<string, unknown>, EndpointMap extends EndpointMapFor<StateName>, HasDispatchPolicy extends boolean = false> = {
664
+ readonly instanceId: InstanceId;
665
+ getSnapshot(): DurableSnapshot<StateName, TransitionNameOf<TransitionPayloads>>;
666
+ /** Called after every committed state or status change. Returns an unsubscribe function. */
667
+ subscribe(listener: (snapshot: DurableSnapshot<StateName, TransitionNameOf<TransitionPayloads>>) => unknown): () => void;
668
+ /** One page of this instance's execution history (ADR 0072). */
669
+ history(query?: HistoryQuery): HistoryPage;
670
+ /** Direct dispatch requires a shared flow failure policy; `handle` supports explicit local mapping. */
671
+ when<From extends StatesWithOutgoing<StateName, EndpointMap>>(state: From): (HasDispatchPolicy extends true ? {
672
+ dispatch(input: DurableDispatchInput<TransitionPayloads, EndpointMap, From>): Promise<AppliedDispatchContext<DurableDispatchInput<TransitionPayloads, EndpointMap, From>, StateName, TransitionNameOf<TransitionPayloads>>>;
673
+ } : Record<never, never>) & {
674
+ handle<Handlers extends DispatchOutcomeHandlers<StateName, TransitionNameOf<TransitionPayloads>, DurableDispatchInput<TransitionPayloads, EndpointMap, From>, From>>(handlers: ExactHandlers<Handlers, DispatchOutcomeHandlers<StateName, string, unknown, From>>): {
675
+ dispatch(input: DurableDispatchInput<TransitionPayloads, EndpointMap, From>): Promise<HandlerResult<Handlers>>;
676
+ };
677
+ };
678
+ /** Exhaustive outcome mapping for manual actions; raw resolve remains the operator primitive. */
679
+ handleResolve<Handlers extends ResolveOutcomeHandlers<StateName, TransitionNameOf<TransitionPayloads>>>(handlers: ExactHandlers<Handlers, ResolveOutcomeHandlers<StateName, TransitionNameOf<TransitionPayloads>>>): {
680
+ resolve(input: ResolveInput<StateName>): Promise<HandlerResult<Handlers>>;
681
+ };
682
+ handleRestart<Handlers extends RestartOutcomeHandlers>(handlers: ExactHandlers<Handlers, RestartOutcomeHandlers>): {
683
+ restart(): HandlerResult<Handlers> | Promise<HandlerResult<Handlers>>;
684
+ };
685
+ /** @deprecated Application instances use handleResolve; raw resolution is for trusted operator tooling. */
686
+ resolve(input: ResolveInput<StateName>): Promise<ResolveResult<StateName, TransitionNameOf<TransitionPayloads>>>;
687
+ /**
688
+ * @deprecated Application instances use handleRestart; raw restart is for trusted operator tooling.
689
+ * Returns false when the instance is not stalled or is executing.
690
+ */
691
+ restartRecovery(): boolean;
692
+ };
693
+ declare function createDurableRuntime(options: DurableRuntimeOptions): DurableRuntime;
694
+
695
+ /** Validates an application-supplied flow instance identity. */
696
+ declare function instanceId(value: string): InstanceId;
697
+ /** Validates an application-supplied dispatch request identity. */
698
+ declare function requestId(value: string): RequestId;
699
+
700
+ /**
701
+ * The one built-in bounded recovery policy (ADR 0066, values in ADR 0075).
702
+ * An operation gets at most this many attempts in total, counting its first run,
703
+ * replays, and reconciliation checks. Attempts survive restarts.
704
+ */
705
+ declare const MAX_ATTEMPTS = 4;
706
+ /** Delay before the next automatic attempt, indexed by attempts already used minus one. */
707
+ declare const RECOVERY_DELAYS_MS: readonly [1000, 5000, 30000];
708
+
709
+ type RuntimeOptions = DurableRuntimeOptions & {
710
+ readonly shutdownTimeoutMs?: number;
711
+ };
712
+ /** A standalone runtime whose asynchronous disposal releases its database ownership. */
713
+ type ManagedRuntime = DurableRuntime & {
714
+ [Symbol.asyncDispose](): Promise<void>;
715
+ };
716
+ /** Use `await using runtime = createRuntime(options)` for automatic cleanup at scope exit. */
717
+ declare function createRuntime(options: RuntimeOptions): ManagedRuntime;
718
+
719
+ /** Owns runtime cleanup even when registration, execution, or response handling throws. */
720
+ declare function withDurableRuntime<Result>(options: RuntimeOptions, run: (runtime: DurableRuntime) => Result | Promise<Result>): Promise<Awaited<Result>>;
721
+
722
+ type TargetBase<StateName extends string> = {
723
+ retry(reason: string): ResolveInput<StateName>;
724
+ terminate(reason: string): ResolveInput<StateName>;
725
+ };
726
+ /** Immutable captured target: refreshing a snapshot cannot silently retarget an operator's action. */
727
+ type RecoveryTarget<StateName extends string> = TargetBase<StateName> & ({
728
+ readonly callback: "guard";
729
+ confirm(result: boolean, reason: string): ResolveInput<StateName>;
730
+ } | {
731
+ readonly callback: "resolve-start-state";
732
+ confirm(result: StateName, reason: string): ResolveInput<StateName>;
733
+ } | {
734
+ readonly callback: "on-enter" | "on-exit" | "on-transition";
735
+ confirm(reason: string): ResolveInput<StateName>;
736
+ });
737
+ declare function recoveryTarget<StateName extends string>(work: UnresolvedWork<StateName, string>): RecoveryTarget<StateName>;
738
+
739
+ export { type AppliedDispatchContext, type AttemptId, type CallbackKind, type CallbackRef, type CompletedDecision, type CreateFlowBuilder, type CreateOutcomeHandlers, type DefinitionMismatchContext, type DispatchFailure, type DispatchOutcome, type DispatchOutcomeHandlers, type DurableCallback, type DurableCompiledFlowModule, type DurableContext, type DurableControls, type DurableCreationHooks, DurableDefinitionError, DurableDefinitionMismatchError, DurableDispatchError, type DurableDispatchInput, type DurableExecutionContext, type DurableFlow, type DurableGuard, type DurableHookTable, DurableInputError, type DurableInspector, type DurableInstance, DurableOperationError, type DurableOperationInfo, DurableOwnershipError, type DurablePayloadCheck, type DurableRuntime, DurableRuntimeClosedError, DurableRuntimeError, type DurableRuntimeOptions, DurableSchemaError, DurableShutdownTimeoutError, type DurableSnapshot, type DurableStartStateResolver, type DurableStateCallback, type DurableStateHooks, type DurableTransitionCallback, type DurableTransitionHooks, type EndpointMapFor, type EnsureInstanceBuilder, type EnsureOutcomeHandlers, type ExactHandlers, type ExecutionStatus, type ExecutionStatusKind, type FlowFailure, type HandlerResult, type HistoryEvent, type HistoryEventType, type HistoryPage, type HistoryQuery, type InstanceId, type InstancePage, type InstanceQuery, type InstanceSummary, type IsJsonCompatible, type JsonCompatible, type JsonPrimitive, type JsonValue, MAX_ATTEMPTS, type ManagedRuntime, type NonJsonPayloadTransitions, type OpenOutcomeHandlers, type OperationId, type OutgoingFrom, RECOVERY_DELAYS_MS, type ReconcileContext, type ReconcileDecision, type RecoveryCause, type RecoveryDeclaration, type RecoveryStrategy, type RecoveryTarget, type RequestId, type ResolveInput, type ResolveOutcomeHandlers, type ResolveRejection, type ResolveResult, type RestartOutcomeHandlers, type RuntimeOptions, type StatesWithOutgoing, type UnresolvedWork, type UnvalidatedDispatchInput, createDurableRuntime, createRuntime, instanceId, parseResolveInput, recoveryTarget, requestId, resolveInputSchema, withDurableRuntime };