@dudousxd/nestjs-durable-core 0.50.1 → 0.52.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
@@ -1749,6 +1749,59 @@ declare function runInWorkflowCtx<T>(ctx: WorkflowCtx, fn: () => T): T;
1749
1749
  */
1750
1750
  declare function currentWorkflowCtx(): WorkflowCtx | undefined;
1751
1751
 
1752
+ /**
1753
+ * Cross-package, cross-runtime marker for engine CONTROL-FLOW signals — {@link WorkflowSuspended}
1754
+ * and {@link ContinueAsNew} (this package), plus the thin worker's {@link
1755
+ * import('@dudousxd/durable-worker').Suspend} (`@dudousxd/durable-worker`, the BullMQ
1756
+ * route-by-handler runtime). These are thrown by `WorkflowCtx`/`WorkflowContext` ops to unwind the
1757
+ * current turn — never real failures — so a workflow's `catch` block MUST rethrow them untouched.
1758
+ * Running a failure/cleanup path on a control-flow signal corrupts the run: it emits extra
1759
+ * `recordStep` commands into history that a subsequent replay didn't produce the first time,
1760
+ * surfacing as a `NonDeterminismError`/`NondeterminismError` on resume.
1761
+ *
1762
+ * `Symbol.for` (the GLOBAL registry), NOT a plain `Symbol()` — so a duplicate copy of this module
1763
+ * (pnpm peer-dependency multiplexing, a dual ESM/CJS load, or the SEPARATE `@dudousxd/durable-worker`
1764
+ * package declaring the same `Symbol.for` key locally) still collapses onto the SAME symbol. Same
1765
+ * rationale as `DURABLE_STEP_NAME` in `./step-name-symbol.ts`.
1766
+ *
1767
+ * Deliberately checked as a stamped property, NOT `instanceof` — `instanceof` only recognizes a
1768
+ * signal thrown by the SAME class the checking code imported, which fails across the in-process
1769
+ * engine (`@dudousxd/nestjs-durable-core`'s `WorkflowSuspended`/`ContinueAsNew`) and the thin worker
1770
+ * (`@dudousxd/durable-worker`'s `Suspend`) — two different classes for what is, from a workflow
1771
+ * author's catch block, the same "this isn't a real error, let it through" event.
1772
+ *
1773
+ * NOT designed to survive a serialization boundary (e.g. JSON over the wire) — these signals are
1774
+ * always thrown and caught in-process within a single replay turn, never (de)serialized, so a
1775
+ * stamped-but-not-cloneable property is sufficient.
1776
+ */
1777
+ declare const CONTROL_FLOW_SIGNAL: unique symbol;
1778
+ /**
1779
+ * True for any engine control-flow signal (currently: {@link WorkflowSuspended}, {@link
1780
+ * ContinueAsNew}, and the thin worker's `Suspend`) — regardless of which runtime or module instance
1781
+ * threw it. Workflow `catch` blocks MUST rethrow these untouched; running a failure/cleanup path on
1782
+ * one corrupts the run's history (extra commands recorded during what replay will later see as a
1783
+ * suspend, not a failure) and the resumed replay dies with a non-determinism error.
1784
+ *
1785
+ * Deliberately NOT control-flow (do not add to this predicate):
1786
+ * - `Cancelled` (worker) / a cancelled run — a TERMINAL outcome the consumer may legitimately want
1787
+ * to observe and react to (e.g. release a lock), not a mid-turn unwind to rethrow untouched.
1788
+ * - `StepFailed` (worker) / an awaited step rejection reaching the engine — a REAL failure a
1789
+ * workflow's `catch` is meant to compensate for; misclassifying it as control-flow would swallow
1790
+ * genuine errors instead of protecting them.
1791
+ *
1792
+ * @example
1793
+ * ```ts
1794
+ * try {
1795
+ * await ctx.step('chargeCard', input);
1796
+ * } catch (error) {
1797
+ * if (isWorkflowControlFlowSignal(error)) throw error; // suspend/continue-as-new: rethrow as-is
1798
+ * await ctx.step('refund', input); // a REAL failure — safe to run cleanup here
1799
+ * throw error;
1800
+ * }
1801
+ * ```
1802
+ */
1803
+ declare function isWorkflowControlFlowSignal(error: unknown): boolean;
1804
+
1752
1805
  /**
1753
1806
  * Back-compat alias of {@link WorkflowCtx}. `localStep` — the checkpointed in-process step primitive
1754
1807
  * used for saga compensation — is now part of the public {@link WorkflowCtx}, so this type adds
@@ -2875,6 +2928,8 @@ declare class GatherError extends Error {
2875
2928
  declare class WorkflowSuspended extends Error {
2876
2929
  /** Epoch ms to auto-resume (durable sleep), or undefined when waiting on an external signal. */
