@dudousxd/nestjs-durable-core 0.49.3 → 0.50.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
@@ -161,6 +161,74 @@ declare class InMemoryAdmissionBackend implements AdmissionBackend {
161
161
  release(queue: string, _slotId: string): Promise<void>;
162
162
  }
163
163
 
164
+ /**
165
+ * Vendored subset of the Standard Schema spec (https://standardschema.dev) — the `~standard`
166
+ * property protocol implemented by zod 3.24+, valibot, arktype, and others. Vendored (rather than
167
+ * taken as a dependency) so core stays dependency-free at runtime: this file is types only, erased
168
+ * entirely by the build. Source: https://github.com/standard-schema/standard-schema (MIT, Colin
169
+ * McDonnell) — trimmed to the `StandardSchemaV1` shape this package actually consumes (drops the
170
+ * sibling `StandardTypedV1`/`StandardJSONSchemaV1` specs the upstream package also exports).
171
+ *
172
+ * Used to type `@Workflow({ searchAttributes })` (see `WorkflowMeta.searchAttributes` in
173
+ * `@dudousxd/nestjs-durable` and `SearchAttributesSchema`/`InferSearchAttributes` in `interfaces.ts`)
174
+ * so a workflow can declare its search-attribute shape with whatever schema library it already uses,
175
+ * without core taking a hard dependency on any of them.
176
+ */
177
+ interface StandardSchemaV1<Input = unknown, Output = Input> {
178
+ /** The Standard Schema properties. */
179
+ readonly '~standard': StandardSchemaV1.Props<Input, Output>;
180
+ }
181
+ declare namespace StandardSchemaV1 {
182
+ /** The Standard Schema properties interface. */
183
+ interface Props<Input = unknown, Output = Input> {
184
+ /** The version number of the standard. */
185
+ readonly version: 1;
186
+ /** The vendor name of the schema library. */
187
+ readonly vendor: string;
188
+ /** Validates unknown input values. */
189
+ readonly validate: (value: unknown) => Result<Output> | Promise<Result<Output>>;
190
+ /** Inferred types associated with the schema. */
191
+ readonly types?: Types<Input, Output> | undefined;
192
+ }
193
+ /** The result interface of the validate function. */
194
+ type Result<Output> = SuccessResult<Output> | FailureResult;
195
+ /** The result interface if validation succeeds. */
196
+ interface SuccessResult<Output> {
197
+ /** The typed output value. */
198
+ readonly value: Output;
199
+ /** A falsy value for `issues` indicates success. */
200
+ readonly issues?: undefined;
201
+ }
202
+ /** The result interface if validation fails. */
203
+ interface FailureResult {
204
+ /** The issues of failed validation. */
205
+ readonly issues: ReadonlyArray<Issue>;
206
+ }
207
+ /** The issue interface of the failure output. */
208
+ interface Issue {
209
+ /** The error message of the issue. */
210
+ readonly message: string;
211
+ /** The path of the issue, if any. */
212
+ readonly path?: ReadonlyArray<PropertyKey | PathSegment> | undefined;
213
+ }
214
+ /** The path segment interface of the issue. */
215
+ interface PathSegment {
216
+ /** The key representing a path segment. */
217
+ readonly key: PropertyKey;
218
+ }
219
+ /** The Standard Schema types interface. */
220
+ interface Types<Input = unknown, Output = Input> {
221
+ /** The input type of the schema. */
222
+ readonly input: Input;
223
+ /** The output type of the schema. */
224
+ readonly output: Output;
225
+ }
226
+ /** Infers the input type of a Standard Schema. */
227
+ type InferInput<Schema extends StandardSchemaV1> = NonNullable<Schema['~standard']['types']>['input'];
228
+ /** Infers the output type of a Standard Schema. */
229
+ type InferOutput<Schema extends StandardSchemaV1> = NonNullable<Schema['~standard']['types']>['output'];
230
+ }
231
+
164
232
  /**
165
233
  * Cross-package step-name stamp. The `@Step` decorator (`@dudousxd/nestjs-durable`) writes a
166
234
  * method's derived routing name under this key; core's `ctx.step` reads it (via {@link stepNameOf})
@@ -337,8 +405,10 @@ interface WorkflowRun {
337
405
  * store-backed gateway from the run's signal waiters (`listSignalWaiters`, ONE bulk scan), so the
338
406
  * dashboard can NAME the wait in a list row without fetching each run's timeline. `on` is derived from
339
407
  * the waiter token's prefix (see `classifyWaiterToken`): `wh:<runId>:<seq>` ⇒ `webhook`, `child:<id>`
340
- * ⇒ `child`, `event:<name>:…` ⇒ `signal` (name decoded), anything else ⇒ `signal` (the token IS the
341
- * signal name).
408
+ * ⇒ `child`, `bp:<runId>:<seq>` ⇒ `breakpoint` (a `ctx.breakpoint` DOES register a signal waiter —
409
+ * same machinery, `engine.continue` resumes it — so it's classified here, not left to fall through to
410
+ * the generic `signal` case with the raw token as its ugly display name), `event:<name>:…` ⇒ `signal`
411
+ * (name decoded), anything else ⇒ `signal` (the token IS the signal name).
342
412
  *
343
413
  * Deliberately EVENT-only (no timer/step): `wakeAt` alone can't tell a real `ctx.sleep` from the
344
414
  * reconcile-fallback `wakeAt` an event/step suspend now carries, and the store exposes no cheap bulk
@@ -347,8 +417,13 @@ interface WorkflowRun {
347
417
  * The detail view (which has the timeline) still distinguishes sleep vs in-flight step precisely.
348
418
  */
