@dudousxd/nestjs-durable 0.22.1 → 0.24.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
@@ -1,6 +1,6 @@
1
- import { StepError, WorkflowRef, SingletonConfig, StateStore, Transport, NamedTransport, ControlPlane, ScheduledWorkflow, RetentionPolicy, QueueConfig, AdmissionBackend, WorkflowEngine, EntityHandler, StepInvocation, WorkflowClass, WorkflowInputOf, StartOptions, RunResult } from '@dudousxd/nestjs-durable-core';
1
+ import { StepError, WorkflowRef, SingletonConfig, WorkflowExecutor, StateStore, Transport, NamedTransport, ControlPlane, ScheduledWorkflow, RetentionPolicy, QueueConfig, AdmissionBackend, WorkflowEngine, EntityHandler, StepInvocation, WorkflowClass, WorkflowInputOf, StartOptions, RunResult } from '@dudousxd/nestjs-durable-core';
2
2
  import { RunRedisWorkerOptions, RunningWorker, DurableWorkerRuntime } from '@dudousxd/durable-worker';
3
- import { DynamicModule, InjectionToken, OnModuleInit, OnApplicationBootstrap, OnApplicationShutdown } from '@nestjs/common';
3
+ import { DynamicModule, InjectionToken, OnModuleInit, OnApplicationBootstrap, OnApplicationShutdown, Provider } from '@nestjs/common';
4
4
  import { DiscoveryService, MetadataScanner } from '@nestjs/core';
5
5
 
6
6
  /**
@@ -268,6 +268,73 @@ declare class DurableWorkerModule {
268
268
  private static build;
269
269
  }
270
270
 
271
+ /**
272
+ * Opt-in config for an **in-app worker**: the same NestJS process runs the engine AND serves its own
273
+ * discovered `@Workflow`/`@DurableStep` on one default `group`. The engine registers each `@Workflow`
274
+ * GROUP-SERVED (its turns are dispatched to `group` over the transport via a {@link RemoteWorkflowExecutor}
275
+ * instead of run inline), and a co-located {@link DurableWorkerRuntime} consumes `group` and replays the
276
+ * very same TS bodies. This is the uniform-dispatch "one app, both roles" shape — every turn pays a
277
+ * transport round-trip even though the worker is the same process. Requires a transport that carries
278
+ * workflow tasks (BullMQ); an in-process-only transport cannot dispatch a {@link WorkflowExecutor}.
279
+ */
280
+ interface DurableInAppWorkerOptions {
281
+ /** The default group this app dispatches its `@Workflow` turns to AND consumes as a worker. */
282
+ group: string;
283
+ /** ioredis connection (string or options) for the co-located worker consumer (`runRedisWorker`). */
284
+ connection: string | Record<string, unknown>;
285
+ /** Key prefix namespacing the durable queues. Defaults to `durable` (matches the transport). */
286
+ prefix?: string;
287
+ /** Stable id for this worker process in heartbeats/control. Defaults to a per-host/pid id. */
288
+ instanceId?: string;
289
+ }
290
+ /** The resolved {@link DurableInAppWorkerOptions} or `null` when the app didn't opt in. */
291
+ declare const IN_APP_WORKER_OPTIONS: unique symbol;
292
+ /**
293
+ * The group-served binding the {@link import('./workflow.registrar').WorkflowRegistrar} applies to every
294
+ * discovered `@Workflow`: `{ group, executor }` when the app opted into an in-app worker, else `null`
295
+ * (workflows register inline — the unchanged default). The executor is a {@link RemoteWorkflowExecutor}
296
+ * over the engine's own transport, so a group-served turn is dispatched to `group` and the co-located
297
+ * worker (below) advances it.
298
+ */
299
+ declare const IN_APP_WORKER_BINDING: unique symbol;
300
+ /** The co-located worker's {@link DurableWorkerRuntime} (the consumer half). */
301
+ declare const IN_APP_WORKER_RUNTIME: unique symbol;
302
+ /** `runRedisWorker`, injected so tests can substitute a fake (no real Redis). Defaults to the real one. */
303
+ declare const IN_APP_RUN_REDIS_WORKER: unique symbol;
304
+ /** Started {@link RunningWorker} handles for the in-app group(s), closed on shutdown. */
305
+ declare const IN_APP_WORKER_RUNNERS: unique symbol;
306
+ /** The group-served binding shape resolved behind {@link IN_APP_WORKER_BINDING}. */
307
+ interface InAppWorkerBinding {
308
+ group: string;
309
+ executor: WorkflowExecutor;
310
+ }
311
+ /**
312
+ * The consumer half of the in-app worker: on init it registers every discovered `@Workflow`/`@DurableStep`
313
+ * on a {@link DurableWorkerRuntime} (the SAME bodies the engine registered group-served), and on bootstrap
314
+ * it starts one `runRedisWorker` consumer on the configured group, closing it on shutdown. A no-op when
315
+ * the app didn't opt in. Mirrors the thin {@link import('./durable-worker.module').DurableWorkerModule},
316
+ * but co-located with a full engine.
317
+ */
318
+ declare class InAppWorkerBootstrap implements OnModuleInit, OnApplicationBootstrap, OnApplicationShutdown {
319
+ private readonly discovery;
320
+ private readonly metadataScanner;
321
+ private readonly options;
322
+ private readonly runtime;
323
+ private readonly runRedisWorker;
324
+ private readonly runnersSink;
325
+ private readonly runners;
326
+ constructor(discovery: DiscoveryService, metadataScanner: MetadataScanner, options: DurableInAppWorkerOptions | null, runtime: DurableWorkerRuntime, runRedisWorker: RunRedisWorkerFn, runnersSink: RunningWorker[]);
327
+ onModuleInit(): void;
328
+ onApplicationBootstrap(): Promise<void>;
329
+ onApplicationShutdown(): Promise<void>;
330
+ }
331
+ /**
332
+ * The providers that stand up an in-app worker, added to {@link import('./durable.module').DurableModule}.
333
+ * All are inert when `inAppWorker` is unset (the binding resolves to `null`, the bootstrap no-ops), so a
334
+ * plain `DurableModule` is byte-for-byte unchanged.
335
+ */
336
+ declare function inAppWorkerProviders(): Provider[];
337
+
271
338
  /**
272
339
  * Retention config for the {@link RetentionPoller}. One or more {@link RetentionPolicy policies}
273
340
  * (status sets must be disjoint — validated at boot), swept together on a shared interval.
@@ -315,6 +382,12 @@ interface DurableModuleOptions {
315
382
  * off in production and call the store adapter's `ensure*DurableSchema()` from a migration.
316
383
  */