2877
2930
  readonly wakeAt?: number | undefined;
2931
+ /** Marks this as a control-flow signal — see {@link isWorkflowControlFlowSignal}. */
2932
+ readonly [CONTROL_FLOW_SIGNAL] = true;
2878
2933
  constructor(wakeAt?: number);
2879
2934
  }
2880
2935
  /**
@@ -2884,6 +2939,8 @@ declare class WorkflowSuspended extends Error {
2884
2939
  */
2885
2940
  declare class ContinueAsNew extends Error {
2886
2941
  readonly input: unknown;
2942
+ /** Marks this as a control-flow signal — see {@link isWorkflowControlFlowSignal}. */
2943
+ readonly [CONTROL_FLOW_SIGNAL] = true;
2887
2944
  constructor(input: unknown);
2888
2945
  }
2889
2946
 
@@ -3369,6 +3426,60 @@ declare const STATE_STORE_CANONICAL: unique symbol;
3369
3426
  declare const TRANSPORT_CANONICAL: unique symbol;
3370
3427
  declare const DURABLE_OPTIONS_CANONICAL: unique symbol;
3371
3428
 
3429
+ /**
3430
+ * The OPT-IN declaration-site contract for a `@Workflow` class: `implements WorkflowHandler<TInput,
3431
+ * TOutput, A>` pins the class's `run(ctx, input)` signature against `TInput`/`TOutput`/`A` so a wrong
3432
+ * signature — a renamed method, swapped/missing param, wrong return type — is a compile error AT THE
3433
+ * CLASS instead of surfacing later as a runtime discovery failure (the `@Workflow` decorator finds no
3434
+ * `run` it recognizes) or a silently-wrong type flowing out of `ctx.child(ThisWorkflow, …)` /
3435
+ * `engine.start(ThisWorkflow, …)`. `A` also declares the run's {@link SearchAttributes} shape, so
3436
+ * `ctx.upsertSearchAttributes` is narrowed to it inside the workflow body — see
3437
+ * {@link SearchAttributesSchema} / {@link InferSearchAttributes} for pairing it with a `@Workflow({
3438
+ * searchAttributes })` schema.
3439
+ *
3440
+ * This is a TYPES-ONLY contract: nothing reads `implements WorkflowHandler` at runtime, registration
3441
+ * still goes through the `@Workflow` decorator + reflected metadata exactly as before, and a class
3442
+ * that doesn't implement it works exactly as it always has.
3443
+ *
3444
+ * IMPORTANT caveat: TypeScript does **not** contextually infer a method's parameter types from an
3445
+ * `implements` clause the way it does for e.g. an object literal assigned to a typed variable. The
3446
+ * class still has to annotate `ctx`/`input` itself — `implements` only CHECKS that what you wrote is
3447
+ * assignable to the interface; it doesn't write the annotations for you. Leaving `run`'s params
3448
+ * unannotated still leaves them `any`/inferred-from-usage, `implements` or not.
3449
+ *
3450
+ * @example
3451
+ * ```ts
3452
+ * import { z } from 'zod';
3453
+ * import { Workflow } from '@dudousxd/nestjs-durable';
3454
+ * import type { InferSearchAttributes, WorkflowCtx, WorkflowHandler } from '@dudousxd/nestjs-durable';
3455
+ *
3456
+ * const orderAttrs = z.object({
3457
+ * tier: z.enum(['free', 'pro']),
3458
+ * amount: z.number(),
3459
+ * });
3460
+ * type OrderAttrs = InferSearchAttributes<typeof orderAttrs>;
3461
+ *
3462
+ * interface CheckoutInput {
3463
+ * orderId: string;
3464
+ * }
3465
+ * interface CheckoutOutput {
3466
+ * receiptId: string;
3467
+ * }
3468
+ *
3469
+ * @Workflow({ name: 'checkout', searchAttributes: orderAttrs })
3470
+ * class CheckoutWorkflow implements WorkflowHandler<CheckoutInput, CheckoutOutput, OrderAttrs> {
3471
+ * async run(ctx: WorkflowCtx<OrderAttrs>, input: CheckoutInput): Promise<CheckoutOutput> {
3472
+ * await ctx.upsertSearchAttributes({ tier: 'pro', amount: 100 });
3473
+ * const receiptId = await ctx.step('charge-card', { orderId: input.orderId });
3474
+ * return { receiptId };
3475
+ * }
3476
+ * }
3477
+ * ```
3478
+ */
3479
+ interface WorkflowHandler<TInput = unknown, TOutput = unknown, A extends SearchAttributes = SearchAttributes> {
3480
+ run(ctx: WorkflowCtx<A>, input: TInput): Promise<TOutput> | TOutput;
3481
+ }
3482
+
3372
3483
  /**
3373
3484
  * A non-durable, in-process `StateStore` for tests and local development.
3374
3485
  * The shipped `@dudousxd/nestjs-durable-store` package re-exports an equivalent.
@@ -3458,4 +3569,4 @@ declare class InMemoryTransport implements Transport, ControlPlane {
3458
3569
  onControl(handler: (msg: ControlMessage) => void): void;
3459
3570
  }
3460
3571
 
3461
- export { type AccumulatorHost, type Admission, type AdmissionBackend, type AdmissionItem, type AttributeFilter, type AttributeOp, type BackoffStrategy, type ChildCallOptions, CodecStateStore, ContinueAsNew, type ControlMessage, type ControlPlane, DURABLE_OPTIONS, DURABLE_OPTIONS_CANONICAL, DURABLE_STEP_CONFIG, DURABLE_STEP_NAME, type DurableTopology, type DurableWebhook, DurableWorkflow, type EngineEvent, type EngineEventType, type EngineListener, Entities, type EntityConfig, type EntityHandler, type EntityHost, EventAccumulators, type EventBatchConfig, FatalError, GatherError, type GroupHealth, type Heartbeat, type HistoryEvent, InMemoryAdmissionBackend, InMemoryStateStore, InMemoryTransport, type InferSearchAttributes, type MetricsCollector, type MetricsSnapshot, type NamedTransport, NonDeterminismError, type PayloadCodec, type QueueConfig, QueueController, RemoteStepError, RemoteStepTimeout, type RemoteTask, RemoteWorkflowExecutor, RemoteWorkflowTimeout, type RetentionPolicy, type RunAttributeRow, type RunDetail, type RunDispatcher, type RunGateway, type RunListItem, type RunQuery, type RunReply, type RunReplyResult, type RunRequest, type RunRequestKind, type RunResult, type RunSchedulesOptions, type RunStatus, type RunWaiting, STATE_STORE, STATE_STORE_CANONICAL, 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 StepUndo, type StoreTransaction, type SubProcessHandle, TERMINAL_RUN_STATUSES, TRANSPORT, TRANSPORT_CANONICAL, type TenantEvent, type Transport, type UndoOf, type UpdateResult, type UpdateValidator, WORKFLOW_NAME_KEY, type WireDates, type WorkerAdjust, type WorkerConcurrencyStatus, type WorkerHeartbeat, type WorkerStatus, type WorkflowClass, type WorkflowCommand, type WorkflowCtx, type WorkflowDecision, WorkflowEngine, type WorkflowEngineDeps, type WorkflowExecutor, type WorkflowInputOf, type WorkflowOutputOf, type WorkflowRef, type WorkflowRun, type WorkflowStartClient, type WorkflowStepEvent, WorkflowSuspended, type WorkflowTask, applyAttributeQuery, attributeColumnFor, attributeOperand, bindWorkflowClass, breakpointToken, classifyWaiterToken, collectMetrics, createStepLogger, currentWorkflowCtx, eventMatchOf, eventMatches, eventNameOf, eventPrefix, eventToken, indexWaitersByRun, matchesAttributes, normalizeAttributeRows, parseDuration, prevCronFireMs, readSearchAttributes, resolveRunWaiting, runInWorkflowCtx, runSchedules, runStepHandler, sanitizeQueueToken, scheduledRunId, sqlComparator, stepConfigOf, stepId, stepNameOf, tenantGroup, workflowName };
3572
+ export { type AccumulatorHost, type Admission, type AdmissionBackend, type AdmissionItem, type AttributeFilter, type AttributeOp, type BackoffStrategy, CONTROL_FLOW_SIGNAL, type ChildCallOptions, CodecStateStore, ContinueAsNew, type ControlMessage, type ControlPlane, DURABLE_OPTIONS, DURABLE_OPTIONS_CANONICAL, DURABLE_STEP_CONFIG, DURABLE_STEP_NAME, type DurableTopology, type DurableWebhook, DurableWorkflow, type EngineEvent, type EngineEventType, type EngineListener, Entities, type EntityConfig, type EntityHandler, type EntityHost, EventAccumulators, type EventBatchConfig, FatalError, GatherError, type GroupHealth, type Heartbeat, type HistoryEvent, InMemoryAdmissionBackend, InMemoryStateStore, InMemoryTransport, type InferSearchAttributes, type MetricsCollector, type MetricsSnapshot, type NamedTransport, NonDeterminismError, type PayloadCodec, type QueueConfig, QueueController, RemoteStepError, RemoteStepTimeout, type RemoteTask, RemoteWorkflowExecutor, RemoteWorkflowTimeout, type RetentionPolicy, type RunAttributeRow, type RunDetail, type RunDispatcher, type RunGateway, type RunListItem, type RunQuery, type RunReply, type RunReplyResult, type RunRequest, type RunRequestKind, type RunResult, type RunSchedulesOptions, type RunStatus, type RunWaiting, STATE_STORE, STATE_STORE_CANONICAL, 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 StepUndo, type StoreTransaction, type SubProcessHandle, TERMINAL_RUN_STATUSES, TRANSPORT, TRANSPORT_CANONICAL, type TenantEvent, type Transport, type UndoOf, type UpdateResult, type UpdateValidator, WORKFLOW_NAME_KEY, type WireDates, type WorkerAdjust, type WorkerConcurrencyStatus, type WorkerHeartbeat, type WorkerStatus, type WorkflowClass, type WorkflowCommand, type WorkflowCtx, type WorkflowDecision, WorkflowEngine, type WorkflowEngineDeps, type WorkflowExecutor, type WorkflowHandler, type WorkflowInputOf, type WorkflowOutputOf, type WorkflowRef, type WorkflowRun, type WorkflowStartClient, type WorkflowStepEvent, WorkflowSuspended, type WorkflowTask, applyAttributeQuery, attributeColumnFor, attributeOperand, bindWorkflowClass, breakpointToken, classifyWaiterToken, collectMetrics, createStepLogger, currentWorkflowCtx, eventMatchOf, eventMatches, eventNameOf, eventPrefix, eventToken, indexWaitersByRun, isWorkflowControlFlowSignal, matchesAttributes, normalizeAttributeRows, parseDuration, prevCronFireMs, readSearchAttributes, resolveRunWaiting, runInWorkflowCtx, runSchedules, runStepHandler, sanitizeQueueToken, scheduledRunId, sqlComparator, stepConfigOf, stepId, stepNameOf, tenantGroup, workflowName };
package/dist/index.d.ts CHANGED
@@ -1749,6 +1749,59 @@ declare function runInWorkflowCtx<T>(ctx: WorkflowCtx, fn: () => T): T;
1749
1749
  */