349
419
  interface RunWaiting {
350
- on: 'signal' | 'webhook' | 'child';
351
- /** The token/name the run is parked on — the signal name, webhook token, or awaited child id. */
420
+ on: 'signal' | 'webhook' | 'child' | 'breakpoint';
421
+ /**
422
+ * The token/name the run is parked on — the signal name, webhook token, or awaited child id. For a
423
+ * breakpoint this is always the literal `'breakpoint'`: the real label (if any) lives on the pending
424
+ * `breakpoint`/`breakpoint:<label>` checkpoint, which the detail view's timeline already shows —
425
+ * naming it here would need an extra per-run checkpoint read, defeating the bulk waiter scan.
426
+ */
352
427
  name: string;
353
428
  }
354
429
  type StepKind = 'local' | 'remote' | 'sleep' | 'signal';
@@ -618,6 +693,38 @@ interface RetentionPolicy {
618
693
  }
619
694
  /** Typed, queryable per-run data — exact values for `eq`/`ne`, numbers/strings for range ops. */
620
695
  type SearchAttributes = Record<string, string | number | boolean>;
696
+ /**
697
+ * A Standard Schema (https://standardschema.dev — implemented by zod 3.24+, valibot, arktype, …)
698
+ * whose validated OUTPUT is search-attribute-shaped: flat `string`/`number`/`boolean` values only.
699
+ * Declared via `@Workflow({ searchAttributes })`, this makes `ctx.upsertSearchAttributes` reject any
700
+ * write whose merged result doesn't conform. The `Output extends SearchAttributes` bound is enforced
701
+ * structurally at the declaration site — a schema whose inferred output has a nested object/array
702
+ * value (e.g. `z.object({ meta: z.object({ ... }) })`) fails to satisfy this type, so it's a
703
+ * compile-time error to declare it as a `searchAttributes` schema, not a runtime surprise.
704
+ *
705
+ * @example
706
+ * ```ts
707
+ * import { z } from 'zod';
708
+ *
709
+ * const orderAttrs = z.object({
710
+ * tier: z.enum(['free', 'pro']),
711
+ * amount: z.number(),
712
+ * rushOrder: z.boolean().optional(),
713
+ * });
714
+ *
715
+ * @Workflow({ name: 'checkout', searchAttributes: orderAttrs })
716
+ * class CheckoutWorkflow {
717
+ * async run(ctx: WorkflowCtx<InferSearchAttributes<typeof orderAttrs>>, input: CheckoutInput) {
718
+ * await ctx.upsertSearchAttributes({ tier: input.tier, amount: input.total });
719
+ * }
720
+ * }
721
+ * ```
722
+ */
723
+ type SearchAttributesSchema<A extends SearchAttributes = SearchAttributes> = StandardSchemaV1<unknown, A>;
724
+ /** Infer the validated OUTPUT shape of a {@link SearchAttributesSchema} — the typed attributes a
725
+ * workflow declares via `@Workflow({ searchAttributes })`. Feed it straight into `WorkflowCtx<A>`:
726
+ * `WorkflowCtx<InferSearchAttributes<typeof mySchema>>`. */
727
+ type InferSearchAttributes<S extends StandardSchemaV1<unknown, SearchAttributes>> = StandardSchemaV1.InferOutput<S>;
621
728
  type AttributeOp = 'eq' | 'ne' | 'gt' | 'gte' | 'lt' | 'lte';
