@dudousxd/nestjs-durable 0.15.0 → 0.16.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/LICENSE +21 -0
- package/dist/index.cjs +790 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +411 -0
- package/dist/index.d.ts +411 -8
- package/dist/index.js +744 -21
- package/dist/index.js.map +1 -1
- package/package.json +21 -7
- package/dist/context-accessor.d.ts +0 -31
- package/dist/context-accessor.d.ts.map +0 -1
- package/dist/context-accessor.js +0 -3
- package/dist/context-accessor.js.map +0 -1
- package/dist/decorators.d.ts +0 -146
- package/dist/decorators.d.ts.map +0 -1
- package/dist/decorators.js +0 -103
- package/dist/decorators.js.map +0 -1
- package/dist/durable-step.registrar.d.ts +0 -30
- package/dist/durable-step.registrar.d.ts.map +0 -1
- package/dist/durable-step.registrar.js +0 -85
- package/dist/durable-step.registrar.js.map +0 -1
- package/dist/durable.module.d.ts +0 -108
- package/dist/durable.module.d.ts.map +0 -1
- package/dist/durable.module.js +0 -207
- package/dist/durable.module.js.map +0 -1
- package/dist/entity.d.ts +0 -43
- package/dist/entity.d.ts.map +0 -1
- package/dist/entity.js +0 -94
- package/dist/entity.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/input-validation.d.ts +0 -9
- package/dist/input-validation.d.ts.map +0 -1
- package/dist/input-validation.js +0 -30
- package/dist/input-validation.js.map +0 -1
- package/dist/step-interceptor.d.ts +0 -20
- package/dist/step-interceptor.d.ts.map +0 -1
- package/dist/step-interceptor.js +0 -22
- package/dist/step-interceptor.js.map +0 -1
- package/dist/timer-poller.d.ts +0 -20
- package/dist/timer-poller.d.ts.map +0 -1
- package/dist/timer-poller.js +0 -81
- package/dist/timer-poller.js.map +0 -1
- package/dist/tokens.d.ts +0 -13
- package/dist/tokens.d.ts.map +0 -1
- package/dist/tokens.js +0 -16
- package/dist/tokens.js.map +0 -1
- package/dist/workflow.registrar.d.ts +0 -33
- package/dist/workflow.registrar.d.ts.map +0 -1
- package/dist/workflow.registrar.js +0 -169
- package/dist/workflow.registrar.js.map +0 -1
- package/dist/workflow.service.d.ts +0 -55
- package/dist/workflow.service.d.ts.map +0 -1
- package/dist/workflow.service.js +0 -58
- package/dist/workflow.service.js.map +0 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,411 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
1
|
+
import { StepError, WorkflowRef, SingletonConfig, StateStore, Transport, NamedTransport, ControlPlane, ScheduledWorkflow, QueueConfig, WorkflowEngine, EntityHandler, StepInvocation, WorkflowClass, WorkflowInputOf, StartOptions, RunResult } from '@dudousxd/nestjs-durable-core';
|
|
2
|
+
import { DynamicModule, InjectionToken } from '@nestjs/common';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Local, structural mirror of `@dudousxd/nestjs-context`'s public accessor
|
|
6
|
+
* (`packages/core/src/accessor.ts`).
|
|
7
|
+
*
|
|
8
|
+
* We deliberately do NOT import nestjs-context (it is an OPTIONAL peer). Instead
|
|
9
|
+
* we declare the same shape here and inject it via the shared
|
|
10
|
+
* {@link CONTEXT_ACCESSOR} token with `@Optional()`. Any object that structurally
|
|
11
|
+
* satisfies this interface — including nestjs-context's real accessor — works.
|
|
12
|
+
*
|
|
13
|
+
* Kept byte-aligned with nestjs-context's `ContextAccessor` (and the identical
|
|
14
|
+
* mirror in `@dudousxd/nestjs-authz`): `traceId()` / `tenantId()` are REQUIRED
|
|
15
|
+
* (the real accessor always provides them) and `get()` is included, so the
|
|
16
|
+
* structural match stays exact when DurableModule auto-feeds the carrier.
|
|
17
|
+
*/
|
|
18
|
+
interface UserRef {
|
|
19
|
+
type: string;
|
|
20
|
+
id: string | number;
|
|
21
|
+
}
|
|
22
|
+
/** Opaque shape of the context store. durable never reads it; mirrors the upstream surface. */
|
|
23
|
+
type ContextStore = Record<string, unknown>;
|
|
24
|
+
interface ContextAccessor {
|
|
25
|
+
/** Trace id for the current request, or `undefined` when unavailable. */
|
|
26
|
+
traceId(): string | undefined;
|
|
27
|
+
/** Current tenant id, or `undefined` when no multi-tenant context is populated. */
|
|
28
|
+
tenantId(): string | undefined;
|
|
29
|
+
/** Reference to the current user, or `undefined` when unauthenticated. */
|
|
30
|
+
userRef(): UserRef | undefined;
|
|
31
|
+
/** The raw context store for the current request, or `undefined`. */
|
|
32
|
+
get(): ContextStore | undefined;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
declare const WORKFLOW_METADATA: unique symbol;
|
|
36
|
+
interface WorkflowMeta {
|
|
37
|
+
name: string;
|
|
38
|
+
version: string;
|
|
39
|
+
/** The workflow this workflow's dead runs route to (a name or a class). See `WorkflowOptions`. */
|
|
40
|
+
deadLetterWorkflow?: WorkflowRef | undefined;
|
|
41
|
+
/** Static searchable labels stamped on every run of this workflow. See `WorkflowOptions`. */
|
|
42
|
+
tags?: string[] | undefined;
|
|
43
|
+
/** Per-key serialization (a durable mutex). See `WorkflowOptions`. */
|
|
44
|
+
singleton?: SingletonConfig | undefined;
|
|
45
|
+
/** Max wall-clock lifetime before a run is cancelled (e.g. `'2h'`). See `WorkflowOptions`. */
|
|
46
|
+
executionTimeout?: string | number | undefined;
|
|
47
|
+
/** class-validator DTO validated at start. See `WorkflowOptions`. */
|
|
48
|
+
inputSchema?: (new (...args: any[]) => object) | undefined;
|
|
49
|
+
/** Custom input validator (throws on invalid). See `WorkflowOptions`. */
|
|
50
|
+
validateInput?: ((input: unknown) => void | Promise<void>) | undefined;
|
|
51
|
+
/** Event names that start a fresh run of this workflow. See `WorkflowOptions`. */
|
|
52
|
+
onEvent?: string[] | undefined;
|
|
53
|
+
/** Debounce `onEvent` triggers — fire once it's quiet for this long. See `WorkflowOptions`. */
|
|
54
|
+
debounce?: string | number | undefined;
|
|
55
|
+
/** Batch `onEvent` triggers — fire on size or window. See `WorkflowOptions`. */
|
|
56
|
+
batch?: {
|
|
57
|
+
maxSize: number;
|
|
58
|
+
within: string | number;
|
|
59
|
+
} | undefined;
|
|
60
|
+
}
|
|
61
|
+
interface WorkflowOptions {
|
|
62
|
+
name: string;
|
|
63
|
+
version?: string;
|
|
64
|
+
/**
|
|
65
|
+
* Route this workflow's dead-lettered runs to another **registered** workflow — by class
|
|
66
|
+
* (`deadLetterWorkflow: CheckoutDlqWorkflow`, refactor-safe) or by name for a cross-runtime
|
|
67
|
+
* handler. For a handler co-located on the same class, prefer an inline `@DeadLetter()` method
|
|
68
|
+
* instead — it takes precedence, and declaring both is a boot-time error. The handler receives a
|
|
69
|
+
* {@link DeadLetter} payload, idempotent by a `dlq:<runId>` id.
|
|
70
|
+
*/
|
|
71
|
+
deadLetterWorkflow?: WorkflowRef;
|
|
72
|
+
/**
|
|
73
|
+
* Static labels stamped on **every run** of this workflow (e.g. `tags: ['etl', 'critical']`) and
|
|
74
|
+
* merged with any per-run tags passed to `start`. Searchable/filterable in the dashboard.
|
|
75
|
+
*/
|
|
76
|
+
tags?: string[];
|
|
77
|
+
/**
|
|
78
|
+
* Serialize runs of this workflow that share a key — a durable FIFO mutex. e.g.
|
|
79
|
+
* `singleton: { key: (input) => `base:${input.baseId}` }` runs at most one pipeline per base at a
|
|
80
|
+
* time; same-key runs queue (suspended) and admit in creation order as slots free. `limit` (default
|
|
81
|
+
* 1) raises the concurrency.
|
|
82
|
+
*/
|
|
83
|
+
singleton?: SingletonConfig;
|
|
84
|
+
/**
|
|
85
|
+
* Max wall-clock lifetime for a run of this workflow (e.g. `'2h'`, `'7 days'`, or ms). A run that
|
|
86
|
+
* outlives it is moved to `cancelled` (`execution_timeout`) by the timer poller — a backstop for
|
|
87
|
+
* runs that get stuck or loop forever. Omit for no limit.
|
|
88
|
+
*/
|
|
89
|
+
executionTimeout?: string | number;
|
|
90
|
+
/**
|
|
91
|
+
* Validate the workflow input at `start` against a **class-validator DTO** (the same
|
|
92
|
+
* `plainToInstance` + `validate` NestJS runs in controllers) — invalid input is rejected before any
|
|
93
|
+
* run is created. Needs the optional peers `class-validator` + `class-transformer`.
|
|
94
|
+
* `@Workflow({ inputSchema: CheckoutInput })`.
|
|
95
|
+
*/
|
|
96
|
+
inputSchema?: new (...args: any[]) => object;
|
|
97
|
+
/**
|
|
98
|
+
* Custom input validator (throws on invalid) — an escape hatch for zod/yup/etc. instead of
|
|
99
|
+
* `inputSchema`. Takes precedence over `inputSchema` if both are set.
|
|
100
|
+
*/
|
|
101
|
+
validateInput?: (input: unknown) => void | Promise<void>;
|
|
102
|
+
/**
|
|
103
|
+
* Start a fresh run of this workflow whenever any of these events is published via
|
|
104
|
+
* `publishEvent(name, payload)` — the payload becomes the run's input. e.g.
|
|
105
|
+
* `onEvent: ['user.registered', 'user.invited']`. The same subscription can also be declared with
|
|
106
|
+
* the `@OnEvent(...)` class decorator; the two are merged.
|
|
107
|
+
*/
|
|
108
|
+
onEvent?: string[];
|
|
109
|
+
/**
|
|
110
|
+
* Coalesce `onEvent` triggers by **debouncing** — start one run only once events have been quiet
|
|
111
|
+
* for this long (resets on each event), with the LAST payload. e.g. `debounce: '30s'`.
|
|
112
|
+
*/
|
|
113
|
+
debounce?: string | number;
|
|
114
|
+
/**
|
|
115
|
+
* Coalesce `onEvent` triggers by **batching** — start one run with all payloads (`{ events: [...] }`)
|
|
116
|
+
* once `maxSize` is reached or `within` elapses from the first event. e.g.
|
|
117
|
+
* `batch: { maxSize: 100, within: '10s' }`.
|
|
118
|
+
*/
|
|
119
|
+
batch?: {
|
|
120
|
+
maxSize: number;
|
|
121
|
+
within: string | number;
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Marks a provider class as a durable workflow. Its `run(ctx, input)` method becomes the
|
|
126
|
+
* workflow function the engine executes and replays.
|
|
127
|
+
*/
|
|
128
|
+
declare function Workflow(options: WorkflowOptions): ClassDecorator;
|
|
129
|
+
declare function getWorkflowMeta(target: Function): WorkflowMeta | undefined;
|
|
130
|
+
declare const DURABLE_STEP_METADATA: unique symbol;
|
|
131
|
+
interface DurableStepMeta {
|
|
132
|
+
name: string;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Marks a provider method as the handler for a remote step `name`. An in-process transport
|
|
136
|
+
* (e.g. the event-emitter transport) routes dispatched tasks to it. The method's single
|
|
137
|
+
* argument is the step input; its return value is the step output.
|
|
138
|
+
*/
|
|
139
|
+
declare function DurableStep(name: string): MethodDecorator;
|
|
140
|
+
declare function getDurableStepMeta(method: Function): DurableStepMeta | undefined;
|
|
141
|
+
declare const DEAD_LETTER_METADATA: unique symbol;
|
|
142
|
+
/**
|
|
143
|
+
* The payload a dead-letter handler receives: the dead run's id, its workflow, the input it was
|
|
144
|
+
* started with (typed via `TInput`), and the failure that killed it.
|
|
145
|
+
*/
|
|
146
|
+
interface DeadLetter<TInput = unknown> {
|
|
147
|
+
/** Id of the run that was dead-lettered (inspectable + retriable in the dashboard). */
|
|
148
|
+
deadRunId: string;
|
|
149
|
+
/** Name of the workflow whose run died. */
|
|
150
|
+
workflow: string;
|
|
151
|
+
/** The original input the dead run was started with. */
|
|
152
|
+
input: TInput;
|
|
153
|
+
/** The structured error that moved the run to `dead`, when known. */
|
|
154
|
+
error?: StepError;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Marks a method on a `@Workflow` class as that workflow's **inline dead-letter handler**. When a
|
|
158
|
+
* run of the workflow is moved to `dead` (exceeded `maxRecoveryAttempts`), this method runs — as a
|
|
159
|
+
* durable workflow itself, auto-registered as `<workflow>.dlq` with a `dlq:<runId>` id — receiving a
|
|
160
|
+
* {@link DeadLetter} payload. It shares the class's injected dependencies, so the handler lives in
|
|
161
|
+
* the same file as the workflow it protects.
|
|
162
|
+
*
|
|
163
|
+
* Takes precedence over `@Workflow({ deadLetterWorkflow })` and the module-level `deadLetterWorkflow`
|
|
164
|
+
* default. The method signature is `(ctx, dead)` — the same `ctx` a workflow `run` gets.
|
|
165
|
+
*/
|
|
166
|
+
declare function DeadLetter(): MethodDecorator;
|
|
167
|
+
declare function isDeadLetterHandler(method: Function): boolean;
|
|
168
|
+
declare const ON_EVENT_METADATA: unique symbol;
|
|
169
|
+
/**
|
|
170
|
+
* Subscribe a `@Workflow` class to one or more events: when any of them is published via
|
|
171
|
+
* `publishEvent(name, payload)`, a fresh run of the workflow starts with the payload as input.
|
|
172
|
+
* Equivalent to `@Workflow({ onEvent })` — use whichever reads better; multiple `@OnEvent(...)`
|
|
173
|
+
* decorators and the option are all merged.
|
|
174
|
+
*/
|
|
175
|
+
declare function OnEvent(...events: string[]): ClassDecorator;
|
|
176
|
+
/** All events a workflow class subscribes to — the union of `@Workflow({ onEvent })` and `@OnEvent`. */
|
|
177
|
+
declare function getOnEvents(meta: WorkflowMeta, target: object): string[];
|
|
178
|
+
|
|
179
|
+
interface DurableModuleOptions {
|
|
180
|
+
store: StateStore;
|
|
181
|
+
transport?: Transport;
|
|
182
|
+
/**
|
|
183
|
+
* An ordered pool of named transports for failover / multi-broker setups. The engine dispatches on
|
|
184
|
+
* the first and fails over to the next; a step pins one via `ctx.call(step, input, { transport })`.
|
|
185
|
+
* Use instead of `transport`.
|
|
186
|
+
*/
|
|
187
|
+
transports?: NamedTransport[];
|
|
188
|
+
/**
|
|
189
|
+
* Cross-instance broadcast pub/sub (lifecycle events + cancellation). Defaults to the (first)
|
|
190
|
+
* transport when it can broadcast (event-emitter, BullMQ); set explicitly to use a dedicated one.
|
|
191
|
+
*/
|
|
192
|
+
controlPlane?: ControlPlane;
|
|
193
|
+
/** Interval (ms) for the durable-timer poller. `0` disables it. Defaults to 1000. */
|
|
194
|
+
timerPollMs?: number;
|
|
195
|
+
/**
|
|
196
|
+
* Auto-create the durable tables on boot via `store.ensureSchema()`. Defaults to true. Turn
|
|
197
|
+
* off in production and call the store adapter's `ensure*DurableSchema()` from a migration.
|
|
198
|
+
*/
|
|
199
|
+
autoSchema?: boolean;
|
|
200
|
+
/**
|
|
201
|
+
* Multi-instance recovery lease, in ms — how long an instance owns a run it picked up before
|
|
202
|
+
* another may take over. Defaults to 30000. Set above your longest synchronous run.
|
|
203
|
+
*/
|
|
204
|
+
leaseMs?: number;
|
|
205
|
+
/** Unique id for this instance (for leases). Defaults to a random id. */
|
|
206
|
+
instanceId?: string;
|
|
207
|
+
/**
|
|
208
|
+
* Cap recovery attempts before a still-`running` run is moved to the `dead` dead-letter state
|
|
209
|
+
* (a poison pill that crashes the process every boot). Omit for unlimited.
|
|
210
|
+
*/
|
|
211
|
+
maxRecoveryAttempts?: number;
|
|
212
|
+
/**
|
|
213
|
+
* The **default** workflow to route dead-lettered runs to, for workflows that don't declare their
|
|
214
|
+
* own. When a run is moved to `dead` (exceeded `maxRecoveryAttempts`), the started handler gets a
|
|
215
|
+
* `DeadLetter` payload `{ deadRunId, workflow, input, error }` (idempotent by a `dlq:<runId>` id) —
|
|
216
|
+
* it can alert, compensate, or queue for review. Resolution per dead run: the workflow's inline
|
|
217
|
+
* `@DeadLetter()` method → its `@Workflow({ deadLetterWorkflow })` reference → this default. Omit
|
|
218
|
+
* everything to just leave dead runs parked (inspectable + retriable from the dashboard). Accepts a
|
|
219
|
+
* workflow class (refactor-safe) or a name (cross-runtime).
|
|
220
|
+
*/
|
|
221
|
+
deadLetterWorkflow?: WorkflowRef;
|
|
222
|
+
/**
|
|
223
|
+
* Whether this instance plays the **worker** role: register `@DurableStep` handlers (consume the
|
|
224
|
+
* transport), recover incomplete runs on boot, and poll due timers. Defaults to `true`. Set
|
|
225
|
+
* `false` for a **dashboard/dispatch-only** instance (e.g. an API pod) that mounts the control
|
|
226
|
+
* plane and reads the store but must not process or recover workflows — leave that to the workers.
|
|
227
|
+
*/
|
|
228
|
+
worker?: boolean;
|
|
229
|
+
/** Max ms to wait for in-flight runs on shutdown before exiting. Defaults to 10000. */
|
|
230
|
+
shutdownTimeoutMs?: number;
|
|
231
|
+
/**
|
|
232
|
+
* Recurring workflows to start on a schedule (fixed interval or cron). The timer poller fires
|
|
233
|
+
* them each tick on **worker** instances only; `engine.start` is idempotent by the schedule's
|
|
234
|
+
* time-bucket run id, so racing instances start each window exactly once. Cron schedules need the
|
|
235
|
+
* optional `cron-parser` peer dependency.
|
|
236
|
+
*/
|
|
237
|
+
schedules?: ScheduledWorkflow[];
|
|
238
|
+
/**
|
|
239
|
+
* Build the public callback URL for a `ctx.webhook()` token, e.g.
|
|
240
|
+
* ``(t) => `https://api.example.com/durable/api/webhooks/${t}` ``. Populates `DurableWebhook.url`
|
|
241
|
+
* so a step can hand the URL to a third party. The dashboard's `POST webhooks/:token` receives the
|
|
242
|
+
* callback. Omit to build URLs yourself from the token.
|
|
243
|
+
*/
|
|
244
|
+
webhookUrl?: (token: string) => string;
|
|
245
|
+
/**
|
|
246
|
+
* Flow-control queues for remote steps, registered on the engine at startup. Reference one from a
|
|
247
|
+
* workflow with `ctx.call(step, input, { queue: name })` to cap its concurrency / admission rate.
|
|
248
|
+
*/
|
|
249
|
+
queues?: QueueConfig[];
|
|
250
|
+
/**
|
|
251
|
+
* Provide the current W3C `traceparent` to stamp on dispatched remote tasks, so workers continue
|
|
252
|
+
* the distributed trace. Pass `otelTraceparent` from `@dudousxd/nestjs-durable-otel`.
|
|
253
|
+
*/
|
|
254
|
+
traceparent?: () => string | undefined;
|
|
255
|
+
/**
|
|
256
|
+
* Provide an opaque context carrier (tenant / user / correlation ids) to stamp on dispatched remote
|
|
257
|
+
* tasks, so workers re-expose it to the step handler alongside the `traceparent`. The engine never
|
|
258
|
+
* inspects its shape.
|
|
259
|
+
*
|
|
260
|
+
* **Auto-feed**: if you omit this AND `@dudousxd/nestjs-context` is installed (its accessor is bound
|
|
261
|
+
* to the shared `CONTEXT_ACCESSOR` token), DurableModule defaults this to a reader that builds
|
|
262
|
+
* `{ traceId, tenantId, userRef }` from the accessor — so a workflow dispatched within a request
|
|
263
|
+
* automatically carries the originating context across process boundaries. Pass your own reader to
|
|
264
|
+
* override the auto-feed; with neither, the carrier is omitted (unchanged behavior).
|
|
265
|
+
*
|
|
266
|
+
* Re-evaluated at each (re)dispatch — including a retry or a crash/scale-down resume that the engine
|
|
267
|
+
* drives OUTSIDE the originating request scope, where this reader may return empty or stale values.
|
|
268
|
+
* Treat the carrier as best-effort correlation/propagation metadata only — do NOT treat it as an
|
|
269
|
+
* authorization boundary.
|
|
270
|
+
*/
|
|
271
|
+
context?: () => Record<string, unknown> | undefined;
|
|
272
|
+
/** Attempts for each saga compensation when a run fails. Default 1 (no retry). Idempotent undos. */
|
|
273
|
+
compensationRetries?: number;
|
|
274
|
+
}
|
|
275
|
+
interface DurableModuleAsyncOptions {
|
|
276
|
+
useFactory: (...args: never[]) => DurableModuleOptions | Promise<DurableModuleOptions>;
|
|
277
|
+
inject?: InjectionToken[];
|
|
278
|
+
}
|
|
279
|
+
declare class DurableModule {
|
|
280
|
+
static forRoot(options: DurableModuleOptions): DynamicModule;
|
|
281
|
+
static forRootAsync(options: DurableModuleAsyncOptions): DynamicModule;
|
|
282
|
+
private static build;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
declare const ENTITY_METADATA: unique symbol;
|
|
286
|
+
declare const ENTITY_ON_METADATA: unique symbol;
|
|
287
|
+
/**
|
|
288
|
+
* Marks an `@Injectable()` class as a **durable entity** (a virtual object): its `@On(op)` methods run
|
|
289
|
+
* serialized per key over the instance's fields as durable state. e.g.
|
|
290
|
+
*
|
|
291
|
+
* ```ts
|
|
292
|
+
* @Entity({ name: 'cart' }) @Injectable()
|
|
293
|
+
* class Cart { items: Item[] = []; @On('add') add(i: Item) { this.items.push(i); } @On('list') list() { return this.items; } }
|
|
294
|
+
* ```
|
|
295
|
+
*
|
|
296
|
+
* The class must be **constructible with no arguments** (a fresh instance is the initial state per key)
|
|
297
|
+
* — keep entities pure state, no DI. Drive them with `EntityService` or `ctx.signalEntity`/`callEntity`.
|
|
298
|
+
*/
|
|
299
|
+
declare function Entity(options: {
|
|
300
|
+
name: string;
|
|
301
|
+
}): ClassDecorator;
|
|
302
|
+
/** Marks an entity method as the handler for operation `op`. */
|
|
303
|
+
declare function On(op: string): MethodDecorator;
|
|
304
|
+
declare function getEntityMeta(target: Function): {
|
|
305
|
+
name: string;
|
|
306
|
+
} | undefined;
|
|
307
|
+
/**
|
|
308
|
+
* Build the engine `EntityConfig` for a discovered `@Entity` class: a fresh instance per key, and
|
|
309
|
+
* handlers that rehydrate the class prototype onto the (serialized) state before dispatching the op,
|
|
310
|
+
* so methods work after replay.
|
|
311
|
+
*/
|
|
312
|
+
declare function entityConfigFor(ctor: Function): {
|
|
313
|
+
initialState: () => object;
|
|
314
|
+
handlers: Record<string, EntityHandler>;
|
|
315
|
+
};
|
|
316
|
+
/** Inject this to drive durable entities from outside a workflow. */
|
|
317
|
+
declare class EntityService {
|
|
318
|
+
private readonly engine;
|
|
319
|
+
constructor(engine: WorkflowEngine);
|
|
320
|
+
/** Send an operation to an entity (fire-and-forget; ordered + exactly-once per key). */
|
|
321
|
+
signal(name: string, key: string, op: string, arg?: unknown): Promise<void>;
|
|
322
|
+
/** Read an entity's current durable state (or undefined if it has none yet). */
|
|
323
|
+
getState<S = unknown>(name: string, key: string): Promise<S | undefined>;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
declare const STEP_INTERCEPTOR_METADATA: unique symbol;
|
|
327
|
+
/**
|
|
328
|
+
* The shape a `@StepInterceptor()` provider must implement: `intercept(invocation, next)` wraps the
|
|
329
|
+
* real execution of every local `ctx.step` (call `next()` to run the step body / next interceptor,
|
|
330
|
+
* and return — or transform — its result). The engine-level {@link StepInterceptor} primitive, with
|
|
331
|
+
* NestJS dependency injection.
|
|
332
|
+
*/
|
|
333
|
+
interface DurableStepInterceptor {
|
|
334
|
+
intercept(invocation: StepInvocation, next: () => Promise<unknown>): Promise<unknown>;
|
|
335
|
+
}
|
|
336
|
+
/**
|
|
337
|
+
* Marks an `@Injectable()` class as a durable step interceptor. The module discovers it on boot and
|
|
338
|
+
* registers its `intercept` method with the engine (so it can inject loggers/tracers/etc.). First
|
|
339
|
+
* declared is outermost. Interceptors fire only when a step actually executes, never on replay.
|
|
340
|
+
*/
|
|
341
|
+
declare function StepInterceptor(): ClassDecorator;
|
|
342
|
+
declare function isStepInterceptor(target: Function): boolean;
|
|
343
|
+
|
|
344
|
+
/**
|
|
345
|
+
* Cross-lib injection token for the current-request context accessor, owned by
|
|
346
|
+
* `@dudousxd/nestjs-context`. We do NOT import nestjs-context (it is an OPTIONAL
|
|
347
|
+
* peer dependency) — instead we share its well-known token by value so DI
|
|
348
|
+
* resolves the same provider when nestjs-context is installed and present.
|
|
349
|
+
*
|
|
350
|
+
* `Symbol.for(key)` uses the global symbol registry, so this resolves to the
|
|
351
|
+
* SAME symbol instance as nestjs-context's `tokens.ts` (and the identical token
|
|
352
|
+
* declared by `@dudousxd/nestjs-authz`) without any import. The key MUST stay
|
|
353
|
+
* byte-identical with nestjs-context's export.
|
|
354
|
+
*/
|
|
355
|
+
declare const CONTEXT_ACCESSOR: unique symbol;
|
|
356
|
+
|
|
357
|
+
/** Public entry point for starting and resuming workflow runs. */
|
|
358
|
+
declare class WorkflowService {
|
|
359
|
+
private readonly engine;
|
|
360
|
+
constructor(engine: WorkflowEngine);
|
|
361
|
+
/**
|
|
362
|
+
* Enqueue a workflow run — it creates the run (`pending`) and returns `{ runId, status: 'pending' }`
|
|
363
|
+
* immediately; a worker executes the body (so the caller never blocks on workflow logic). Use
|
|
364
|
+
* {@link waitForRun} when you need the outcome. Pass the workflow's **class**
|
|
365
|
+
* (`start(CheckoutWorkflow, input)`) for a typed input + refactor-safety, or a **name** string for a
|
|
366
|
+
* cross-runtime workflow. `runId` defaults to a random id; pass your own to make the start idempotent
|
|
367
|
+
* (a redelivery returns the existing run). `opts.tags` are merged with the workflow's static
|
|
368
|
+
* `@Workflow({ tags })`; `opts.searchAttributes` stamp typed, queryable run data.
|
|
369
|
+
*/
|
|
370
|
+
start<C extends WorkflowClass>(workflow: C, input: WorkflowInputOf<C>, runId?: string, opts?: StartOptions): Promise<RunResult>;
|
|
371
|
+
start(workflow: string, input: unknown, runId?: string, opts?: StartOptions): Promise<RunResult>;
|
|
372
|
+
resume(runId: string): Promise<RunResult>;
|
|
373
|
+
/**
|
|
374
|
+
* Resolve once a run settles — terminal (completed/failed/cancelled/dead) or suspended. `start`
|
|
375
|
+
* only enqueues (a worker runs the body), so pair them when a request needs the outcome:
|
|
376
|
+
* `const { runId } = await svc.start(...); const result = await svc.waitForRun(runId)`.
|
|
377
|
+
*/
|
|
378
|
+
waitForRun(runId: string, opts?: {
|
|
379
|
+
timeoutMs?: number;
|
|
380
|
+
}): Promise<RunResult>;
|
|
381
|
+
/** Deliver an external signal (e.g. from a webhook) to the run waiting on `token`. */
|
|
382
|
+
signal(token: string, payload: unknown): Promise<RunResult | null>;
|
|
383
|
+
/**
|
|
384
|
+
* Ensure a run exists for `runId`, then deliver a signal to it — race-free (the signal is buffered
|
|
385
|
+
* until the run reaches its `waitForSignal`). The durable-entity / accumulator pattern: one
|
|
386
|
+
* long-lived run per key fed events by many calls. See {@link WorkflowEngine.signalWithStart}.
|
|
387
|
+
*/
|
|
388
|
+
signalWithStart<C extends WorkflowClass>(workflow: C, input: WorkflowInputOf<C>, runId: string, signal: {
|
|
389
|
+
token: string;
|
|
390
|
+
payload?: unknown;
|
|
391
|
+
}, opts?: StartOptions): Promise<{
|
|
392
|
+
runId: string;
|
|
393
|
+
}>;
|
|
394
|
+
signalWithStart(workflow: string, input: unknown, runId: string, signal: {
|
|
395
|
+
token: string;
|
|
396
|
+
payload?: unknown;
|
|
397
|
+
}, opts?: StartOptions): Promise<{
|
|
398
|
+
runId: string;
|
|
399
|
+
}>;
|
|
400
|
+
/**
|
|
401
|
+
* Publish a named event. Resumes runs waiting on it via `ctx.waitForEvent(name, { match })` and
|
|
402
|
+
* starts a fresh run of every workflow subscribed via `@Workflow({ onEvent })` / `@OnEvent` (the
|
|
403
|
+
* payload becomes its input). Pass `opts.id` to dedupe redeliveries. Returns how many runs it
|
|
404
|
+
* touched (resumed + started).
|
|
405
|
+
*/
|
|
406
|
+
publishEvent(name: string, payload: unknown, opts?: {
|
|
407
|
+
id?: string;
|
|
408
|
+
}): Promise<number>;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
export { CONTEXT_ACCESSOR, type ContextAccessor, type ContextStore, DEAD_LETTER_METADATA, DURABLE_STEP_METADATA, DeadLetter, DurableModule, type DurableModuleAsyncOptions, type DurableModuleOptions, DurableStep, type DurableStepInterceptor, type DurableStepMeta, ENTITY_METADATA, ENTITY_ON_METADATA, Entity, EntityService, ON_EVENT_METADATA, On, OnEvent, STEP_INTERCEPTOR_METADATA, StepInterceptor, type UserRef, WORKFLOW_METADATA, Workflow, type WorkflowMeta, type WorkflowOptions, WorkflowService, entityConfigFor, getDurableStepMeta, getEntityMeta, getOnEvents, getWorkflowMeta, isDeadLetterHandler, isStepInterceptor };
|