317
384
  autoSchema?: boolean;
385
+ /**
386
+ * Worker-pool partition for this instance (forwarded to the engine). Default `'default'`. Set a
387
+ * distinct value to share ONE state store across non-interchangeable pools — e.g. a developer's
388
+ * local instance vs the deployed cluster. See `WorkflowEngineDeps.namespace`.
389
+ */
390
+ namespace?: string;
318
391
  /**
319
392
  * Multi-instance recovery lease, in ms — how long an instance owns a run it picked up before
320
393
  * another may take over. Defaults to 30000. Set above your longest synchronous run.
@@ -411,6 +484,15 @@ interface DurableModuleOptions {
411
484
  context?: () => Record<string, unknown> | undefined;
412
485
  /** Attempts for each saga compensation when a run fails. Default 1 (no retry). Idempotent undos. */
413
486
  compensationRetries?: number;
487
+ /**
488
+ * Opt into an **in-app worker** (uniform dispatch): the same process runs the engine AND serves its
489
+ * own discovered `@Workflow`/`@DurableStep` on one default `group`. Each `@Workflow` is registered
490
+ * GROUP-SERVED — its turns are dispatched to `group` over the transport and replayed by a co-located
491
+ * worker consumer — instead of run inline. Requires a workflow-task transport (BullMQ). Omit (the
492
+ * default) to keep every `@Workflow` on the inline fast path with zero dispatch round-trips. See
493
+ * {@link DurableInAppWorkerOptions}.
494
+ */
495
+ inAppWorker?: DurableInAppWorkerOptions;
414
496
  }
415
497
  interface DurableModuleAsyncOptions {
416
498
  useFactory: (...args: never[]) => DurableModuleOptions | Promise<DurableModuleOptions>;
@@ -548,4 +630,4 @@ declare class WorkflowService {
548
630
  }): Promise<number>;
549
631
  }
550
632
 
