@dudousxd/nestjs-durable 0.47.1 → 0.48.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -1,5 +1,5 @@
1
- import { WorkflowCtx, SearchAttributes, WorkflowClass, StepError, WorkflowRef, SingletonConfig, ConcurrencyConfig, SearchAttributesSchema, StateStore, Transport, NamedTransport, ControlPlane, ScheduledWorkflow, RetentionPolicy, QueueConfig, AdmissionBackend, WorkflowInputOf, StartOptions, RunResult, RunGateway, WorkflowEngine, EntityHandler, DurableTopology, RunDetailOptions, RunDetail, FanPageQuery, FanPage, RunQuery, RunListItem, RunFacetQuery, RunFacetRow, RunValueAxis, RunValueFacetOptions, RunValueFacetRow, GroupHealth, RunWaiting, EngineEvent, RunRequest, RunReply, StepInvocation, WorkflowRun, TenantEvent } from '@dudousxd/nestjs-durable-core';
2
- export { AttributeFilter, DynamicWorkflowCtx, EngineEvent, InferSearchAttributes, RunDetail, RunGateway, RunListItem, RunQuery, RunStatus, RunWaiting, SearchAttributes, SearchAttributesSchema, StepCheckpoint, StepEvent, StepLogger, WorkflowCtx, WorkflowEngine, WorkflowHandler, WorkflowRun, readSearchAttributes } from '@dudousxd/nestjs-durable-core';
1
+ import { WorkflowCtx, SearchAttributes, WorkflowClass, StepError, OnErrorInput, WorkflowRef, SingletonConfig, ConcurrencyConfig, SearchAttributesSchema, StateStore, Transport, NamedTransport, ControlPlane, ScheduledWorkflow, RetentionPolicy, QueueConfig, AdmissionBackend, WorkflowInputOf, StartOptions, RunResult, RunGateway, WorkflowEngine, EntityHandler, DurableTopology, RunDetailOptions, RunDetail, FanPageQuery, FanPage, RunQuery, RunListItem, RunFacetQuery, RunFacetRow, RunValueAxis, RunValueFacetOptions, RunValueFacetRow, GroupHealth, RunWaiting, EngineEvent, RunRequest, RunReply, StepInvocation, WorkflowRun, TenantEvent } from '@dudousxd/nestjs-durable-core';
2
+ export { AttributeFilter, DynamicWorkflowCtx, EngineEvent, InferSearchAttributes, OnErrorInput, RunDetail, RunGateway, RunListItem, RunQuery, RunStatus, RunWaiting, SearchAttributes, SearchAttributesSchema, StepCheckpoint, StepEvent, StepLogger, WorkflowCtx, WorkflowEngine, WorkflowHandler, WorkflowRun, readSearchAttributes } from '@dudousxd/nestjs-durable-core';
3
3
  import { z } from 'zod';
4
4
  import { ConcurrencyOption, StartRunDeps, RunRedisWorkerOptions, RunningWorker, DurableWorkerRuntime } from '@dudousxd/durable-worker';
5
5
  import { DynamicModule, InjectionToken, OnModuleInit, OnApplicationBootstrap, OnApplicationShutdown, Provider } from '@nestjs/common';