1750
1750
  declare function currentWorkflowCtx(): WorkflowCtx | undefined;
1751
1751
 
1752
+ /**
1753
+ * Cross-package, cross-runtime marker for engine CONTROL-FLOW signals — {@link WorkflowSuspended}
1754
+ * and {@link ContinueAsNew} (this package), plus the thin worker's {@link
1755
+ * import('@dudousxd/durable-worker').Suspend} (`@dudousxd/durable-worker`, the BullMQ
1756
+ * route-by-handler runtime). These are thrown by `WorkflowCtx`/`WorkflowContext` ops to unwind the
1757
+ * current turn — never real failures — so a workflow's `catch` block MUST rethrow them untouched.
1758
+ * Running a failure/cleanup path on a control-flow signal corrupts the run: it emits extra
1759
+ * `recordStep` commands into history that a subsequent replay didn't produce the first time,
1760
+ * surfacing as a `NonDeterminismError`/`NondeterminismError` on resume.
1761
+ *
1762
+ * `Symbol.for` (the GLOBAL registry), NOT a plain `Symbol()` — so a duplicate copy of this module
1763
+ * (pnpm peer-dependency multiplexing, a dual ESM/CJS load, or the SEPARATE `@dudousxd/durable-worker`
1764
+ * package declaring the same `Symbol.for` key locally) still collapses onto the SAME symbol. Same
1765
+ * rationale as `DURABLE_STEP_NAME` in `./step-name-symbol.ts`.
1766
+ *
1767
+ * Deliberately checked as a stamped property, NOT `instanceof` — `instanceof` only recognizes a
1768
+ * signal thrown by the SAME class the checking code imported, which fails across the in-process
1769
+ * engine (`@dudousxd/nestjs-durable-core`'s `WorkflowSuspended`/`ContinueAsNew`) and the thin worker
1770
+ * (`@dudousxd/durable-worker`'s `Suspend`) — two different classes for what is, from a workflow
1771
+ * author's catch block, the same "this isn't a real error, let it through" event.
1772
+ *
1773
+ * NOT designed to survive a serialization boundary (e.g. JSON over the wire) — these signals are
1774
+ * always thrown and caught in-process within a single replay turn, never (de)serialized, so a
1775
+ * stamped-but-not-cloneable property is sufficient.
1776
+ */
1777
+ declare const CONTROL_FLOW_SIGNAL: unique symbol;
1778
+ /**
1779
+ * True for any engine control-flow signal (currently: {@link WorkflowSuspended}, {@link
1780
+ * ContinueAsNew}, and the thin worker's `Suspend`) — regardless of which runtime or module instance
1781
+ * threw it. Workflow `catch` blocks MUST rethrow these untouched; running a failure/cleanup path on
1782
+ * one corrupts the run's history (extra commands recorded during what replay will later see as a
1783
+ * suspend, not a failure) and the resumed replay dies with a non-determinism error.
1784
+ *
1785
+ * Deliberately NOT control-flow (do not add to this predicate):
1786
+ * - `Cancelled` (worker) / a cancelled run — a TERMINAL outcome the consumer may legitimately want
1787
+ * to observe and react to (e.g. release a lock), not a mid-turn unwind to rethrow untouched.
1788
+ * - `StepFailed` (worker) / an awaited step rejection reaching the engine — a REAL failure a
1789
+ * workflow's `catch` is meant to compensate for; misclassifying it as control-flow would swallow
1790
+ * genuine errors instead of protecting them.
1791
+ *
1792
+ * @example
1793
+ * ```ts
1794
+ * try {
1795
+ * await ctx.step('chargeCard', input);
1796
+ * } catch (error) {
1797
+ * if (isWorkflowControlFlowSignal(error)) throw error; // suspend/continue-as-new: rethrow as-is
1798
+ * await ctx.step('refund', input); // a REAL failure — safe to run cleanup here
1799
+ * throw error;
1800
+ * }
1801
+ * ```
1802
+ */
1803
+ declare function isWorkflowControlFlowSignal(error: unknown): boolean;
1804
+
1752
1805
  /**
1753
1806
  * Back-compat alias of {@link WorkflowCtx}. `localStep` — the checkpointed in-process step primitive
1754
1807
  * used for saga compensation — is now part of the public {@link WorkflowCtx}, so this type adds
@@ -2875,6 +2928,8 @@ declare class GatherError extends Error {
2875
2928
  declare class WorkflowSuspended extends Error {
2876
2929
  /** Epoch ms to auto-resume (durable sleep), or undefined when waiting on an external signal. */