551
- export { CONTEXT_ACCESSOR, type ContextAccessor, type ContextStore, DEAD_LETTER_METADATA, DURABLE_STEP_METADATA, DURABLE_WORKER_OPTIONS, DURABLE_WORKER_RUNNERS, DeadLetter, DurableModule, type DurableModuleAsyncOptions, type DurableModuleOptions, type DurableRetentionOptions, DurableStep, type DurableStepInterceptor, type DurableStepMeta, DurableWorkerModule, type DurableWorkerModuleAsyncOptions, type DurableWorkerModuleOptions, ENTITY_METADATA, ENTITY_ON_METADATA, Entity, EntityService, ON_EVENT_METADATA, On, OnEvent, RUN_REDIS_WORKER, type RunRedisWorkerFn, STEP_INTERCEPTOR_METADATA, StepInterceptor, ThinStepRegistrar, ThinWorkerBootstrap, ThinWorkflowRegistrar, type UserRef, WORKFLOW_METADATA, Workflow, type WorkflowMeta, type WorkflowOptions, WorkflowService, entityConfigFor, getDurableStepMeta, getEntityMeta, getOnEvents, getWorkflowMeta, isDeadLetterHandler, isStepInterceptor };
633
+ export { CONTEXT_ACCESSOR, type ContextAccessor, type ContextStore, DEAD_LETTER_METADATA, DURABLE_STEP_METADATA, DURABLE_WORKER_OPTIONS, DURABLE_WORKER_RUNNERS, DeadLetter, type DurableInAppWorkerOptions, DurableModule, type DurableModuleAsyncOptions, type DurableModuleOptions, type DurableRetentionOptions, DurableStep, type DurableStepInterceptor, type DurableStepMeta, DurableWorkerModule, type DurableWorkerModuleAsyncOptions, type DurableWorkerModuleOptions, ENTITY_METADATA, ENTITY_ON_METADATA, Entity, EntityService, IN_APP_RUN_REDIS_WORKER, IN_APP_WORKER_BINDING, IN_APP_WORKER_OPTIONS, IN_APP_WORKER_RUNNERS, IN_APP_WORKER_RUNTIME, type InAppWorkerBinding, InAppWorkerBootstrap, ON_EVENT_METADATA, On, OnEvent, RUN_REDIS_WORKER, type RunRedisWorkerFn, STEP_INTERCEPTOR_METADATA, StepInterceptor, ThinStepRegistrar, ThinWorkerBootstrap, ThinWorkflowRegistrar, type UserRef, WORKFLOW_METADATA, Workflow, type WorkflowMeta, type WorkflowOptions, WorkflowService, entityConfigFor, getDurableStepMeta, getEntityMeta, getOnEvents, getWorkflowMeta, inAppWorkerProviders, isDeadLetterHandler, isStepInterceptor };
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- import { StepError, WorkflowRef, SingletonConfig, StateStore, Transport, NamedTransport, ControlPlane, ScheduledWorkflow, RetentionPolicy, QueueConfig, AdmissionBackend, WorkflowEngine, EntityHandler, StepInvocation, WorkflowClass, WorkflowInputOf, StartOptions, RunResult } from '@dudousxd/nestjs-durable-core';
1
+ import { StepError, WorkflowRef, SingletonConfig, WorkflowExecutor, StateStore, Transport, NamedTransport, ControlPlane, ScheduledWorkflow, RetentionPolicy, QueueConfig, AdmissionBackend, WorkflowEngine, EntityHandler, StepInvocation, WorkflowClass, WorkflowInputOf, StartOptions, RunResult } from '@dudousxd/nestjs-durable-core';
2
2
  import { RunRedisWorkerOptions, RunningWorker, DurableWorkerRuntime } from '@dudousxd/durable-worker';
3
- import { DynamicModule, InjectionToken, OnModuleInit, OnApplicationBootstrap, OnApplicationShutdown } from '@nestjs/common';
3
+ import { DynamicModule, InjectionToken, OnModuleInit, OnApplicationBootstrap, OnApplicationShutdown, Provider } from '@nestjs/common';
4
4
  import { DiscoveryService, MetadataScanner } from '@nestjs/core';
5
5
 