@@ -108,6 +108,11 @@ interface WorkflowMeta {
108
108
  version: string;
109
109
  /** The workflow this workflow's dead runs route to (a name or a class). See `WorkflowOptions`. */
110
110
  deadLetterWorkflow?: WorkflowRef | undefined;
111
+ /** Where failed runs are routed by error code. See `WorkflowOptions`. */
112
+ onError?: {
113
+ code?: string | ErrorClassWithCode;
114
+ workflow: WorkflowRef;
115
+ }[] | undefined;
111
116
  /** Static searchable labels stamped on every run of this workflow. See `WorkflowOptions`. */
112
117
  tags?: string[] | undefined;
113
118
  /** Per-key serialization (a durable mutex). See `WorkflowOptions`. */
@@ -146,6 +151,16 @@ interface WorkflowOptions {
146
151
  * {@link DeadLetter} payload, idempotent by a `dlq:<runId>` id.
147
152
  */
148
153
  deadLetterWorkflow?: WorkflowRef;
154
+ /**
155
+ * Route failed runs of this workflow to other **registered** workflows by error code — the
156
+ * separate-class form of an `@OnError` method (see it for the semantics). Each handler receives an
157
+ * {@link OnErrorInput}; omit `code` for the catch-all. A code routed here and by an `@OnError`
158
+ * method on the class is a boot-time error.
159
+ */
160
+ onError?: {
161
+ code?: string | ErrorClassWithCode;
162
+ workflow: WorkflowRef;
163
+ }[];
149
164
  /**
150
165
  * Static labels stamped on **every run** of this workflow (e.g. `tags: ['etl', 'critical']`) and
151
166
  * merged with any per-run tags passed to `start`. Searchable/filterable in the dashboard.
@@ -356,6 +371,42 @@ interface DeadLetter<TInput = unknown> {
356
371
  */
357
372
  declare function DeadLetter(): MethodDecorator;
358
373
  declare function isDeadLetterHandler(method: Function): boolean;
374
+ declare const ON_ERROR_METADATA: unique symbol;
375
+ /**
376
+ * An error class that declares the `code` it is thrown with (`static readonly code = 'invalid_line'`).
377
+ * `@OnError(Class)` matches on that code, not on `instanceof`: a dispatched step's error reaches the
378
+ * workflow as a plain `{ message, code }`, without its class.
379
+ */
380
+ interface ErrorClassWithCode {
381
+ readonly code: string;
382
+ }
383
+ type WorkflowShape = {
384
+ run(ctx: any, input: any): Promise<unknown>;
385
+ };
386
+ /**
387
+ * An `@OnError` method: a workflow body that receives the failed run's {@link OnErrorInput}, typed with
388
+ * `run`'s input, and returns what `run` returns.
389
+ */
390
+ type OnErrorMethod<T extends WorkflowShape> = (ctx: WorkflowCtx<any>, failure: OnErrorInput<Parameters<T['run']>[1]>) => Promise<Awaited<ReturnType<T['run']>>>;
391
+ /**
392
+ * Marks a method on a `@Workflow` class as the handler for a failure of that workflow's runs. When a
393
+ * run ends `failed` with an error of the given `code` (a string, or an {@link ErrorClassWithCode}),
394
+ * the engine starts the method as its own durable workflow — registered as
395
+ * `<workflow>.onError.<method>`, with a `<runId>.onError` id — and the failed run waits for it, then
396
+ * settles with its outcome: the method's return value as its output, or its error. Without an
397
+ * argument it takes any failure no other code matches.
398
+ *
399
+ * The engine routes the failure, so this holds for whatever ran the body (inline, an in-app worker,
400
+ * another runtime). The method's signature is checked against the workflow: `(ctx, failure)`, with
401
+ * `failure.input` typed as `run`'s input and the return type as `run`'s. Stack the decorator to give
402
+ * one method several codes. Saga compensations of the failed body run before the handoff;
403
+ * cancellation and non-determinism are never routed.
404
+ */
405
+ declare function OnError(match?: string | ErrorClassWithCode): <T extends WorkflowShape>(_target: T, _propertyKey: string | symbol, descriptor: {
406
+ value?: OnErrorMethod<T> | undefined;
407
+ }) => void;
408
+ /** The codes an `@OnError` method takes (`undefined` for the catch-all), or undefined if it has none. */
409
+ declare function onErrorCodesOf(method: Function): (string | undefined)[] | undefined;
359
410
  declare const ON_EVENT_METADATA: unique symbol;
360
411
  /**
361
412
  * Subscribe a `@Workflow` class to one or more events: when any of them is published via
@@ -551,6 +602,18 @@ interface DurableModuleOptions {
551
602
  * a driving instance's poll picks it up. Ignored (irrelevant) for a thin worker (no `store`).
552
603
  */
553
604
  drive?: boolean;
605
+ /**
606
+ * Whether this process CONSUMES from the broker. Defaults to `true`. Set `false` in a process that
607
+ * boots the module without being a worker — a CLI command, a REPL, a migration or seed script — so
608
+ * it doesn't compete with the real fleet: every transport that supports it (`BullMQTransport`) has
609
+ * its point-to-point consumers (step tasks, results, decisions, step events, start-run, run-request)
610
+ * parked via `deferConsumers()`, and no co-located/thin worker consumer starts. The process still
611
+ * dispatches and starts runs; the jobs stay on the queues for the fleet. Pair it with
612
+ * `drive: false` so it doesn't poll/recover runs either. To consume later in the same process, call
613
+ * `startConsumers()` on your transport. A transport without `deferConsumers()` (the SQL/SQS/in-process
614
+ * transports) keeps consuming — a warning says so.
615
+ */
616
+ consumers?: boolean;
554
617
  /** Max ms to wait for in-flight runs on shutdown before exiting. Defaults to 10000. Operator only. */
555
618
  shutdownTimeoutMs?: number;
556
619
  /**
@@ -804,9 +867,10 @@ type RunRedisWorkerFn = (opts: RunRedisWorkerOptions) => Promise<RunningWorker>;
804
867
  */
805
868
  declare class ThinWorkflowRegistrar implements OnModuleInit {
806
869
  private readonly discovery;
870
+ private readonly metadataScanner;
807
871
  private readonly runtime;
808
872
  private readonly options;
809
- constructor(discovery: DiscoveryService, runtime: DurableWorkerRuntime | null, options: DurableModuleOptions);
873
+ constructor(discovery: DiscoveryService, metadataScanner: MetadataScanner, runtime: DurableWorkerRuntime | null, options: DurableModuleOptions);
810
874
  onModuleInit(): void;
811
875
  }
812
876
  /**
@@ -971,13 +1035,25 @@ declare class ProxyRunGateway implements RunGateway {
971
1035
  private readonly transport;
972
1036
  private readonly tenant;
973
1037
  private readonly timeoutMs;
1038
+ private readonly capabilityTtlMs;
974
1039
  private readonly pending;
975
- constructor(transport: Transport, tenant: string, timeoutMs?: number);
1040
+ /** Verb → when to ask the control plane for it again, after it answered that it does not know it.
1041
+ * During a rolling upgrade the control plane is several pods of mixed versions behind one queue,
1042
+ * and a reply does not say which pod sent it, so the whole control plane is assumed old until the
1043
+ * entry expires. */
1044
+ private readonly unsupportedUntil;
1045
+ constructor(transport: Transport, tenant: string, timeoutMs?: number, capabilityTtlMs?: number);
976
1046
  private handleReply;
977
1047
  private request;
978
1048
  topology(): DurableTopology;
1049
+ /**
1050
+ * A control plane that predates {@link RunDetailOptions} ignores them and sends the full detail;
1051
+ * a summarized detail always carries `fans`, so its absence means the summary is made here.
1052
+ */
979
1053
  getRunDetail(runId: string, options?: RunDetailOptions): Promise<RunDetail | null>;
1054
+ /** Paged from the full detail when the control plane is too old to page a fan itself. */
980
1055
  getFanMembers(runId: string, group: string, query: FanPageQuery): Promise<FanPage | null>;
1056
+ private knownUnsupported;
981
1057
  /** The control plane's `StoreRunGateway` resolves each run's `waiting` descriptor; the reply carries
982
1058
  * it through as plain JSON, so a tenant's list rows name the wait too. */
983
1059
  listRuns(query: RunQuery): Promise<RunListItem[]>;
@@ -1020,6 +1096,12 @@ declare function isOperatorRole(options: DurableModuleOptions): boolean;
1020
1096
  */
1021
1097
  declare function isDrivingOperator(options: DurableModuleOptions): boolean;
1022
1098
 
1099
+ /**
1100
+ * The error `code` a responder replies with for a verb it does not know, so a newer tenant can tell
1101
+ * "this control plane is older than me" from a real failure and fall back at once. Earlier
1102
+ * responders reply `ok: true` with no `data` instead; `ProxyRunGateway` reads both.
1103
+ */
1104
+ declare const UNSUPPORTED_RUN_REQUEST = "unsupported-request";
1023
1105
  /** The narrow slice of `Transport` the responder needs — a tenant's read/control request in, a
1024
1106
  * correlated reply out. Both are OPTIONAL on the full `Transport` interface (only broker
1025
1107
  * transports carry the run-request/reply protocol); the caller capability-checks before wiring
@@ -1235,4 +1317,4 @@ declare class WorkflowService {
1235
1317
  }): Promise<number>;
1236
1318
  }
1237
1319
 
1238
- export { CONTEXT_ACCESSOR, type ContextAccessor, type ContextStore, DEAD_LETTER_METADATA, DURABLE_STEP_METADATA, DURABLE_WORKER_RUNNERS, DURABLE_WORKER_RUNTIME, DeadLetter, DurableModule, type DurableModuleAsyncOptions, type DurableModuleOptions, type DurableRetentionOptions, DurableStartClient, DurableStep, type DurableStepInterceptor, type DurableStepMeta, ENTITY_METADATA, ENTITY_ON_METADATA, Entity, EntityService, IN_APP_RUN_REDIS_WORKER, IN_APP_WORKER_BINDING, IN_APP_WORKER_RUNNERS, IN_APP_WORKER_RUNTIME, type InAppWorkerBinding, InAppWorkerBootstrap, ON_EVENT_METADATA, On, OnDurableEvent, OnEvent, ProxyRunGateway, RUN_GATEWAY, RUN_REDIS_WORKER, type RunLookupStore, type RunRedisWorkerFn, RunRequestResponder, type RunRequestTransport, STEP_INTERCEPTOR_METADATA, Step, StepInterceptor, type StepOptions, StoreRunGateway, TenantEventRepublisher, ThinStepRegistrar, ThinWorkerBootstrap, ThinWorkflowRegistrar, type UserRef, WORKFLOW_METADATA, Workflow, type WorkflowAttributesOf, type WorkflowMeta, type WorkflowOptions, WorkflowService, attributesOf, entityConfigFor, getDurableStepMeta, getEntityMeta, getOnEvents, getWorkflowMeta, inAppWorkerProviders, isDeadLetterHandler, isDrivingOperator, isOperatorRole, isStepInterceptor, thinWorkerProviders, unavailableRunGateway };
1320
+ export { CONTEXT_ACCESSOR, type ContextAccessor, type ContextStore, DEAD_LETTER_METADATA, DURABLE_STEP_METADATA, DURABLE_WORKER_RUNNERS, DURABLE_WORKER_RUNTIME, DeadLetter, DurableModule, type DurableModuleAsyncOptions, type DurableModuleOptions, type DurableRetentionOptions, DurableStartClient, DurableStep, type DurableStepInterceptor, type DurableStepMeta, ENTITY_METADATA, ENTITY_ON_METADATA, Entity, EntityService, type ErrorClassWithCode, IN_APP_RUN_REDIS_WORKER, IN_APP_WORKER_BINDING, IN_APP_WORKER_RUNNERS, IN_APP_WORKER_RUNTIME, type InAppWorkerBinding, InAppWorkerBootstrap, ON_ERROR_METADATA, ON_EVENT_METADATA, On, OnDurableEvent, OnError, type OnErrorMethod, OnEvent, ProxyRunGateway, RUN_GATEWAY, RUN_REDIS_WORKER, type RunLookupStore, type RunRedisWorkerFn, RunRequestResponder, type RunRequestTransport, STEP_INTERCEPTOR_METADATA, Step, StepInterceptor, type StepOptions, StoreRunGateway, TenantEventRepublisher, ThinStepRegistrar, ThinWorkerBootstrap, ThinWorkflowRegistrar, UNSUPPORTED_RUN_REQUEST, type UserRef, WORKFLOW_METADATA, Workflow, type WorkflowAttributesOf, type WorkflowMeta, type WorkflowOptions, WorkflowService, attributesOf, entityConfigFor, getDurableStepMeta, getEntityMeta, getOnEvents, getWorkflowMeta, inAppWorkerProviders, isDeadLetterHandler, isDrivingOperator, isOperatorRole, isStepInterceptor, onErrorCodesOf, thinWorkerProviders, unavailableRunGateway };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { WorkflowCtx, SearchAttributes, WorkflowClass, StepError, WorkflowRef, SingletonConfig, ConcurrencyConfig, SearchAttributesSchema, StateStore, Transport, NamedTransport, ControlPlane, ScheduledWorkflow, RetentionPolicy, QueueConfig, AdmissionBackend, WorkflowInputOf, StartOptions, RunResult, RunGateway, WorkflowEngine, EntityHandler, DurableTopology, RunDetailOptions, RunDetail, FanPageQuery, FanPage, RunQuery, RunListItem, RunFacetQuery, RunFacetRow, RunValueAxis, RunValueFacetOptions, RunValueFacetRow, GroupHealth, RunWaiting, EngineEvent, RunRequest, RunReply, StepInvocation, WorkflowRun, TenantEvent } from '@dudousxd/nestjs-durable-core';
2
- export { AttributeFilter, DynamicWorkflowCtx, EngineEvent, InferSearchAttributes, RunDetail, RunGateway, RunListItem, RunQuery, RunStatus, RunWaiting, SearchAttributes, SearchAttributesSchema, StepCheckpoint, StepEvent, StepLogger, WorkflowCtx, WorkflowEngine, WorkflowHandler, WorkflowRun, readSearchAttributes } from '@dudousxd/nestjs-durable-core';
1
+ import { WorkflowCtx, SearchAttributes, WorkflowClass, StepError, OnErrorInput, WorkflowRef, SingletonConfig, ConcurrencyConfig, SearchAttributesSchema, StateStore, Transport, NamedTransport, ControlPlane, ScheduledWorkflow, RetentionPolicy, QueueConfig, AdmissionBackend, WorkflowInputOf, StartOptions, RunResult, RunGateway, WorkflowEngine, EntityHandler, DurableTopology, RunDetailOptions, RunDetail, FanPageQuery, FanPage, RunQuery, RunListItem, RunFacetQuery, RunFacetRow, RunValueAxis, RunValueFacetOptions, RunValueFacetRow, GroupHealth, RunWaiting, EngineEvent, RunRequest, RunReply, StepInvocation, WorkflowRun, TenantEvent } from '@dudousxd/nestjs-durable-core';
2
+ export { AttributeFilter, DynamicWorkflowCtx, EngineEvent, InferSearchAttributes, OnErrorInput, RunDetail, RunGateway, RunListItem, RunQuery, RunStatus, RunWaiting, SearchAttributes, SearchAttributesSchema, StepCheckpoint, StepEvent, StepLogger, WorkflowCtx, WorkflowEngine, WorkflowHandler, WorkflowRun, readSearchAttributes } from '@dudousxd/nestjs-durable-core';
3
3
  import { z } from 'zod';
4
4
  import { ConcurrencyOption, StartRunDeps, RunRedisWorkerOptions, RunningWorker, DurableWorkerRuntime } from '@dudousxd/durable-worker';
5
5
  import { DynamicModule, InjectionToken, OnModuleInit, OnApplicationBootstrap, OnApplicationShutdown, Provider } from '@nestjs/common';
@@ -108,6 +108,11 @@ interface WorkflowMeta {
108
108
  version: string;
109
109
  /** The workflow this workflow's dead runs route to (a name or a class). See `WorkflowOptions`. */
110
110
  deadLetterWorkflow?: WorkflowRef | undefined;
111
+ /** Where failed runs are routed by error code. See `WorkflowOptions`. */
112
+ onError?: {
113
+ code?: string | ErrorClassWithCode;
114
+ workflow: WorkflowRef;
115
+ }[] | undefined;
111
116
  /** Static searchable labels stamped on every run of this workflow. See `WorkflowOptions`. */
112
117
  tags?: string[] | undefined;
113
118
  /** Per-key serialization (a durable mutex). See `WorkflowOptions`. */
@@ -146,6 +151,16 @@ interface WorkflowOptions {
146
151
  * {@link DeadLetter} payload, idempotent by a `dlq:<runId>` id.
147
152
  */
148
153
  deadLetterWorkflow?: WorkflowRef;
154
+ /**
155
+ * Route failed runs of this workflow to other **registered** workflows by error code — the
156
+ * separate-class form of an `@OnError` method (see it for the semantics). Each handler receives an
157
+ * {@link OnErrorInput}; omit `code` for the catch-all. A code routed here and by an `@OnError`
158
+ * method on the class is a boot-time error.
159
+ */
160
+ onError?: {
161
+ code?: string | ErrorClassWithCode;
162
+ workflow: WorkflowRef;
163
+ }[];
149
164
  /**
150
165
  * Static labels stamped on **every run** of this workflow (e.g. `tags: ['etl', 'critical']`) and
151
166
  * merged with any per-run tags passed to `start`. Searchable/filterable in the dashboard.
@@ -356,6 +371,42 @@ interface DeadLetter<TInput = unknown> {
356
371
  */
357
372
  declare function DeadLetter(): MethodDecorator;
358
373
  declare function isDeadLetterHandler(method: Function): boolean;
374
+ declare const ON_ERROR_METADATA: unique symbol;
375
+ /**
376
+ * An error class that declares the `code` it is thrown with (`static readonly code = 'invalid_line'`).
377
+ * `@OnError(Class)` matches on that code, not on `instanceof`: a dispatched step's error reaches the
378
+ * workflow as a plain `{ message, code }`, without its class.
379
+ */
380
+ interface ErrorClassWithCode {
381
+ readonly code: string;
382
+ }
383
+ type WorkflowShape = {
384
+ run(ctx: any, input: any): Promise<unknown>;
385
+ };
386
+ /**
387
+ * An `@OnError` method: a workflow body that receives the failed run's {@link OnErrorInput}, typed with
388
+ * `run`'s input, and returns what `run` returns.
389
+ */
390
+ type OnErrorMethod<T extends WorkflowShape> = (ctx: WorkflowCtx<any>, failure: OnErrorInput<Parameters<T['run']>[1]>) => Promise<Awaited<ReturnType<T['run']>>>;
391
+ /**
392
+ * Marks a method on a `@Workflow` class as the handler for a failure of that workflow's runs. When a
393
+ * run ends `failed` with an error of the given `code` (a string, or an {@link ErrorClassWithCode}),
394
+ * the engine starts the method as its own durable workflow — registered as
395
+ * `<workflow>.onError.<method>`, with a `<runId>.onError` id — and the failed run waits for it, then
396
+ * settles with its outcome: the method's return value as its output, or its error. Without an
397
+ * argument it takes any failure no other code matches.
398
+ *
399
+ * The engine routes the failure, so this holds for whatever ran the body (inline, an in-app worker,
400
+ * another runtime). The method's signature is checked against the workflow: `(ctx, failure)`, with
401
+ * `failure.input` typed as `run`'s input and the return type as `run`'s. Stack the decorator to give
402
+ * one method several codes. Saga compensations of the failed body run before the handoff;
403
+ * cancellation and non-determinism are never routed.
404
+ */
405
+ declare function OnError(match?: string | ErrorClassWithCode): <T extends WorkflowShape>(_target: T, _propertyKey: string | symbol, descriptor: {
406
+ value?: OnErrorMethod<T> | undefined;
407
+ }) => void;
408
+ /** The codes an `@OnError` method takes (`undefined` for the catch-all), or undefined if it has none. */
409
+ declare function onErrorCodesOf(method: Function): (string | undefined)[] | undefined;
359
410
  declare const ON_EVENT_METADATA: unique symbol;
360
411
  /**
361
412
  * Subscribe a `@Workflow` class to one or more events: when any of them is published via
@@ -551,6 +602,18 @@ interface DurableModuleOptions {
551
602
  * a driving instance's poll picks it up. Ignored (irrelevant) for a thin worker (no `store`).
552
603
  */
553
604
  drive?: boolean;
605
+ /**
606
+ * Whether this process CONSUMES from the broker. Defaults to `true`. Set `false` in a process that
607
+ * boots the module without being a worker — a CLI command, a REPL, a migration or seed script — so
608
+ * it doesn't compete with the real fleet: every transport that supports it (`BullMQTransport`) has
609
+ * its point-to-point consumers (step tasks, results, decisions, step events, start-run, run-request)
610
+ * parked via `deferConsumers()`, and no co-located/thin worker consumer starts. The process still
611
+ * dispatches and starts runs; the jobs stay on the queues for the fleet. Pair it with
612
+ * `drive: false` so it doesn't poll/recover runs either. To consume later in the same process, call
613
+ * `startConsumers()` on your transport. A transport without `deferConsumers()` (the SQL/SQS/in-process
614
+ * transports) keeps consuming — a warning says so.
615
+ */
616
+ consumers?: boolean;
554
617
  /** Max ms to wait for in-flight runs on shutdown before exiting. Defaults to 10000. Operator only. */
555
618
  shutdownTimeoutMs?: number;
556
619
  /**
@@ -804,9 +867,10 @@ type RunRedisWorkerFn = (opts: RunRedisWorkerOptions) => Promise<RunningWorker>;
804
867
  */
805
868
  declare class ThinWorkflowRegistrar implements OnModuleInit {
806
869
  private readonly discovery;
870
+ private readonly metadataScanner;
807
871
  private readonly runtime;
808
872
  private readonly options;
809
- constructor(discovery: DiscoveryService, runtime: DurableWorkerRuntime | null, options: DurableModuleOptions);
873
+ constructor(discovery: DiscoveryService, metadataScanner: MetadataScanner, runtime: DurableWorkerRuntime | null, options: DurableModuleOptions);
810
874
  onModuleInit(): void;
811
875
  }
812
876
  /**
@@ -971,13 +1035,25 @@ declare class ProxyRunGateway implements RunGateway {
971
1035
  private readonly transport;
972
1036
  private readonly tenant;
973
1037
  private readonly timeoutMs;
1038
+ private readonly capabilityTtlMs;
974
1039
  private readonly pending;
975
- constructor(transport: Transport, tenant: string, timeoutMs?: number);
1040
+ /** Verb → when to ask the control plane for it again, after it answered that it does not know it.
1041
+ * During a rolling upgrade the control plane is several pods of mixed versions behind one queue,
1042
+ * and a reply does not say which pod sent it, so the whole control plane is assumed old until the
1043
+ * entry expires. */
1044
+ private readonly unsupportedUntil;
1045
+ constructor(transport: Transport, tenant: string, timeoutMs?: number, capabilityTtlMs?: number);
976
1046
  private handleReply;
977
1047
  private request;
978
1048
  topology(): DurableTopology;
1049
+ /**
1050
+ * A control plane that predates {@link RunDetailOptions} ignores them and sends the full detail;
1051
+ * a summarized detail always carries `fans`, so its absence means the summary is made here.
1052
+ */
979
1053
  getRunDetail(runId: string, options?: RunDetailOptions): Promise<RunDetail | null>;
1054
+ /** Paged from the full detail when the control plane is too old to page a fan itself. */
980
1055
  getFanMembers(runId: string, group: string, query: FanPageQuery): Promise<FanPage | null>;
1056
+ private knownUnsupported;
981
1057
  /** The control plane's `StoreRunGateway` resolves each run's `waiting` descriptor; the reply carries
982
1058
  * it through as plain JSON, so a tenant's list rows name the wait too. */
983
1059
  listRuns(query: RunQuery): Promise<RunListItem[]>;
@@ -1020,6 +1096,12 @@ declare function isOperatorRole(options: DurableModuleOptions): boolean;
1020
1096
  */
1021
1097
  declare function isDrivingOperator(options: DurableModuleOptions): boolean;
1022
1098
 
1099
+ /**
1100
+ * The error `code` a responder replies with for a verb it does not know, so a newer tenant can tell
1101
+ * "this control plane is older than me" from a real failure and fall back at once. Earlier
1102
+ * responders reply `ok: true` with no `data` instead; `ProxyRunGateway` reads both.
1103
+ */
1104
+ declare const UNSUPPORTED_RUN_REQUEST = "unsupported-request";
1023
1105
  /** The narrow slice of `Transport` the responder needs — a tenant's read/control request in, a
1024
1106
  * correlated reply out. Both are OPTIONAL on the full `Transport` interface (only broker
1025
1107
  * transports carry the run-request/reply protocol); the caller capability-checks before wiring
@@ -1235,4 +1317,4 @@ declare class WorkflowService {
1235
1317
  }): Promise<number>;
1236
1318
  }
1237
1319
 
1238
- export { CONTEXT_ACCESSOR, type ContextAccessor, type ContextStore, DEAD_LETTER_METADATA, DURABLE_STEP_METADATA, DURABLE_WORKER_RUNNERS, DURABLE_WORKER_RUNTIME, DeadLetter, DurableModule, type DurableModuleAsyncOptions, type DurableModuleOptions, type DurableRetentionOptions, DurableStartClient, DurableStep, type DurableStepInterceptor, type DurableStepMeta, ENTITY_METADATA, ENTITY_ON_METADATA, Entity, EntityService, IN_APP_RUN_REDIS_WORKER, IN_APP_WORKER_BINDING, IN_APP_WORKER_RUNNERS, IN_APP_WORKER_RUNTIME, type InAppWorkerBinding, InAppWorkerBootstrap, ON_EVENT_METADATA, On, OnDurableEvent, OnEvent, ProxyRunGateway, RUN_GATEWAY, RUN_REDIS_WORKER, type RunLookupStore, type RunRedisWorkerFn, RunRequestResponder, type RunRequestTransport, STEP_INTERCEPTOR_METADATA, Step, StepInterceptor, type StepOptions, StoreRunGateway, TenantEventRepublisher, ThinStepRegistrar, ThinWorkerBootstrap, ThinWorkflowRegistrar, type UserRef, WORKFLOW_METADATA, Workflow, type WorkflowAttributesOf, type WorkflowMeta, type WorkflowOptions, WorkflowService, attributesOf, entityConfigFor, getDurableStepMeta, getEntityMeta, getOnEvents, getWorkflowMeta, inAppWorkerProviders, isDeadLetterHandler, isDrivingOperator, isOperatorRole, isStepInterceptor, thinWorkerProviders, unavailableRunGateway };
1320
+ export { CONTEXT_ACCESSOR, type ContextAccessor, type ContextStore, DEAD_LETTER_METADATA, DURABLE_STEP_METADATA, DURABLE_WORKER_RUNNERS, DURABLE_WORKER_RUNTIME, DeadLetter, DurableModule, type DurableModuleAsyncOptions, type DurableModuleOptions, type DurableRetentionOptions, DurableStartClient, DurableStep, type DurableStepInterceptor, type DurableStepMeta, ENTITY_METADATA, ENTITY_ON_METADATA, Entity, EntityService, type ErrorClassWithCode, IN_APP_RUN_REDIS_WORKER, IN_APP_WORKER_BINDING, IN_APP_WORKER_RUNNERS, IN_APP_WORKER_RUNTIME, type InAppWorkerBinding, InAppWorkerBootstrap, ON_ERROR_METADATA, ON_EVENT_METADATA, On, OnDurableEvent, OnError, type OnErrorMethod, OnEvent, ProxyRunGateway, RUN_GATEWAY, RUN_REDIS_WORKER, type RunLookupStore, type RunRedisWorkerFn, RunRequestResponder, type RunRequestTransport, STEP_INTERCEPTOR_METADATA, Step, StepInterceptor, type StepOptions, StoreRunGateway, TenantEventRepublisher, ThinStepRegistrar, ThinWorkerBootstrap, ThinWorkflowRegistrar, UNSUPPORTED_RUN_REQUEST, type UserRef, WORKFLOW_METADATA, Workflow, type WorkflowAttributesOf, type WorkflowMeta, type WorkflowOptions, WorkflowService, attributesOf, entityConfigFor, getDurableStepMeta, getEntityMeta, getOnEvents, getWorkflowMeta, inAppWorkerProviders, isDeadLetterHandler, isDrivingOperator, isOperatorRole, isStepInterceptor, onErrorCodesOf, thinWorkerProviders, unavailableRunGateway };