622
729
  /** One predicate over a run's {@link SearchAttributes}; a {@link RunQuery} ANDs them all. */
623
730
  interface AttributeFilter {
@@ -730,6 +837,12 @@ type RunRequestKind = {
730
837
  kind: 'retryWithInput';
731
838
  runId: string;
732
839
  input: unknown;
840
+ } | {
841
+ kind: 'redispatch';
842
+ runId: string;
843
+ } | {
844
+ kind: 'waitingFor';
845
+ runIds: string[];
733
846
  };
734
847
  /** The control plane's answer to a {@link RunRequest}, correlated by `requestId`. */
735
848
  interface RunReply {
@@ -1320,8 +1433,13 @@ type UndoOf<H> = H extends (input: infer I, ...rest: never[]) => infer R ? StepU
1320
1433
  /**
1321
1434
  * The context handed to a workflow function. Every interaction with the outside world goes
1322
1435
  * through it so the engine can checkpoint — the workflow body itself stays deterministic.
1436
+ *
1437
+ * Generic over `A`, the run's {@link SearchAttributes} shape — narrows {@link upsertSearchAttributes}
1438
+ * when a workflow declares a `@Workflow({ searchAttributes })` schema (pass
1439
+ * `WorkflowCtx<InferSearchAttributes<typeof mySchema>>` as the `run` method's ctx type). Defaults to
1440
+ * the untyped `SearchAttributes`, so every existing `WorkflowCtx` usage is unaffected.
1323
1441
  */
1324
- interface WorkflowCtx {
1442
+ interface WorkflowCtx<A extends SearchAttributes = SearchAttributes> {
1325
1443
  readonly runId: string;
1326
1444
  /**
1327
1445
  * Run a durable step — always dispatched, always engine-scheduled: the ONE step primitive (no
@@ -1528,8 +1646,16 @@ interface WorkflowCtx {
1528
1646
  * write, not one per turn. Use this instead of injecting the {@link StateStore} to mutate the run
1529
1647
  * you're executing (`@Inject(state-store)` + `store.updateRun(ctx.runId, …)` becomes
1530
1648
  * `ctx.upsertSearchAttributes(…)`).
1649
+ *
1650
+ * When the workflow declares a `@Workflow({ searchAttributes })` schema, the MERGED result (this
1651
+ * run's existing `searchAttributes` shallow-merged with `attrs`) is validated against it before the
1652
+ * write — an invalid merge throws, naming the workflow, the offending key(s), and the schema's
1653
+ * issues. Validation runs once, on the same first-run-only position as the write itself (skipped
1654
+ * entirely on replay, so it's never a source of nondeterminism); it must be synchronous — a schema
1655
+ * whose `validate` returns a `Promise` throws instead of being awaited. No schema declared ⇒
1656
+ * unchanged, unvalidated behavior.
1531
1657
  */
1532
- upsertSearchAttributes(attrs: SearchAttributes): Promise<void>;
1658
+ upsertSearchAttributes(attrs: Partial<A>): Promise<void>;
1533
1659
  /**
1534
1660
  * Run a checkpointed step **in-process** — the escape hatch from the always-dispatched {@link step}
1535
1661
  * for work that must run inline in the workflow body. Like `step`, its result is a durable checkpoint
@@ -1818,6 +1944,27 @@ interface WorkflowEngineDeps {
1818
1944
  * for a genuinely-orphaned run. Default 5min; set `0` to disable (the prior wake-forever behavior).
1819
1945
  */
1820
1946
  reconcileMs?: number | undefined;
1947
+ /**
1948
+ * Opt-in self-heal window (ms) for a remote step with NO `timeoutMs` whose dispatched job was LOST —
1949
+ * the worker crashed mid-step leaving no result, or the transport dropped the job (a Redis
1950
+ * flush/eviction, or BullMQ moving a stalled job to `failed` and removing it). The `pending`
1951
+ * checkpoint then has no result to resume on, and — BY DESIGN (see {@link reconcileMs}) — the
1952
+ * reconcile re-drive re-suspends a still-pending step rather than re-dispatching, so a slow-but-live
1953
+ * worker is never double-run. That safety means a genuinely-lost dispatch would otherwise hang
1954
+ * forever. When set, a reconcile re-drive that finds a remote step still `pending` PAST this window
1955
+ * re-dispatches it (bumping `attempts`, bounded by {@link remoteRedispatchMax}). Off by default:
1956
+ * re-dispatch can double-run a step whose original job is merely slow, so the window MUST exceed the
1957
+ * longest such step and the step MUST be idempotent. Prefer a per-step `timeoutMs` (tighter,
1958
+ * heartbeat-aware) where you can; this is the store-driven net for no-timeout steps that must
1959
+ * survive a lost dispatch. {@link WorkflowEngine.redispatchPending} is the manual counterpart.
1960
+ */
1961
+ remoteRedispatchMs?: number | undefined;
1962
+ /**
1963
+ * Max times {@link remoteRedispatchMs} re-dispatches one lost remote step before giving up and
1964
+ * failing it as a {@link RemoteStepError} (`code: 'remote_step_lost'`), so the run fails / dead-letters
1965
+ * instead of re-dispatching forever. Default 10. Ignored when `remoteRedispatchMs` is unset.
1966
+ */
1967
+ remoteRedispatchMax?: number | undefined;
1821
1968
  /**
1822
1969
  * Build the public callback URL for a `ctx.webhook()` token (e.g.
1823
1970
  * ``(t) => `https://api.example.com/durable/webhooks/${t}` ``). Populates
@@ -1894,6 +2041,8 @@ declare class WorkflowEngine {
1894
2041
  private readonly maxRecoveryAttempts?;
1895
2042
  private readonly remoteAdvanceSilenceMs?;
1896
2043
  private readonly reconcileMs;
2044
+ private readonly remoteRedispatchMs;
2045
+ private readonly remoteRedispatchMax;
1897
2046
  private readonly webhookUrl?;
1898
2047
  private readonly traceparent?;
1899
2048
  private readonly context?;
@@ -1983,6 +2132,8 @@ declare class WorkflowEngine {
1983
2132
  singleton?: SingletonConfig | undefined;
1984
2133
  executionTimeout?: string | number | undefined;
1985
2134
  validateInput?: ((input: unknown) => void | Promise<void>) | undefined;
2135
+ /** Typed/validated `searchAttributes` shape — see `RegisteredWorkflow.searchAttributesSchema`. */
2136
+ searchAttributesSchema?: SearchAttributesSchema | undefined;
1986
2137
  onEvent?: string[] | undefined;
1987
2138
  eventBatch?: EventBatchConfig | undefined;
1988
2139
  /** Worker group to DISPATCH this workflow's turns to (uniform dispatch). Requires `executor`.
@@ -2186,6 +2337,19 @@ declare class WorkflowEngine {
2186
2337
  * the HTTP request on workflow execution.
2187
2338
  */
2188
2339
  requeue(runId: string): Promise<RunResult | null>;
2340
+ /**
2341
+ * Explicitly re-dispatch every remote step of `runId` stuck `pending` — the OPERATOR escape hatch for
2342
+ * a run whose dispatched step job was LOST (worker crashed with no result, or a transport that dropped
2343
+ * the job). No automatic recovery re-drives these: a reconcile re-drive re-suspends a still-pending
2344
+ * step by design (unless `remoteRedispatchMs` is set), `recoverIncomplete` only reclaims LEASED runs,
2345
+ * and `requeue` just replays back to the pending guard. This re-enqueues the same `stepId` so the
2346
+ * (idempotent) step re-runs and its result resumes the run. Safe to call on a healthy run — it re-runs
2347
+ * only in-flight `pending` remote steps, which are idempotent by the durable contract. Returns the
2348
+ * run's current status (with the count re-dispatched), or null if the run is unknown.
2349
+ */
2350
+ redispatchPending(runId: string): Promise<(RunResult & {
2351
+ redispatched: number;
2352
+ }) | null>;
2189
2353
  /**
2190
2354
  * **Fix-and-replay**: re-run a run (typically a `dead`/`failed` one) with a corrected `input`, as a
2191
2355
  * fresh run with clean history. It's a NEW run — `newRunId` defaults to `<runId>~retry~<uuid>` — so
@@ -2488,6 +2652,10 @@ declare class WorkflowEngine {
2488
2652
  */
2489
2653
  update(runId: string, name: string, arg: unknown): Promise<UpdateResult>;
2490
2654
  private callRemote;
2655
+ /** Enqueue a remote step task to its worker group via the transport pool. Shared by the initial
2656
+ * dispatch, the opt-in self-heal re-dispatch (see `remoteRedispatchMs`), and the explicit
2657
+ * {@link redispatchPending}. Carries the current trace/context so a re-dispatch is traceable. */
2658
+ private dispatchRemoteTask;
2491
2659
  /**
2492
2660
  * Complete a durable remote step from its worker result and resume the run — runs on whichever
2493
2661
  * instance receives the result (the dispatching one may be gone), so the run is crash/scale-safe.
@@ -2789,7 +2957,9 @@ interface DurableTopology {
2789
2957
  /** The tenant's isolation partition name; set only when `role` is 'tenant'. */
2790
2958
  tenant?: string;
2791
2959
  }
2792
- /** A run + its timeline + child ids — the detail view. Mirrors the dashboard's `RunDetail`. */
2960
+ /** A run + its timeline + child ids — the detail view. Single source of truth: the dashboard server
2961
+ * re-exports this instead of re-declaring it, and the dashboard client derives its wire mirror from
2962
+ * it via {@link WireDates} instead of hand-mirroring field by field. */
2793
2963
  interface RunDetail {
2794
2964
  run: WorkflowRun;
2795
2965
  /** Steps in execution order (local + remote). */
@@ -2797,6 +2967,17 @@ interface RunDetail {
2797
2967
  /** Ids of runs this run spawned (parent→children tree). */
2798
2968
  children: string[];
2799
2969
  }
2970
+ /**
2971
+ * Maps every `Date` (and `Date | undefined`) field of `T` to its ISO-string wire form — the shape a
2972
+ * JSON response actually carries once dates cross the wire (`JSON.stringify` already does this
2973
+ * coercion; this just types it). Homomorphic: each field keeps its own optional modifier, so a
2974
+ * required `Date` becomes a required `string` and an optional one stays optional. Lets a consumer
2975
+ * derive its own wire-facing client type from a core server type (e.g. the dashboard's SPA `WorkflowRun`/
2976
+ * `StepCheckpoint`/`RunDetail`) instead of hand-mirroring it field by field and drifting.
2977
+ */
2978
+ type WireDates<T> = {
2979
+ [K in keyof T]: T[K] extends Date ? string : T[K] extends Date | undefined ? string | undefined : T[K];
2980
+ };
2800
2981
  /**
2801
2982
  * The bounded read/control/stream surface a consumer (e.g. a controller) needs, satisfied by BOTH
2802
2983
  * topologies: the control plane binds a store-backed impl (reuses `DashboardService`); a tenant binds
@@ -2812,6 +2993,17 @@ interface RunGateway {
2812
2993
  * parked on). The store-backed gateway resolves `waiting`; a proxy relays whatever the control
2813
2994
  * plane sent. */
2814
2995
  listRuns(query: RunQuery): Promise<RunListItem[]>;
2996
+ /**
2997
+ * Bulk-resolve {@link RunWaiting} for an arbitrary set of run ids — for a consumer with its OWN
2998
+ * filtered/paginated run listing (so it isn't just `listRuns` under another name) that needs to know
2999
+ * which of ITS runs are parked on a breakpoint (or any other event wait) without re-deriving the bulk
3000
+ * waiter scan itself or reaching for raw SQL against `durable_step_checkpoints`. A `Record` (not a
3001
+ * `Map`) because `ProxyRunGateway` serialises the reply over the transport as plain JSON. Entries are
3002
+ * present ONLY for runs currently waiting — an unknown id, a non-suspended id, and a suspended id
3003
+ * parked on something non-event (a bare `ctx.sleep`, an in-flight step) are simply absent, same as a
3004
+ * `listRuns` row with no `waiting`.
3005
+ */
3006
+ waitingFor(runIds: string[]): Promise<Record<string, RunWaiting>>;
2815
3007
  /** Per-group worker health (queue backlog + live worker heartbeats). On the control plane this is
2816
3008
  * every group; over a tenant proxy the operator scopes it to the tenant's own groups. */
2817
3009
  workerHealth(): Promise<GroupHealth[]>;
@@ -2820,6 +3012,12 @@ interface RunGateway {
2820
3012
  }): Promise<RunResult | null>;
2821
3013
  retry(runId: string): Promise<RunResult | null>;
2822
3014
  continue(runId: string): Promise<RunResult | null>;
3015
+ /** Re-dispatch every remote step of a run stuck `pending` — the operator recovery for a LOST step
3016
+ * dispatch (crashed worker / dropped job) that no automatic path re-drives. Returns the run's status
3017
+ * plus how many steps were re-dispatched, or null if the run is unknown. */
3018
+ redispatchPending(runId: string): Promise<(RunResult & {
3019
+ redispatched: number;
3020
+ }) | null>;
2823
3021
  retryWithInput(runId: string, input: unknown): Promise<{
2824
3022
  runId: string;
2825
3023
  } | null>;
@@ -2832,6 +3030,11 @@ interface RunGateway {
2832
3030
  * The token prefix carries the kind — no extra store lookup and no new persisted field. Used by the
2833
3031
  * store-backed run gateway to stamp {@link RunWaiting} onto each listed run so the dashboard can name
2834
3032
  * the wait in a row without fetching that run's timeline.
3033
+ *
3034
+ * `ctx.breakpoint` reuses the signal-waiter machinery (`engine.continue` resumes it via `signal()`
3035
+ * like any other), so without this case it would fall through to the generic `signal` branch with the
3036
+ * raw `bp:<runId>:<seq>` token as its display name — a real bug. Named `'breakpoint'` here instead;
3037
+ * the token carries no separate label to recover cheaply (see {@link RunWaiting.name}).
2835
3038
  */
2836
3039
  declare function classifyWaiterToken(token: string): RunWaiting;
2837
3040
  /**
@@ -3079,6 +3282,35 @@ declare function attributeColumnFor(filter: AttributeFilter): 'numValue' | 'strV
3079
3282
  /** The literal a side-table predicate compares against (booleans → `"true"`/`"false"` strings). */
3080
3283
  declare function attributeOperand(filter: AttributeFilter): string | number;
3081
3284
 
3285
+ /**
3286
+ * Read a run's `searchAttributes` through a {@link SearchAttributesSchema}, typed to the schema's
3287
+ * inferred output. **Safe-parse semantics, deliberately lenient** — unlike
3288
+ * `ctx.upsertSearchAttributes` (which is strict: an invalid merge throws), a failed validation here
3289
+ * returns `{}` rather than throwing. This is intentional: `run.searchAttributes` may predate the
3290
+ * schema (an older deploy wrote it under a looser or absent schema, or a run started before this
3291
+ * workflow ever declared one), and a dashboard/read path crashing on old history is worse than it
3292
+ * quietly reporting no typed attributes for that run. Write-time enforcement is what keeps NEW writes
3293
+ * conformant; this is the read-side counterpart for consuming them.
3294
+ *
3295
+ * The schema's `validate` must be synchronous (matching the write-side constraint in
3296
+ * `ctx.upsertSearchAttributes`) — one returning a `Promise` throws with a clear error rather than
3297
+ * being silently awaited or silently treated as a failure.
3298
+ *
3299
+ * @example
3300
+ * ```ts
3301
+ * import { z } from 'zod';
3302
+ * import { readSearchAttributes } from '@dudousxd/nestjs-durable-core';
3303
+ *
3304
+ * const orderAttrs = z.object({ tier: z.enum(['free', 'pro']), amount: z.number() });
3305
+ *
3306
+ * const run = await store.getRun(runId);
3307
+ * const attrs = readSearchAttributes(orderAttrs, run ?? {}); // { tier: 'pro', amount: 42 } | {}
3308
+ * ```
3309
+ */
3310
+ declare function readSearchAttributes<S extends SearchAttributesSchema>(schema: S, run: {
3311
+ searchAttributes?: SearchAttributes | undefined;
3312
+ }): InferSearchAttributes<S>;
3313
+
3082
3314
  /**
3083
3315
  * Compute the worker group a tenant's run dispatches to. Mirrors the transport's
3084
3316
  * default-is-bare rule (see {@link TransportPool.useNamespace}'s `'default'` no-op): a
@@ -3226,4 +3458,4 @@ declare class InMemoryTransport implements Transport, ControlPlane {
3226
3458
  onControl(handler: (msg: ControlMessage) => void): void;
3227
3459
  }
3228
3460
 
3229
- 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 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, SignalTimeoutError, type SignalWaiter, type SingletonConfig, SingletonQueueFullError, 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 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, resolveRunWaiting, runInWorkflowCtx, runSchedules, runStepHandler, sanitizeQueueToken, scheduledRunId, sqlComparator, stepConfigOf, stepId, stepNameOf, tenantGroup, workflowName };
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 };