2877
2930
  readonly wakeAt?: number | undefined;
2931
+ /** Marks this as a control-flow signal — see {@link isWorkflowControlFlowSignal}. */
2932
+ readonly [CONTROL_FLOW_SIGNAL] = true;
2878
2933
  constructor(wakeAt?: number);
2879
2934
  }
2880
2935
  /**
@@ -2884,6 +2939,8 @@ declare class WorkflowSuspended extends Error {
2884
2939
  */
2885
2940
  declare class ContinueAsNew extends Error {
2886
2941
  readonly input: unknown;
2942
+ /** Marks this as a control-flow signal — see {@link isWorkflowControlFlowSignal}. */
2943
+ readonly [CONTROL_FLOW_SIGNAL] = true;
2887
2944
  constructor(input: unknown);
2888
2945
  }
2889
2946
 
@@ -3369,6 +3426,60 @@ declare const STATE_STORE_CANONICAL: unique symbol;
3369
3426
  declare const TRANSPORT_CANONICAL: unique symbol;
3370
3427
  declare const DURABLE_OPTIONS_CANONICAL: unique symbol;
3371
3428
 
3429
+ /**
3430
+ * The OPT-IN declaration-site contract for a `@Workflow` class: `implements WorkflowHandler<TInput,
3431
+ * TOutput, A>` pins the class's `run(ctx, input)` signature against `TInput`/`TOutput`/`A` so a wrong
3432
+ * signature — a renamed method, swapped/missing param, wrong return type — is a compile error AT THE
3433
+ * CLASS instead of surfacing later as a runtime discovery failure (the `@Workflow` decorator finds no
3434
+ * `run` it recognizes) or a silently-wrong type flowing out of `ctx.child(ThisWorkflow, …)` /
3435
+ * `engine.start(ThisWorkflow, …)`. `A` also declares the run's {@link SearchAttributes} shape, so
3436
+ * `ctx.upsertSearchAttributes` is narrowed to it inside the workflow body — see
3437
+ * {@link SearchAttributesSchema} / {@link InferSearchAttributes} for pairing it with a `@Workflow({
3438
+ * searchAttributes })` schema.
3439
+ *
3440
+ * This is a TYPES-ONLY contract: nothing reads `implements WorkflowHandler` at runtime, registration
3441
+ * still goes through the `@Workflow` decorator + reflected metadata exactly as before, and a class
3442
+ * that doesn't implement it works exactly as it always has.
3443
+ *
3444
+ * IMPORTANT caveat: TypeScript does **not** contextually infer a method's parameter types from an
3445
+ * `implements` clause the way it does for e.g. an object literal assigned to a typed variable. The
3446
+ * class still has to annotate `ctx`/`input` itself — `implements` only CHECKS that what you wrote is
3447
+ * assignable to the interface; it doesn't write the annotations for you. Leaving `run`'s params
3448
+ * unannotated still leaves them `any`/inferred-from-usage, `implements` or not.
3449
+ *
3450
+ * @example
3451
+ * ```ts
3452
+ * import { z } from 'zod';
3453
+ * import { Workflow } from '@dudousxd/nestjs-durable';
3454
+ * import type { InferSearchAttributes, WorkflowCtx, WorkflowHandler } from '@dudousxd/nestjs-durable';
3455
+ *
3456
+ * const orderAttrs = z.object({
3457
+ * tier: z.enum(['free', 'pro']),
3458
+ * amount: z.number(),
3459
+ * });
3460
+ * type OrderAttrs = InferSearchAttributes<typeof orderAttrs>;
3461
+ *
3462
+ * interface CheckoutInput {
3463
+ * orderId: string;
3464
+ * }
3465
+ * interface CheckoutOutput {
3466
+ * receiptId: string;
3467
+ * }
3468
+ *
3469
+ * @Workflow({ name: 'checkout', searchAttributes: orderAttrs })
3470
+ * class CheckoutWorkflow implements WorkflowHandler<CheckoutInput, CheckoutOutput, OrderAttrs> {
3471
+ * async run(ctx: WorkflowCtx<OrderAttrs>, input: CheckoutInput): Promise<CheckoutOutput> {
3472
+ * await ctx.upsertSearchAttributes({ tier: 'pro', amount: 100 });
3473
+ * const receiptId = await ctx.step('charge-card', { orderId: input.orderId });
3474
+ * return { receiptId };
3475
+ * }
3476
+ * }
3477
+ * ```
3478
+ */
3479
+ interface WorkflowHandler<TInput = unknown, TOutput = unknown, A extends SearchAttributes = SearchAttributes> {
3480
+ run(ctx: WorkflowCtx<A>, input: TInput): Promise<TOutput> | TOutput;
3481
+ }
3482
+
3372
3483
  /**
3373
3484
  * A non-durable, in-process `StateStore` for tests and local development.
3374
3485
  * The shipped `@dudousxd/nestjs-durable-store` package re-exports an equivalent.
@@ -3458,4 +3569,4 @@ declare class InMemoryTransport implements Transport, ControlPlane {
3458
3569
  onControl(handler: (msg: ControlMessage) => void): void;
3459
3570
  }
3460
3571
 
3461
- export { type AccumulatorHost, type Admission, type AdmissionBackend, type AdmissionItem, type AttributeFilter, type AttributeOp, type BackoffStrategy, type ChildCallOptions, CodecStateStore, ContinueAsNew, type ControlMessage, type ControlPlane, DURABLE_OPTIONS, DURABLE_OPTIONS_CANONICAL, DURABLE_STEP_CONFIG, DURABLE_STEP_NAME, type DurableTopology, type DurableWebhook, DurableWorkflow, type EngineEvent, type EngineEventType, type EngineListener, Entities, type EntityConfig, type EntityHandler, type EntityHost, EventAccumulators, type EventBatchConfig, FatalError, GatherError, type GroupHealth, type Heartbeat, type HistoryEvent, InMemoryAdmissionBackend, InMemoryStateStore, InMemoryTransport, type InferSearchAttributes, type MetricsCollector, type MetricsSnapshot, type NamedTransport, NonDeterminismError, type PayloadCodec, type QueueConfig, QueueController, RemoteStepError, RemoteStepTimeout, type RemoteTask, RemoteWorkflowExecutor, RemoteWorkflowTimeout, type RetentionPolicy, type RunAttributeRow, type RunDetail, type RunDispatcher, type RunGateway, type RunListItem, type RunQuery, type RunReply, type RunReplyResult, type RunRequest, type RunRequestKind, type RunResult, type RunSchedulesOptions, type RunStatus, type RunWaiting, STATE_STORE, STATE_STORE_CANONICAL, 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 StepUndo, type StoreTransaction, type SubProcessHandle, TERMINAL_RUN_STATUSES, TRANSPORT, TRANSPORT_CANONICAL, type TenantEvent, type Transport, type UndoOf, type UpdateResult, type UpdateValidator, WORKFLOW_NAME_KEY, type WireDates, type WorkerAdjust, type WorkerConcurrencyStatus, type WorkerHeartbeat, type WorkerStatus, type WorkflowClass, type WorkflowCommand, type WorkflowCtx, type WorkflowDecision, WorkflowEngine, type WorkflowEngineDeps, type WorkflowExecutor, type WorkflowInputOf, type WorkflowOutputOf, type WorkflowRef, type WorkflowRun, type WorkflowStartClient, type WorkflowStepEvent, WorkflowSuspended, type WorkflowTask, applyAttributeQuery, attributeColumnFor, attributeOperand, bindWorkflowClass, breakpointToken, classifyWaiterToken, collectMetrics, createStepLogger, currentWorkflowCtx, eventMatchOf, eventMatches, eventNameOf, eventPrefix, eventToken, indexWaitersByRun, matchesAttributes, normalizeAttributeRows, parseDuration, prevCronFireMs, readSearchAttributes, resolveRunWaiting, runInWorkflowCtx, runSchedules, runStepHandler, sanitizeQueueToken, scheduledRunId, sqlComparator, stepConfigOf, stepId, stepNameOf, tenantGroup, workflowName };
3572
+ export { type AccumulatorHost, type Admission, type AdmissionBackend, type AdmissionItem, type AttributeFilter, type AttributeOp, type BackoffStrategy, CONTROL_FLOW_SIGNAL, type ChildCallOptions, CodecStateStore, ContinueAsNew, type ControlMessage, type ControlPlane, DURABLE_OPTIONS, DURABLE_OPTIONS_CANONICAL, DURABLE_STEP_CONFIG, DURABLE_STEP_NAME, type DurableTopology, type DurableWebhook, DurableWorkflow, type EngineEvent, type EngineEventType, type EngineListener, Entities, type EntityConfig, type EntityHandler, type EntityHost, EventAccumulators, type EventBatchConfig, FatalError, GatherError, type GroupHealth, type Heartbeat, type HistoryEvent, InMemoryAdmissionBackend, InMemoryStateStore, InMemoryTransport, type InferSearchAttributes, type MetricsCollector, type MetricsSnapshot, type NamedTransport, NonDeterminismError, type PayloadCodec, type QueueConfig, QueueController, RemoteStepError, RemoteStepTimeout, type RemoteTask, RemoteWorkflowExecutor, RemoteWorkflowTimeout, type RetentionPolicy, type RunAttributeRow, type RunDetail, type RunDispatcher, type RunGateway, type RunListItem, type RunQuery, type RunReply, type RunReplyResult, type RunRequest, type RunRequestKind, type RunResult, type RunSchedulesOptions, type RunStatus, type RunWaiting, STATE_STORE, STATE_STORE_CANONICAL, 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 StepUndo, type StoreTransaction, type SubProcessHandle, TERMINAL_RUN_STATUSES, TRANSPORT, TRANSPORT_CANONICAL, type TenantEvent, type Transport, type UndoOf, type UpdateResult, type UpdateValidator, WORKFLOW_NAME_KEY, type WireDates, type WorkerAdjust, type WorkerConcurrencyStatus, type WorkerHeartbeat, type WorkerStatus, type WorkflowClass, type WorkflowCommand, type WorkflowCtx, type WorkflowDecision, WorkflowEngine, type WorkflowEngineDeps, type WorkflowExecutor, type WorkflowHandler, type WorkflowInputOf, type WorkflowOutputOf, type WorkflowRef, type WorkflowRun, type WorkflowStartClient, type WorkflowStepEvent, WorkflowSuspended, type WorkflowTask, applyAttributeQuery, attributeColumnFor, attributeOperand, bindWorkflowClass, breakpointToken, classifyWaiterToken, collectMetrics, createStepLogger, currentWorkflowCtx, eventMatchOf, eventMatches, eventNameOf, eventPrefix, eventToken, indexWaitersByRun, isWorkflowControlFlowSignal, matchesAttributes, normalizeAttributeRows, parseDuration, prevCronFireMs, readSearchAttributes, resolveRunWaiting, runInWorkflowCtx, runSchedules, runStepHandler, sanitizeQueueToken, scheduledRunId, sqlComparator, stepConfigOf, stepId, stepNameOf, tenantGroup, workflowName };
package/dist/index.js CHANGED
@@ -173,6 +173,13 @@ function currentWorkflowCtx() {
173
173
  }
174
174
  __name(currentWorkflowCtx, "currentWorkflowCtx");
175
175
 
176
+ // src/control-flow-signal.ts
177
+ var CONTROL_FLOW_SIGNAL = Symbol.for("aviary:durable:control-flow");
178
+ function isWorkflowControlFlowSignal(error) {
179
+ return typeof error === "object" && error !== null && error[CONTROL_FLOW_SIGNAL] === true;
180
+ }
181
+ __name(isWorkflowControlFlowSignal, "isWorkflowControlFlowSignal");
182
+
176
183
  // src/errors.ts
177
184
  var FatalError = class extends Error {
178
185
  static {
@@ -271,6 +278,8 @@ var WorkflowSuspended = class extends Error {
271
278
  }
272
279
  /** Epoch ms to auto-resume (durable sleep), or undefined when waiting on an external signal. */