6
6
  /**
@@ -268,6 +268,73 @@ declare class DurableWorkerModule {
268
268
  private static build;
269
269
  }
270
270
 
271
+ /**
272
+ * Opt-in config for an **in-app worker**: the same NestJS process runs the engine AND serves its own
273
+ * discovered `@Workflow`/`@DurableStep` on one default `group`. The engine registers each `@Workflow`
274
+ * GROUP-SERVED (its turns are dispatched to `group` over the transport via a {@link RemoteWorkflowExecutor}
275
+ * instead of run inline), and a co-located {@link DurableWorkerRuntime} consumes `group` and replays the
276
+ * very same TS bodies. This is the uniform-dispatch "one app, both roles" shape — every turn pays a
277
+ * transport round-trip even though the worker is the same process. Requires a transport that carries
278
+ * workflow tasks (BullMQ); an in-process-only transport cannot dispatch a {@link WorkflowExecutor}.
279
+ */
280
+ interface DurableInAppWorkerOptions {
281
+ /** The default group this app dispatches its `@Workflow` turns to AND consumes as a worker. */
282
+ group: string;
283
+ /** ioredis connection (string or options) for the co-located worker consumer (`runRedisWorker`). */
284
+ connection: string | Record<string, unknown>;
285
+ /** Key prefix namespacing the durable queues. Defaults to `durable` (matches the transport). */
286
+ prefix?: string;
287
+ /** Stable id for this worker process in heartbeats/control. Defaults to a per-host/pid id. */
288
+ instanceId?: string;
289
+ }
290
+ /** The resolved {@link DurableInAppWorkerOptions} or `null` when the app didn't opt in. */
291
+ declare const IN_APP_WORKER_OPTIONS: unique symbol;
292
+ /**
293
+ * The group-served binding the {@link import('./workflow.registrar').WorkflowRegistrar} applies to every
294
+ * discovered `@Workflow`: `{ group, executor }` when the app opted into an in-app worker, else `null`
295
+ * (workflows register inline — the unchanged default). The executor is a {@link RemoteWorkflowExecutor}
296
+ * over the engine's own transport, so a group-served turn is dispatched to `group` and the co-located
297
+ * worker (below) advances it.
298
+ */
299
+ declare const IN_APP_WORKER_BINDING: unique symbol;
300
+ /** The co-located worker's {@link DurableWorkerRuntime} (the consumer half). */
301
+ declare const IN_APP_WORKER_RUNTIME: unique symbol;
302
+ /** `runRedisWorker`, injected so tests can substitute a fake (no real Redis). Defaults to the real one. */
303
+ declare const IN_APP_RUN_REDIS_WORKER: unique symbol;
304
+ /** Started {@link RunningWorker} handles for the in-app group(s), closed on shutdown. */
305
+ declare const IN_APP_WORKER_RUNNERS: unique symbol;
306
+ /** The group-served binding shape resolved behind {@link IN_APP_WORKER_BINDING}. */
307
+ interface InAppWorkerBinding {
308
+ group: string;
309
+ executor: WorkflowExecutor;
310
+ }
311
+ /**
312
+ * The consumer half of the in-app worker: on init it registers every discovered `@Workflow`/`@DurableStep`
313
+ * on a {@link DurableWorkerRuntime} (the SAME bodies the engine registered group-served), and on bootstrap
314
+ * it starts one `runRedisWorker` consumer on the configured group, closing it on shutdown. A no-op when
315
+ * the app didn't opt in. Mirrors the thin {@link import('./durable-worker.module').DurableWorkerModule},
316
+ * but co-located with a full engine.
317
+ */
318
+ declare class InAppWorkerBootstrap implements OnModuleInit, OnApplicationBootstrap, OnApplicationShutdown {
319
+ private readonly discovery;
320
+ private readonly metadataScanner;
321
+ private readonly options;
322
+ private readonly runtime;
323
+ private readonly runRedisWorker;
324
+ private readonly runnersSink;
325
+ private readonly runners;
326
+ constructor(discovery: DiscoveryService, metadataScanner: MetadataScanner, options: DurableInAppWorkerOptions | null, runtime: DurableWorkerRuntime, runRedisWorker: RunRedisWorkerFn, runnersSink: RunningWorker[]);
327
+ onModuleInit(): void;
328
+ onApplicationBootstrap(): Promise<void>;
329
+ onApplicationShutdown(): Promise<void>;
330
+ }
331
+ /**
332
+ * The providers that stand up an in-app worker, added to {@link import('./durable.module').DurableModule}.
333
+ * All are inert when `inAppWorker` is unset (the binding resolves to `null`, the bootstrap no-ops), so a
334
+ * plain `DurableModule` is byte-for-byte unchanged.
335
+ */
336
+ declare function inAppWorkerProviders(): Provider[];
337
+
271
338
  /**
272
339
  * Retention config for the {@link RetentionPoller}. One or more {@link RetentionPolicy policies}
273
340
  * (status sets must be disjoint — validated at boot), swept together on a shared interval.
@@ -315,6 +382,12 @@ interface DurableModuleOptions {
315
382
  * off in production and call the store adapter's `ensure*DurableSchema()` from a migration.
316
383
  */
317
384
  autoSchema?: boolean;