273
280
  wakeAt;
281
+ /** Marks this as a control-flow signal — see {@link isWorkflowControlFlowSignal}. */
282
+ [CONTROL_FLOW_SIGNAL] = true;
274
283
  constructor(wakeAt) {
275
284
  super("workflow suspended");
276
285
  this.name = "WorkflowSuspended";
@@ -282,6 +291,8 @@ var ContinueAsNew = class extends Error {
282
291
  __name(this, "ContinueAsNew");
283
292
  }
284
293
  input;
294
+ /** Marks this as a control-flow signal — see {@link isWorkflowControlFlowSignal}. */
295
+ [CONTROL_FLOW_SIGNAL] = true;
285
296
  constructor(input) {
286
297
  super("workflow continued as new"), this.input = input;
287
298
  this.name = "ContinueAsNew";
@@ -5203,6 +5214,7 @@ var InMemoryTransport = class {
5203
5214
  }
5204
5215
  };
5205
5216
  export {
5217
+ CONTROL_FLOW_SIGNAL,
5206
5218
  CodecStateStore,
5207
5219
  ContinueAsNew,
5208
5220
  DURABLE_OPTIONS,
@@ -5248,6 +5260,7 @@ export {
5248
5260
  eventPrefix,
5249
5261
  eventToken,
5250
5262
  indexWaitersByRun,
5263
+ isWorkflowControlFlowSignal,
5251
5264
  matchesAttributes,
5252
5265
  normalizeAttributeRows,
5253
5266
  parseDuration,