385
+ /**
386
+ * Worker-pool partition for this instance (forwarded to the engine). Default `'default'`. Set a
387
+ * distinct value to share ONE state store across non-interchangeable pools — e.g. a developer's
388
+ * local instance vs the deployed cluster. See `WorkflowEngineDeps.namespace`.
389
+ */
390
+ namespace?: string;
318
391
  /**
319
392
  * Multi-instance recovery lease, in ms — how long an instance owns a run it picked up before
320
393
  * another may take over. Defaults to 30000. Set above your longest synchronous run.
@@ -411,6 +484,15 @@ interface DurableModuleOptions {
411
484
  context?: () => Record<string, unknown> | undefined;
412
485
  /** Attempts for each saga compensation when a run fails. Default 1 (no retry). Idempotent undos. */
413
486
  compensationRetries?: number;
487
+ /**
488
+ * Opt into an **in-app worker** (uniform dispatch): the same process runs the engine AND serves its
489
+ * own discovered `@Workflow`/`@DurableStep` on one default `group`. Each `@Workflow` is registered
490
+ * GROUP-SERVED — its turns are dispatched to `group` over the transport and replayed by a co-located
491
+ * worker consumer — instead of run inline. Requires a workflow-task transport (BullMQ). Omit (the
492
+ * default) to keep every `@Workflow` on the inline fast path with zero dispatch round-trips. See
493
+ * {@link DurableInAppWorkerOptions}.
494
+ */
495
+ inAppWorker?: DurableInAppWorkerOptions;
414
496
  }
415
497
  interface DurableModuleAsyncOptions {
416
498
  useFactory: (...args: never[]) => DurableModuleOptions | Promise<DurableModuleOptions>;
@@ -548,4 +630,4 @@ declare class WorkflowService {
548
630
  }): Promise<number>;
549
631
  }
550
632
 
551
- export { CONTEXT_ACCESSOR, type ContextAccessor, type ContextStore, DEAD_LETTER_METADATA, DURABLE_STEP_METADATA, DURABLE_WORKER_OPTIONS, DURABLE_WORKER_RUNNERS, DeadLetter, DurableModule, type DurableModuleAsyncOptions, type DurableModuleOptions, type DurableRetentionOptions, DurableStep, type DurableStepInterceptor, type DurableStepMeta, DurableWorkerModule, type DurableWorkerModuleAsyncOptions, type DurableWorkerModuleOptions, ENTITY_METADATA, ENTITY_ON_METADATA, Entity, EntityService, ON_EVENT_METADATA, On, OnEvent, RUN_REDIS_WORKER, type RunRedisWorkerFn, STEP_INTERCEPTOR_METADATA, StepInterceptor, ThinStepRegistrar, ThinWorkerBootstrap, ThinWorkflowRegistrar, type UserRef, WORKFLOW_METADATA, Workflow, type WorkflowMeta, type WorkflowOptions, WorkflowService, entityConfigFor, getDurableStepMeta, getEntityMeta, getOnEvents, getWorkflowMeta, isDeadLetterHandler, isStepInterceptor };
633
+ export { CONTEXT_ACCESSOR, type ContextAccessor, type ContextStore, DEAD_LETTER_METADATA, DURABLE_STEP_METADATA, DURABLE_WORKER_OPTIONS, DURABLE_WORKER_RUNNERS, DeadLetter, type DurableInAppWorkerOptions, DurableModule, type DurableModuleAsyncOptions, type DurableModuleOptions, type DurableRetentionOptions, DurableStep, type DurableStepInterceptor, type DurableStepMeta, DurableWorkerModule, type DurableWorkerModuleAsyncOptions, type DurableWorkerModuleOptions, ENTITY_METADATA, ENTITY_ON_METADATA, Entity, EntityService, IN_APP_RUN_REDIS_WORKER, IN_APP_WORKER_BINDING, IN_APP_WORKER_OPTIONS, IN_APP_WORKER_RUNNERS, IN_APP_WORKER_RUNTIME, type InAppWorkerBinding, InAppWorkerBootstrap, ON_EVENT_METADATA, On, OnEvent, RUN_REDIS_WORKER, type RunRedisWorkerFn, STEP_INTERCEPTOR_METADATA, StepInterceptor, ThinStepRegistrar, ThinWorkerBootstrap, ThinWorkflowRegistrar, type UserRef, WORKFLOW_METADATA, Workflow, type WorkflowMeta, type WorkflowOptions, WorkflowService, entityConfigFor, getDurableStepMeta, getEntityMeta, getOnEvents, getWorkflowMeta, inAppWorkerProviders, isDeadLetterHandler, isStepInterceptor };