@horizon-republic/nestjs-jetstream 2.12.0 → 2.13.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.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { Logger, ModuleMetadata, FactoryProvider, Type, OnApplicationShutdown, DynamicModule } from '@nestjs/common';
2
2
  import { MsgHdrs, NatsConnection, Status, ConnectionOptions, Msg } from '@nats-io/transport-node';
3
- import { JetStreamManager, JetStreamClient, StreamConfig, ConsumerConfig, ConsumeOptions, DeliverPolicy, ReplayPolicy, ConsumerInfo, JsMsg } from '@nats-io/jetstream';
3
+ import { JetStreamManager, JetStreamClient, StreamConfig, ConsumerConfig, ConsumeOptions, DeliverPolicy, ReplayPolicy, StreamInfo, ConsumerInfo, JsMsg } from '@nats-io/jetstream';
4
4
  import { Registry } from 'prom-client';
5
5
  import { Span } from '@opentelemetry/api';
6
6
  import { ClientProxy, ReadPacket, WritePacket, MessageHandler, Server, CustomTransportStrategy, BaseRpcContext } from '@nestjs/microservices';
@@ -11,7 +11,7 @@ import { Observable } from 'rxjs';
11
11
  *
12
12
  * Implementations handle serialization between application objects and
13
13
  * binary data transmitted over NATS. The transport uses a single global
14
- * codec all messages (RPC and events) share the same format.
14
+ * codec: all messages (RPC and events) share the same format.
15
15
  *
16
16
  * @example
17
17
  * ```typescript
@@ -37,10 +37,10 @@ interface Codec {
37
37
  /**
38
38
  * Identifies a JetStream stream/consumer kind.
39
39
  *
40
- * - `Event` — Workqueue events (at-least-once delivery to one consumer).
41
- * - `Command` — RPC commands (JetStream mode only).
42
- * - `Broadcast` Broadcast events (fan-out to all consumers).
43
- * - `Ordered` — Ordered events (strict sequential delivery, Limits retention).
40
+ * - `Event`: workqueue events (at-least-once delivery to one consumer).
41
+ * - `Command`: RPC commands (JetStream mode only).
42
+ * - `Broadcast`: broadcast events (fan-out to all consumers).
43
+ * - `Ordered`: ordered events (strict sequential delivery, Limits retention).
44
44
  */
45
45
  declare enum StreamKind {
46
46
  Event = "ev",
@@ -65,7 +65,7 @@ declare enum MessageKind {
65
65
  type HandlerStatus = 'success' | 'error' | 'retried' | 'terminated';
66
66
  /**
67
67
  * Outcome of a client publish (event emit or RPC publish leg). Outbound
68
- * operations either acknowledge cleanly or surface a transport error there
68
+ * operations either acknowledge cleanly or surface a transport error; there
69
69
  * is no retried/terminated dimension at the publish boundary.
70
70
  */
71
71
  type PublishStatus = 'success' | 'error';
@@ -152,7 +152,7 @@ interface TransportHooks {
152
152
  * Fired after every client-side publish (event emit or RPC publish leg)
153
153
  * completes, regardless of outcome.
154
154
  *
155
- * @param subject Declared user pattern (e.g. `orders.created`) bounded
155
+ * @param subject Declared user pattern (e.g. `orders.created`), bounded
156
156
  * by handler registration, safe for high-cardinality labels.
157
157
  * @param kind Stream kind the publish targets: `Event`, `Broadcast`,
158
158
  * `Ordered`, or `Command` (RPC publish leg).
@@ -161,7 +161,7 @@ interface TransportHooks {
161
161
  */
162
162
  [TransportEvent.Published](subject: string, kind: StreamKind, durationMs: number, status: PublishStatus): void;
163
163
  /**
164
- * Fired after an RPC round-trip completes from the caller's perspective
164
+ * Fired after an RPC round-trip completes from the caller's perspective:
165
165
  * either a reply is received, the call errors out, or the deadline expires.
166
166
  *
167
167
  * Distinct from {@link Published} which only covers the publish leg.
@@ -175,7 +175,7 @@ interface TransportHooks {
175
175
  }
176
176
  /**
177
177
  * Internal subscriber for a transport event. Multiple subscribers may be
178
- * registered per event via `EventBus.subscribe()` used by built-in
178
+ * registered per event via `EventBus.subscribe()`; used by built-in
179
179
  * observers (e.g. metrics) without overriding the user-provided hook.
180
180
  */
181
181
  type TransportEventSubscriber<K extends keyof TransportHooks> = (...args: Parameters<TransportHooks[K]>) => unknown;
@@ -241,7 +241,7 @@ interface MetricsConfig {
241
241
  /**
242
242
  * Polling interval (ms) for gauge metrics that query `JetStreamManager`
243
243
  * (consumer pending, stream messages, etc.). Default `15_000`.
244
- * Set to `0` to disable polling counter/histogram metrics still update
244
+ * Set to `0` to disable polling; counter/histogram metrics still update
245
245
  * via the event bus.
246
246
  */
247
247
  pollInterval?: number;
@@ -256,7 +256,7 @@ type MetricsOption = boolean | MetricsConfig;
256
256
 
257
257
  /**
258
258
  * Instrumentation scope name reported on every span the library emits.
259
- * Matches the npm package name the convention used by
259
+ * Matches the npm package name, the convention used by
260
260
  * `@opentelemetry/instrumentation-*` and most third-party instrumentations.
261
261
  */
262
262
  declare const TRACER_NAME = "@horizon-republic/nestjs-jetstream";
@@ -287,7 +287,7 @@ declare enum JetstreamTrace {
287
287
  Consume = "consume",
288
288
  /**
289
289
  * `CLIENT` span covering a full RPC round-trip on the caller side
290
- * (`client.send()` reply received). Wraps the inner publish.
290
+ * (`client.send()` -> reply received). Wraps the inner publish.
291
291
  * Default: ON.
292
292
  */
293
293
  RpcClientSend = "rpc.client.send",
@@ -325,8 +325,8 @@ declare const DEFAULT_TRACES: readonly JetstreamTrace[];
325
325
  * Central event bus for transport lifecycle notifications.
326
326
  *
327
327
  * Two emission paths:
328
- * - User hooks registered via `forRoot({ hooks })` at most one per event.
329
- * - Internal subscribers added via `subscribe()` many per event, used by
328
+ * - User hooks registered via `forRoot({ hooks })`: at most one per event.
329
+ * - Internal subscribers added via `subscribe()`: many per event, used by
330
330
  * metrics and other built-in observers.
331
331
  *
332
332
  * Both fire on every `emit()` call. Subscriber failures are isolated and
@@ -366,9 +366,9 @@ declare class EventBus {
366
366
  * Manages the lifecycle of a single NATS connection shared across the application.
367
367
  *
368
368
  * Provides both Promise-based and Observable-based access to the connection:
369
- * - `connect()` / `getConnection()` async/await for one-time setup
370
- * - `nc$` cached observable (shareReplay) for reactive consumers
371
- * - `status$` live connection status event stream
369
+ * - `connect()` / `getConnection()`: async/await for one-time setup
370
+ * - `nc$`: cached observable (shareReplay) for reactive consumers
371
+ * - `status$`: live connection status event stream
372
372
  *
373
373
  * One instance per application, created by `JetstreamModule.forRoot()`.
374
374
  */
@@ -391,7 +391,7 @@ declare class ConnectionProvider {
391
391
  private lifecycleSpan;
392
392
  constructor(options: JetstreamModuleOptions, eventBus: EventBus);
393
393
  /**
394
- * Establish NATS connection. Idempotent returns cached connection on subsequent calls.
394
+ * Establish NATS connection. Idempotent: returns cached connection on subsequent calls.
395
395
  *
396
396
  * @throws Error if connection is refused (fail fast).
397
397
  */
@@ -417,7 +417,7 @@ declare class ConnectionProvider {
417
417
  /**
418
418
  * Gracefully shut down the connection.
419
419
  *
420
- * Sequence: drain wait for close. Falls back to force-close on error.
420
+ * Sequence: drain -> wait for close. Falls back to force-close on error.
421
421
  */
422
422
  shutdown(): Promise<void>;
423
423
  private initJetStreamManager;
@@ -429,6 +429,31 @@ declare class ConnectionProvider {
429
429
  private monitorStatus;
430
430
  }
431
431
 
432
+ /** Single source of truth for all stream, consumer, and subject names. */
433
+ declare class NameResolver {
434
+ private readonly options;
435
+ private readonly kinds;
436
+ private readonly dlq;
437
+ constructor(options: JetstreamModuleOptions);
438
+ streamName(kind: StreamKind): string;
439
+ consumerName(kind: StreamKind): string;
440
+ dlqStreamName(): string;
441
+ subject(kind: StreamKind, pattern: string): string;
442
+ filterSubject(kind: StreamKind): string;
443
+ schedulePrefix(kind: StreamKind): string;
444
+ hasCustomPrefix(kind: StreamKind): boolean;
445
+ /**
446
+ * Map a resolved event subject back to its schedule-holder base subject
447
+ * (the `_sch` namespace twin, without the per-message unique suffix).
448
+ */
449
+ scheduleSubjectBase(eventSubject: string): string;
450
+ private get;
451
+ private buildKindMap;
452
+ private normalizePrefix;
453
+ private conventionPrefix;
454
+ private conventionSchedulePrefix;
455
+ }
456
+
432
457
  /**
433
458
  * NestJS ClientProxy implementation for the JetStream transport.
434
459
  *
@@ -439,7 +464,7 @@ declare class ConnectionProvider {
439
464
  * Events always go through JetStream publish for guaranteed delivery.
440
465
  * The mode only affects RPC (request/reply) behavior.
441
466
  *
442
- * Clients are lightweight they share the NATS connection from `forRoot()`.
467
+ * Clients are lightweight: they share the NATS connection from `forRoot()`.
443
468
  */
444
469
  declare class JetstreamClient extends ClientProxy {
445
470
  private readonly rootOptions;
@@ -451,14 +476,14 @@ declare class JetstreamClient extends ClientProxy {
451
476
  private readonly targetName;
452
477
  /** Pre-cached caller name derived from rootOptions.name, computed once in constructor. */
453
478
  private readonly callerName;
454
- /**
455
- * Subject prefixes of the form `{serviceName}__microservice.{kind}.` — one
456
- * per stream kind this client may publish to. Built once in the constructor
457
- * so producing a full subject is a single string concat with the user pattern.
458
- */
479
+ /** Convention subject prefixes for foreign targets; one per stream kind. */
459
480
  private readonly eventSubjectPrefix;
460
481
  private readonly commandSubjectPrefix;
461
482
  private readonly orderedSubjectPrefix;
483
+ /** Broadcast subject prefix derived from the own resolver; never null. */
484
+ private readonly broadcastPrefix;
485
+ /** Resolver for self-target subjects; null when targeting a foreign service. */
486
+ private readonly selfNames;
462
487
  /**
463
488
  * RPC configuration snapshots. The values are derived from rootOptions at
464
489
  * construction time so the publish hot path never has to re-run
@@ -470,13 +495,8 @@ declare class JetstreamClient extends ClientProxy {
470
495
  private readonly otel;
471
496
  /** Server endpoint parts used for `server.address` / `server.port` span attributes. */
472
497
  private readonly serverEndpoint;
473
- /** Shared inbox for JetStream-mode RPC responses. */
474
- private inbox;
475
- private inboxSubscription;
476
- /** Pending JetStream-mode RPC callbacks, keyed by correlation ID. */
477
- private readonly pendingMessages;
478
- /** Pending JetStream-mode RPC timeouts, keyed by correlation ID. */
479
- private readonly pendingTimeouts;
498
+ /** Reply inbox and pending-request registry for JetStream-mode RPC. */
499
+ private readonly rpcInbox;
480
500
  /** Subscription to connection status events for disconnect handling. */
481
501
  private statusSubscription;
482
502
  /**
@@ -485,7 +505,7 @@ declare class JetstreamClient extends ClientProxy {
485
505
  * and reach for the underlying connection synchronously instead.
486
506
  */
487
507
  private readyForPublish;
488
- constructor(rootOptions: JetstreamModuleOptions, targetServiceName: string, connection: ConnectionProvider, codec: Codec, eventBus: EventBus);
508
+ constructor(rootOptions: JetstreamModuleOptions, targetServiceName: string, connection: ConnectionProvider, codec: Codec, eventBus: EventBus, names?: NameResolver);
489
509
  /**
490
510
  * Establish connection. Called automatically by NestJS on first use.
491
511
  *
@@ -523,23 +543,14 @@ declare class JetstreamClient extends ClientProxy {
523
543
  private publishCoreRpc;
524
544
  /** JetStream mode: publish to stream + wait for inbox response. */
525
545
  private publishJetStreamRpc;
546
+ private warnIfDuplicate;
526
547
  private reportPublished;
527
548
  private reportRpcCompleted;
528
549
  /** Fail-fast all pending JetStream RPC callbacks on connection loss. */
529
550
  private handleDisconnect;
530
- /** Reject all pending RPC callbacks, clear timeouts, and tear down inbox. */
531
- private rejectPendingRpcs;
532
- /** Setup shared inbox subscription for JetStream RPC responses. */
533
- private setupInbox;
534
- /** Route an inbox reply to the matching pending callback. */
535
- private routeInboxReply;
536
551
  /**
537
- * Resolve a user pattern to a fully-qualified NATS subject, dispatching
538
- * between the event, broadcast, and ordered prefixes.
539
- *
540
- * The leading-char check short-circuits the `startsWith` comparisons for
541
- * patterns that cannot possibly carry a broadcast/ordered marker, which is
542
- * the overwhelmingly common case.
552
+ * Resolve a user pattern to a fully-qualified NATS subject. Self-targets go
553
+ * through the resolver so custom subjectPrefix options are honoured.
543
554
  */
544
555
  private buildEventSubject;
545
556
  /** Build NATS headers merging custom headers with transport headers. */
@@ -549,17 +560,12 @@ declare class JetstreamClient extends ClientProxy {
549
560
  /**
550
561
  * Build a schedule-holder subject for NATS message scheduling.
551
562
  *
552
- * The schedule-holder subject resides in the same stream as the target but
553
- * uses a separate `_sch` namespace that is NOT matched by any consumer filter.
554
- * NATS holds the message and publishes it to the target subject after the delay.
555
- *
556
- * A unique per-message suffix is appended because the server stores schedules
557
- * as rollup messages one active schedule per subject (ADR-51). Without it,
558
- * concurrent schedules of the same pattern would silently replace each other.
559
- *
560
- * Examples:
561
- * - `{svc}__microservice.ev.order.reminder` → `{svc}__microservice._sch.order.reminder.<nuid>`
562
- * - `broadcast.config.updated` → `broadcast._sch.config.updated.<nuid>`
563
+ * The holder lives in the same stream as the target but under the `_sch`
564
+ * namespace no consumer filter matches; the server publishes it to the
565
+ * target subject when the schedule fires. The unique per-message suffix
566
+ * exists because the server stores schedules as rollup messages, one
567
+ * active schedule per subject (ADR-51): without it, concurrent schedules
568
+ * of the same pattern would silently replace each other.
563
569
  */
564
570
  private buildScheduleSubject;
565
571
  }
@@ -611,7 +617,7 @@ declare class JetstreamRecord<TData = unknown> {
611
617
  * Fluent builder for constructing JetstreamRecord instances.
612
618
  *
613
619
  * Protected headers (`correlation-id`, `reply-to`, `error`) cannot be
614
- * set by the user attempting to do so throws an error at build time.
620
+ * set by the user; attempting to do so throws an error at build time.
615
621
  */
616
622
  declare class JetstreamRecordBuilder<TData = unknown> {
617
623
  private data;
@@ -742,9 +748,8 @@ interface HandlerMetadata {
742
748
  }
743
749
  /**
744
750
  * Host / port pair surfaced as `server.address` / `server.port` span
745
- * attributes. `port` is optional OTel semconv makes it conditional on
746
- * being different from the protocol default, and we'd rather emit nothing
747
- * than invent a number the user never configured.
751
+ * attributes. `port` is optional: OTel semconv makes it conditional, so we
752
+ * omit it rather than invent a number the user never configured.
748
753
  */
749
754
  interface ServerEndpoint {
750
755
  readonly host: string;
@@ -799,7 +804,7 @@ interface JetstreamResponseContext {
799
804
  }
800
805
  /**
801
806
  * Classification outcome for a thrown error. Affects span status and
802
- * attributes only reply envelopes and internal logging are unchanged.
807
+ * attributes only; reply envelopes and internal logging are unchanged.
803
808
  */
804
809
  type ErrorClassification = 'expected' | 'unexpected';
805
810
  /** Object form of {@link OtelOptions.captureBody}. */
@@ -820,7 +825,7 @@ interface CaptureBodyOptions {
820
825
  readonly subjectAllowlist?: readonly string[];
821
826
  }
822
827
  /**
823
- * OpenTelemetry configuration for `JetstreamModule.forRoot({ otel: })`.
828
+ * OpenTelemetry configuration for `JetstreamModule.forRoot({ otel: ... })`.
824
829
  * All fields are optional; when the host app has not registered an OTel
825
830
  * SDK, every call made by the library is a no-op regardless of config.
826
831
  */
@@ -835,11 +840,11 @@ interface OtelOptions {
835
840
  /**
836
841
  * Which trace kinds to emit.
837
842
  *
838
- * - `'default'` publish, consume, RPC client round-trip, dead letter
839
- * - `'all'` every trace kind defined in {@link JetstreamTrace}
840
- * - `'none'` emit no spans at all (useful with `enabled: true` for
843
+ * - `'default'`: publish, consume, RPC client round-trip, dead letter
844
+ * - `'all'`: every trace kind defined in {@link JetstreamTrace}
845
+ * - `'none'`: emit no spans at all (useful with `enabled: true` for
841
846
  * pure trace-context propagation without the span overhead)
842
- * - `JetstreamTrace[]` explicit selection
847
+ * - `JetstreamTrace[]`: explicit selection
843
848
  *
844
849
  * @default 'default'
845
850
  */
@@ -857,7 +862,7 @@ interface OtelOptions {
857
862
  *
858
863
  * Transport-internal headers (`x-correlation-id`, `x-reply-to`, `x-error`,
859
864
  * `x-subject`, `x-caller-name`) and propagator-owned headers
860
- * (`traceparent`, `tracestate`, `baggage`, `sentry-trace`, `b3`, ) are
865
+ * (`traceparent`, `tracestate`, `baggage`, `sentry-trace`, `b3`, ...) are
861
866
  * always suppressed regardless of the allowlist.
862
867
  *
863
868
  * @default ['x-request-id']
@@ -882,7 +887,7 @@ interface OtelOptions {
882
887
  /**
883
888
  * Invoked after a publish span has been started and before the actual
884
889
  * publish call executes. Use to enrich the span with custom attributes.
885
- * Must be synchronous thrown errors are caught and logged at debug
890
+ * Must be synchronous; thrown errors are caught and logged at debug
886
891
  * level without affecting the publish path.
887
892
  */
888
893
  publishHook?(span: Span, ctx: JetstreamPublishContext): void;
@@ -918,9 +923,9 @@ interface OtelOptions {
918
923
  * RPC contract) or `'unexpected'` (infrastructure failure or bug). Drives
919
924
  * OpenTelemetry span status and attributes only.
920
925
  *
921
- * - `'expected'` span status `OK` with `jetstream.rpc.reply.has_error`
926
+ * - `'expected'` -> span status `OK` with `jetstream.rpc.reply.has_error`
922
927
  * and `jetstream.rpc.reply.error.code` attributes
923
- * - `'unexpected'` span status `ERROR` with `span.recordException(err)`
928
+ * - `'unexpected'` -> span status `ERROR` with `span.recordException(err)`
924
929
  *
925
930
  * Reply envelopes delivered to RPC clients are identical in both cases.
926
931
  * This classification affects only the observability artifact.
@@ -941,6 +946,18 @@ interface OtelOptions {
941
946
 
942
947
  type ProvisioningEntity = 'stream' | 'consumer';
943
948
 
949
+ /** How the library provisions a JetStream entity. */
950
+ declare enum ManagementMode {
951
+ /** Library creates/updates the entity (current behavior). Default. */
952
+ Auto = "auto",
953
+ /** Bind to an externally-provisioned entity; never create or update. */
954
+ Manual = "manual"
955
+ }
956
+ /** Per-entity provisioning control for one stream kind. */
957
+ interface EntityManagement {
958
+ stream?: ManagementMode;
959
+ consumer?: ManagementMode;
960
+ }
944
961
  /**
945
962
  * Stream config overrides exposed to users.
946
963
  *
@@ -949,12 +966,19 @@ type ProvisioningEntity = 'stream' | 'consumer';
949
966
  * Any `retention` value provided at runtime is silently stripped.
950
967
  */
951
968
  type StreamConfigOverrides = Partial<Omit<StreamConfig, 'retention'>>;
969
+ /**
970
+ * Ack-deadline auto-extension setting.
971
+ *
972
+ * `false` disables extension, `true` extends at half of `ack_wait`,
973
+ * and a number sets an explicit extension interval in milliseconds.
974
+ */
975
+ type AckExtensionConfig = boolean | number;
952
976
  /**
953
977
  * RPC transport configuration.
954
978
  *
955
979
  * Discriminated union on `mode`:
956
- * - `'core'` — NATS native request/reply. Lowest latency.
957
- * - `'jetstream'` — Commands persisted in JetStream. Responses via Core NATS inbox.
980
+ * - `'core'`: NATS native request/reply. Lowest latency.
981
+ * - `'jetstream'`: Commands persisted in JetStream. Responses via Core NATS inbox.
958
982
  *
959
983
  * When `mode` is `'core'`, only `timeout` is available.
960
984
  * When `mode` is `'jetstream'`, additional stream/consumer overrides are exposed.
@@ -979,8 +1003,16 @@ type RpcConfig = {
979
1003
  * Auto-extend ack deadline via `msg.working()` during RPC handler execution.
980
1004
  * The RPC handler timeout (`setTimeout` + `msg.term()`) still acts as the hard cap.
981
1005
  */
982
- ackExtension?: boolean | number;
1006
+ ackExtension?: AckExtensionConfig;
1007
+ /** Provisioning control for RPC stream/consumer. Falls back to provisioning.management. */
1008
+ management?: EntityManagement;
1009
+ /** Custom subject prefix (trailing dot normalized), e.g. 'company.orders.'. */
1010
+ subjectPrefix?: string;
983
1011
  };
1012
+ /** The JetStream variant of {@link RpcConfig}. */
1013
+ type JetStreamRpcConfig = Extract<RpcConfig, {
1014
+ mode: 'jetstream';
1015
+ }>;
984
1016
  /** Overrides for JetStream stream and consumer configuration. */
985
1017
  interface StreamConsumerOverrides {
986
1018
  stream?: StreamConfigOverrides;
@@ -990,16 +1022,16 @@ interface StreamConsumerOverrides {
990
1022
  * Controls prefetch buffer size, idle heartbeat interval, and auto-refill thresholds.
991
1023
  *
992
1024
  * nats.js supports two consumption modes (message-based and byte-based).
993
- * Do not mix `max_bytes`/`threshold_bytes` with `threshold_messages` —
1025
+ * Do not mix `max_bytes`/`threshold_bytes` with `threshold_messages`;
994
1026
  * use one mode or the other.
995
1027
  *
996
- * @see https://github.com/nats-io/nats.js ConsumeOptions
1028
+ * @see https://github.com/nats-io/nats.js ConsumeOptions
997
1029
  */
998
1030
  consume?: Partial<ConsumeOptions>;
999
1031
  /**
1000
1032
  * Maximum number of concurrent handler executions (RxJS `mergeMap` limit).
1001
1033
  *
1002
- * Default: `undefined` (unlimited naturally bounded by `max_ack_pending`).
1034
+ * Default: `undefined` (unlimited, naturally bounded by `max_ack_pending`).
1003
1035
  * Set this to protect downstream systems from overload.
1004
1036
  *
1005
1037
  * **Important:** if `concurrency < max_ack_pending`, messages buffer in RxJS
@@ -1010,11 +1042,15 @@ interface StreamConsumerOverrides {
1010
1042
  /**
1011
1043
  * Auto-extend the NATS ack deadline via `msg.working()` during handler execution.
1012
1044
  *
1013
- * - `false` (default): disabled NATS redelivers after `ack_wait` if not acked.
1045
+ * - `false` (default): disabled; NATS redelivers after `ack_wait` if not acked.
1014
1046
  * - `true`: auto-extend at `ack_wait / 2` interval (calculated from consumer config).
1015
1047
  * - `number`: explicit extension interval in milliseconds.
1016
1048
  */
1017
- ackExtension?: boolean | number;
1049
+ ackExtension?: AckExtensionConfig;
1050
+ /** Provisioning control for this kind's stream/consumer. Falls back to provisioning.management. */
1051
+ management?: EntityManagement;
1052
+ /** Custom subject prefix (trailing dot normalized), e.g. 'company.orders.'. */
1053
+ subjectPrefix?: string;
1018
1054
  }
1019
1055
  /**
1020
1056
  * Configuration for ordered event consumers.
@@ -1022,7 +1058,7 @@ interface StreamConsumerOverrides {
1022
1058
  * Ordered consumers use Limits retention and deliver messages in strict
1023
1059
  * sequential order with at-most-once delivery. No ack/nak/DLQ.
1024
1060
  *
1025
- * Only a subset of consumer options applies ordered consumers are
1061
+ * Only a subset of consumer options applies; ordered consumers are
1026
1062
  * ephemeral and auto-managed by nats.js.
1027
1063
  */
1028
1064
  interface OrderedEventOverrides {
@@ -1046,6 +1082,10 @@ interface OrderedEventOverrides {
1046
1082
  * @default ReplayPolicy.Instant
1047
1083
  */
1048
1084
  replayPolicy?: ReplayPolicy;
1085
+ /** Provisioning control for this kind's stream/consumer. Falls back to provisioning.management. */
1086
+ management?: EntityManagement;
1087
+ /** Custom subject prefix (trailing dot normalized), e.g. 'company.orders.'. */
1088
+ subjectPrefix?: string;
1049
1089
  }
1050
1090
  /**
1051
1091
  * Configuration for the handler metadata KV registry.
@@ -1054,7 +1094,7 @@ interface OrderedEventOverrides {
1054
1094
  * entries to a NATS KV bucket at startup. External services (API gateways,
1055
1095
  * dashboards) can watch the bucket for service discovery.
1056
1096
  *
1057
- * All fields are optional sensible defaults are applied.
1097
+ * All fields are optional; sensible defaults are applied.
1058
1098
  */
1059
1099
  interface MetadataRegistryOptions {
1060
1100
  /**
@@ -1086,6 +1126,8 @@ interface ProvisioningOptions {
1086
1126
  * Warn-only; never blocks boot. Off by default.
1087
1127
  */
1088
1128
  preflightStorageCheck?: boolean;
1129
+ /** Default management mode for every stream and consumer. @default ManagementMode.Auto */
1130
+ management?: ManagementMode;
1089
1131
  }
1090
1132
  /**
1091
1133
  * Root module configuration for `JetstreamModule.forRoot()`.
@@ -1129,7 +1171,7 @@ interface JetstreamModuleOptions {
1129
1171
  ordered?: OrderedEventOverrides;
1130
1172
  /**
1131
1173
  * Transport lifecycle hook handlers.
1132
- * Unset hooks are silently ignored no default logging.
1174
+ * Unset hooks are silently ignored; no default logging.
1133
1175
  */
1134
1176
  hooks?: Partial<TransportHooks>;
1135
1177
  /**
@@ -1173,6 +1215,8 @@ interface JetstreamModuleOptions {
1173
1215
  */
1174
1216
  dlq?: {
1175
1217
  stream?: StreamConfigOverrides;
1218
+ /** Provisioning control for the DLQ stream. Falls back to provisioning.management. */
1219
+ management?: EntityManagement;
1176
1220
  };
1177
1221
  /**
1178
1222
  * Graceful shutdown timeout in ms.
@@ -1187,7 +1231,7 @@ interface JetstreamModuleOptions {
1187
1231
  * if immutable properties like `storage` differ from the running stream.
1188
1232
  * Messages are preserved during migration.
1189
1233
  *
1190
- * `retention` is NOT migratable it is controlled by the transport
1234
+ * `retention` is NOT migratable: it is controlled by the transport
1191
1235
  * (Workqueue for events, Limits for broadcast/ordered) and a mismatch
1192
1236
  * is always treated as an error regardless of this flag.
1193
1237
  *
@@ -1214,7 +1258,7 @@ interface JetstreamModuleOptions {
1214
1258
  /**
1215
1259
  * Raw NATS ConnectionOptions pass-through for advanced connection config.
1216
1260
  * Allows setting tls, auth, reconnect behavior, maxReconnectAttempts, etc.
1217
- * Merged with `name` and `servers` those take precedence.
1261
+ * Merged with `name` and `servers`; those take precedence.
1218
1262
  */
1219
1263
  connectionOptions?: Partial<ConnectionOptions>;
1220
1264
  /**
@@ -1223,7 +1267,7 @@ interface JetstreamModuleOptions {
1223
1267
  * Pass `true` to enable with defaults, or a {@link MetricsConfig} object for
1224
1268
  * full control (custom registry, prefix, labels, polling, buckets).
1225
1269
  * When omitted or `false`, the metrics module is not registered and
1226
- * `prom-client` is not imported zero overhead.
1270
+ * `prom-client` is not imported, so there is zero overhead.
1227
1271
  *
1228
1272
  * Requires `prom-client` peer dependency to be installed when enabled.
1229
1273
  * The service writes to `prom-client`'s global `register` by default,
@@ -1245,7 +1289,7 @@ interface JetstreamModuleOptions {
1245
1289
  * OpenTelemetry integration. When omitted, sensible defaults are applied:
1246
1290
  * tracing is enabled, default trace kinds are emitted, only standard
1247
1291
  * correlation headers are captured. If no OTel SDK is registered in the
1248
- * consuming application, all tracer calls are no-ops there is no
1292
+ * consuming application, all tracer calls are no-ops with no
1249
1293
  * runtime cost.
1250
1294
  *
1251
1295
  * Accepts a full {@link OtelOptions} object, or the boolean shorthand
@@ -1273,7 +1317,7 @@ interface JetstreamFeatureOptions {
1273
1317
  * Supports three patterns: `useFactory`, `useExisting`, `useClass`.
1274
1318
  */
1275
1319
  type JetstreamModuleAsyncOptions = {
1276
- /** Service name required upfront for DI token generation. */
1320
+ /** Service name, required upfront for DI token generation. */
1277
1321
  name: string;
1278
1322
  /** Additional module imports (e.g., ConfigModule). */
1279
1323
  imports?: ModuleMetadata['imports'];
@@ -1352,6 +1396,7 @@ interface RpcRouterOptions {
1352
1396
  */
1353
1397
  declare class PatternRegistry {
1354
1398
  private readonly options;
1399
+ private readonly names;
1355
1400
  private readonly logger;
1356
1401
  private readonly registry;
1357
1402
  private cachedPatterns;
@@ -1360,7 +1405,7 @@ declare class PatternRegistry {
1360
1405
  private _hasBroadcasts;
1361
1406
  private _hasOrdered;
1362
1407
  private _hasMetadata;
1363
- constructor(options: JetstreamModuleOptions);
1408
+ constructor(options: JetstreamModuleOptions, names: NameResolver);
1364
1409
  /**
1365
1410
  * Register all handlers from the NestJS strategy.
1366
1411
  *
@@ -1373,7 +1418,7 @@ declare class PatternRegistry {
1373
1418
  * Resolve the declared pattern and {@link StreamKind} for a full NATS subject.
1374
1419
  *
1375
1420
  * Returns `null` when the subject is not registered. The declared pattern is
1376
- * the value the user passed to `@EventPattern`/`@MessagePattern` stable and
1421
+ * the value the user passed to `@EventPattern`/`@MessagePattern`: stable and
1377
1422
  * bounded, suitable for use as a Prometheus label without cardinality risk.
1378
1423
  */
1379
1424
  resolveDeclared(subject: string): {
@@ -1382,6 +1427,10 @@ declare class PatternRegistry {
1382
1427
  } | null;
1383
1428
  /** Get all registered broadcast patterns (for consumer filter_subject setup). */
1384
1429
  getBroadcastPatterns(): string[];
1430
+ /** Get registered event patterns as raw user-declared patterns. */
1431
+ getEventPatterns(): string[];
1432
+ /** Get registered command patterns as raw user-declared patterns. */
1433
+ getCommandPatterns(): string[];
1385
1434
  hasBroadcastHandlers(): boolean;
1386
1435
  hasRpcHandlers(): boolean;
1387
1436
  hasEventHandlers(): boolean;
@@ -1399,8 +1448,6 @@ declare class PatternRegistry {
1399
1448
  getMetadataEntries(): Map<string, Record<string, unknown>>;
1400
1449
  /** Get patterns grouped by kind (cached after registration). */
1401
1450
  getPatternsByKind(): PatternsByKind;
1402
- /** Normalize a full NATS subject back to the user-facing pattern. */
1403
- normalizeSubject(subject: string): string;
1404
1451
  private buildPatternsByKind;
1405
1452
  private resolveStreamKind;
1406
1453
  private logSummary;
@@ -1412,19 +1459,20 @@ declare class PatternRegistry {
1412
1459
  * Subscribes to `{service}.cmd.>` with a queue group for load balancing.
1413
1460
  * Each request is processed and replied to directly via `msg.respond()`.
1414
1461
  *
1415
- * This is the default RPC mode lowest latency, no persistence overhead.
1462
+ * This is the default RPC mode: lowest latency, no persistence overhead.
1416
1463
  */
1417
1464
  declare class CoreRpcServer {
1418
1465
  private readonly connection;
1419
1466
  private readonly patternRegistry;
1420
1467
  private readonly codec;
1421
1468
  private readonly eventBus;
1469
+ private readonly names?;
1422
1470
  private readonly logger;
1423
1471
  private subscription;
1424
1472
  private readonly otel;
1425
1473
  private readonly serviceName;
1426
1474
  private readonly serverEndpoint;
1427
- constructor(options: JetstreamModuleOptions, connection: ConnectionProvider, patternRegistry: PatternRegistry, codec: Codec, eventBus: EventBus);
1475
+ constructor(options: JetstreamModuleOptions, connection: ConnectionProvider, patternRegistry: PatternRegistry, codec: Codec, eventBus: EventBus, names?: NameResolver | undefined);
1428
1476
  /** Start listening for RPC requests on the command subject. */
1429
1477
  start(): Promise<void>;
1430
1478
  /** Stop listening and clean up the subscription. */
@@ -1437,71 +1485,12 @@ declare class CoreRpcServer {
1437
1485
  }
1438
1486
 
1439
1487
  /**
1440
- * Manages JetStream stream lifecycle: creation, updates, and idempotent ensures.
1441
- *
1442
- * Creates up to three stream types depending on configuration:
1443
- * - **Event stream** — workqueue events (always, when consumer enabled)
1444
- * - **Command stream** — RPC commands (only in jetstream RPC mode)
1445
- * - **Broadcast stream** — fan-out events (only if broadcast handlers exist)
1488
+ * Routes event, broadcast, and ordered messages to their handlers.
1446
1489
  *
1447
- * All operations are idempotent: safe to call on every startup and reconnection.
1490
+ * Per stream kind it assembles a routing pipeline (resolve, handle, settle)
1491
+ * and a concurrency gate, then feeds the message stream through them. The
1492
+ * dead-letter flow lives in {@link DeadLetterCapture}.
1448
1493
  */
1449
- declare class StreamProvider {
1450
- private readonly options;
1451
- private readonly connection;
1452
- private readonly logger;
1453
- private readonly migration;
1454
- private readonly otel;
1455
- private readonly otelServiceName;
1456
- private readonly otelEndpoint;
1457
- constructor(options: JetstreamModuleOptions, connection: ConnectionProvider);
1458
- /**
1459
- * Ensure all required streams exist with correct configuration.
1460
- *
1461
- * @param kinds Which stream kinds to create. Determined by the module based
1462
- * on RPC mode and registered handler patterns.
1463
- * If the dlq option is enabled, also ensures the DLQ stream exists.
1464
- */
1465
- ensureStreams(kinds: StreamKind[]): Promise<void>;
1466
- /** Get the stream name for a given kind. */
1467
- getStreamName(kind: StreamKind): string;
1468
- /** Get the subjects pattern for a given kind. */
1469
- getSubjects(kind: StreamKind): string[];
1470
- /** Ensure a single stream exists, creating or updating as needed. */
1471
- private ensureStream;
1472
- /** Ensure a dead-letter queue stream exists, creating or updating as needed. */
1473
- private ensureDlqStream;
1474
- private handleExistingStream;
1475
- private buildMutableOnlyConfig;
1476
- private logChanges;
1477
- private buildReservation;
1478
- private errorContext;
1479
- private runStreamOp;
1480
- /** The broadcast stream is global — every service in the cluster shares it. */
1481
- private isSharedStream;
1482
- /** Build the full stream config by merging defaults with user overrides. */
1483
- private buildConfig;
1484
- /**
1485
- * Build the stream configuration for the Dead-Letter Queue (DLQ).
1486
- *
1487
- * Merges the library default DLQ config with user-provided overrides.
1488
- * Ensures transport-controlled settings like retention are safely decoupled.
1489
- */
1490
- private buildDlqConfig;
1491
- /** Get default config for a stream kind. */
1492
- private getDefaults;
1493
- /** Check if scheduling is enabled for a stream kind via `allow_msg_schedules` override. */
1494
- private isSchedulingEnabled;
1495
- /** Get user-provided overrides for a stream kind, stripping transport-controlled properties. */
1496
- private getOverrides;
1497
- /**
1498
- * Remove transport-controlled properties from user overrides.
1499
- * `retention` is managed by the transport (Workqueue/Limits per stream kind)
1500
- * and silently stripped to protect users from misconfiguration.
1501
- */
1502
- private stripTransportControlled;
1503
- }
1504
-
1505
1494
  declare class EventRouter {
1506
1495
  private readonly messageProvider;
1507
1496
  private readonly patternRegistry;
@@ -1510,14 +1499,13 @@ declare class EventRouter {
1510
1499
  private readonly deadLetterConfig?;
1511
1500
  private readonly processingConfig?;
1512
1501
  private readonly ackWaitMap?;
1513
- private readonly connection?;
1514
- private readonly options?;
1515
1502
  private readonly logger;
1516
1503
  private readonly subscriptions;
1517
1504
  private readonly otel;
1518
1505
  private readonly serviceName;
1519
1506
  private readonly serverEndpoint;
1520
- constructor(messageProvider: MessageProvider, patternRegistry: PatternRegistry, codec: Codec, eventBus: EventBus, deadLetterConfig?: DeadLetterConfig | undefined, processingConfig?: EventProcessingConfig | undefined, ackWaitMap?: Map<StreamKind, number> | undefined, connection?: ConnectionProvider | undefined, options?: JetstreamModuleOptions | undefined);
1507
+ private readonly capture;
1508
+ constructor(messageProvider: MessageProvider, patternRegistry: PatternRegistry, codec: Codec, eventBus: EventBus, deadLetterConfig?: DeadLetterConfig | undefined, processingConfig?: EventProcessingConfig | undefined, ackWaitMap?: Map<StreamKind, number> | undefined, connection?: ConnectionProvider, options?: JetstreamModuleOptions, names?: NameResolver);
1521
1509
  /**
1522
1510
  * Update the max_deliver thresholds from actual NATS consumer configs.
1523
1511
  * Called after consumers are ensured so the DLQ map reflects reality.
@@ -1527,50 +1515,10 @@ declare class EventRouter {
1527
1515
  start(): void;
1528
1516
  /** Stop routing and unsubscribe from all streams. */
1529
1517
  destroy(): void;
1530
- /** Subscribe to a message stream and route each message to its handler. */
1518
+ /** Assemble the pipeline and concurrency gate for one stream and subscribe. */
1531
1519
  private subscribeToStream;
1532
1520
  private getConcurrency;
1533
1521
  private getAckExtensionConfig;
1534
- /**
1535
- * Last-resort path for a dead letter: invoke `onDeadLetter`, then `term` on
1536
- * success. On failure the message is nak'd to release it, but the server
1537
- * never redelivers past `max_deliver` — it stays in the stream for manual
1538
- * recovery. Used when the DLQ stream isn't configured, or when publishing
1539
- * to it failed and we still have to surface the message somewhere.
1540
- */
1541
- private fallbackToOnDeadLetterCallback;
1542
- /**
1543
- * Copy the original message headers for the DLQ republish, dropping NATS
1544
- * server control headers: a copied Nats-TTL expires the DLQ entry (or gets
1545
- * the publish rejected when the DLQ stream has no allow_msg_ttl), a copied
1546
- * Nats-Msg-Id collides with the DLQ dedup window.
1547
- */
1548
- private buildDlqHeaders;
1549
- /**
1550
- * Attempt the DLQ publish up to {@link DLQ_PUBLISH_ATTEMPTS} times.
1551
- *
1552
- * Past `max_deliver` the server never redelivers, so an in-process retry is
1553
- * the only second chance a dead letter gets. There is no artificial delay
1554
- * between attempts: when the broker is unreachable each publish already
1555
- * spends its own request timeout, which spaces the attempts naturally.
1556
- */
1557
- private publishToDlqWithRetry;
1558
- /**
1559
- * Publish a dead letter to the configured Dead-Letter Queue (DLQ) stream.
1560
- *
1561
- * Appends diagnostic metadata headers to the original message and preserves
1562
- * the primary payload. If publishing succeeds, it notifies the standard
1563
- * `onDeadLetter` callback and terminates the message. If it fails, it falls
1564
- * back to the callback entirely to prevent silent data loss.
1565
- */
1566
- private publishToDlq;
1567
- /**
1568
- * Orchestrates the handling of a message that has exhausted delivery limits.
1569
- *
1570
- * Emits a system event and delegates either to the robust DLQ stream publisher
1571
- * or directly to the fallback callback based on the active module configuration.
1572
- */
1573
- private handleDeadLetter;
1574
1522
  }
1575
1523
 
1576
1524
  /**
@@ -1583,7 +1531,7 @@ declare class EventRouter {
1583
1531
  * - Timeout -> no response -> term
1584
1532
  * - No handler / decode error -> term immediately
1585
1533
  *
1586
- * Nak is never used for RPC prevents duplicate side effects.
1534
+ * Nak is never used for RPC; it would risk duplicate side effects.
1587
1535
  */
1588
1536
  declare class RpcRouter {
1589
1537
  private readonly messageProvider;
@@ -1611,6 +1559,108 @@ declare class RpcRouter {
1611
1559
  destroy(): void;
1612
1560
  }
1613
1561
 
1562
+ /** Minimal JetStreamManager surface used by the binder. */
1563
+ interface BinderJsm {
1564
+ streams: {
1565
+ info(name: string): Promise<StreamInfo>;
1566
+ };
1567
+ consumers: {
1568
+ info(stream: string, consumer: string): Promise<ConsumerInfo>;
1569
+ };
1570
+ }
1571
+ /** Bind-only provisioning path: info()-only lookups and validation. */
1572
+ declare class InfrastructureBinder {
1573
+ private readonly options;
1574
+ private readonly names;
1575
+ private readonly registry;
1576
+ private readonly logger;
1577
+ constructor(options: JetstreamModuleOptions, names: NameResolver, registry: PatternRegistry);
1578
+ bindStream(jsm: BinderJsm, kind: StreamKind): Promise<StreamInfo>;
1579
+ bindDlqStream(jsm: BinderJsm): Promise<StreamInfo>;
1580
+ bindConsumer(jsm: BinderJsm, kind: StreamKind): Promise<ConsumerInfo>;
1581
+ private fetchStream;
1582
+ private fetchConsumer;
1583
+ private assertHandlersCovered;
1584
+ private assertDlqSubjectCoverage;
1585
+ private assertScheduleCoverage;
1586
+ private assertScheduleHoldersNotConsumed;
1587
+ private warnOnOrphanedMigrationBackup;
1588
+ private warnOnSchedulesDisabled;
1589
+ private warnOnRetention;
1590
+ private warnOnUnlimitedDelivery;
1591
+ private warnOnShortAckWait;
1592
+ private resolveHandlerSubjects;
1593
+ }
1594
+
1595
+ /**
1596
+ * Manages JetStream stream lifecycle: creation, updates, and idempotent ensures.
1597
+ *
1598
+ * Creates up to three stream types depending on configuration:
1599
+ * - **Event stream**: workqueue events (always, when consumer enabled)
1600
+ * - **Command stream**: RPC commands (only in jetstream RPC mode)
1601
+ * - **Broadcast stream**: fan-out events (only if broadcast handlers exist)
1602
+ *
1603
+ * All operations are idempotent: safe to call on every startup and reconnection.
1604
+ */
1605
+ declare class StreamProvider {
1606
+ private readonly options;
1607
+ private readonly connection;
1608
+ private readonly names;
1609
+ private readonly binder;
1610
+ private readonly logger;
1611
+ private readonly migration;
1612
+ private readonly otel;
1613
+ private readonly otelServiceName;
1614
+ private readonly otelEndpoint;
1615
+ constructor(options: JetstreamModuleOptions, connection: ConnectionProvider, names: NameResolver, binder: InfrastructureBinder);
1616
+ /**
1617
+ * Ensure all required streams exist with correct configuration.
1618
+ *
1619
+ * @param kinds Which stream kinds to create. Determined by the module based
1620
+ * on RPC mode and registered handler patterns.
1621
+ * If the dlq option is enabled, also ensures the DLQ stream exists.
1622
+ */
1623
+ ensureStreams(kinds: StreamKind[]): Promise<void>;
1624
+ /** Get the stream name for a given kind. */
1625
+ getStreamName(kind: StreamKind): string;
1626
+ /** Get the subjects pattern for a given kind. */
1627
+ getSubjects(kind: StreamKind): string[];
1628
+ /** Ensure a single stream exists, creating or updating as needed. */
1629
+ private ensureStream;
1630
+ /** Ensure a dead-letter queue stream exists, creating or updating as needed. */
1631
+ private ensureDlqStream;
1632
+ private handleExistingStream;
1633
+ private buildMutableOnlyConfig;
1634
+ private logChanges;
1635
+ private buildReservation;
1636
+ private errorContext;
1637
+ private runStreamOp;
1638
+ private partitionByManagement;
1639
+ private bindStream;
1640
+ private bindDlqStream;
1641
+ /** The broadcast stream is global; every service in the cluster shares it. */
1642
+ private isSharedStream;
1643
+ /** Build the full stream config by merging defaults with user overrides. */
1644
+ private buildConfig;
1645
+ /**
1646
+ * Build the DLQ stream config: library defaults merged with user overrides,
1647
+ * with transport-controlled settings like retention stripped.
1648
+ */
1649
+ private buildDlqConfig;
1650
+ /** Get default config for a stream kind. */
1651
+ private getDefaults;
1652
+ /** Check if scheduling is enabled for a stream kind via `allow_msg_schedules` override. */
1653
+ private isSchedulingEnabled;
1654
+ /** Get user-provided overrides for a stream kind, stripping transport-controlled properties. */
1655
+ private getOverrides;
1656
+ /**
1657
+ * Remove transport-controlled properties from user overrides.
1658
+ * `retention` is managed by the transport (Workqueue/Limits per stream kind)
1659
+ * and silently stripped to protect users from misconfiguration.
1660
+ */
1661
+ private stripTransportControlled;
1662
+ }
1663
+
1614
1664
  /**
1615
1665
  * Manages JetStream consumer lifecycle: creation and idempotent ensures.
1616
1666
  *
@@ -1622,11 +1672,13 @@ declare class ConsumerProvider {
1622
1672
  private readonly connection;
1623
1673
  private readonly streamProvider;
1624
1674
  private readonly patternRegistry;
1675
+ private readonly names;
1676
+ private readonly binder;
1625
1677
  private readonly logger;
1626
1678
  private readonly otel;
1627
1679
  private readonly otelServiceName;
1628
1680
  private readonly otelEndpoint;
1629
- constructor(options: JetstreamModuleOptions, connection: ConnectionProvider, streamProvider: StreamProvider, patternRegistry: PatternRegistry);
1681
+ constructor(options: JetstreamModuleOptions, connection: ConnectionProvider, streamProvider: StreamProvider, patternRegistry: PatternRegistry, names: NameResolver, binder: InfrastructureBinder);
1630
1682
  /**
1631
1683
  * Ensure consumers exist for the specified kinds.
1632
1684
  *
@@ -1637,22 +1689,16 @@ declare class ConsumerProvider {
1637
1689
  getConsumerName(kind: StreamKind): string;
1638
1690
  /**
1639
1691
  * Ensure a single consumer exists with the desired config.
1640
- * Used at **startup** — creates or updates the consumer to match
1641
- * the current pod's configuration.
1692
+ * Startup path: creates or updates the consumer to match the current pod's configuration.
1642
1693
  */
1643
1694
  ensureConsumer(jsm: Awaited<ReturnType<ConnectionProvider['getJetStreamManager']>>, kind: StreamKind): Promise<ConsumerInfo>;
1644
1695
  /**
1645
1696
  * Recover a consumer that disappeared during runtime.
1646
- * Used by **self-healing** — creates if missing, but NEVER updates config.
1647
- *
1648
- * If a migration backup stream exists, another pod is mid-migration — we
1649
- * throw so the self-healing retry loop waits with backoff until migration
1650
- * completes and the backup is cleaned up.
1651
1697
  *
1652
- * This prevents old pods from:
1653
- * - Overwriting a newer pod's consumer config during rolling updates
1654
- * - Creating consumers during migration (which would consume and delete
1655
- * workqueue messages while they're being restored)
1698
+ * Self-healing path: creates if missing but never updates config, so an old pod
1699
+ * cannot overwrite a newer pod's config during rolling updates. If a migration
1700
+ * backup stream exists, throws so the retry loop backs off until migration completes;
1701
+ * creating a consumer mid-migration would eat workqueue messages being restored.
1656
1702
  */
1657
1703
  recoverConsumer(jsm: Awaited<ReturnType<ConnectionProvider['getJetStreamManager']>>, kind: StreamKind): Promise<ConsumerInfo>;
1658
1704
  /**
@@ -1661,13 +1707,12 @@ declare class ConsumerProvider {
1661
1707
  * naturally waiting until the migrating pod finishes and cleans up the backup.
1662
1708
  */
1663
1709
  private assertNoMigrationInProgress;
1664
- /**
1665
- * Create a consumer, handling the race where another pod creates it first.
1666
- */
1710
+ /** Create a consumer, handling the race where another pod creates it first. */
1667
1711
  private createConsumer;
1668
1712
  private runConsumerOp;
1669
1713
  /** Build consumer config by merging defaults with user overrides. */
1670
1714
  private buildConfig;
1715
+ private buildCustomPrefixConfig;
1671
1716
  /** Get default config for a consumer kind. */
1672
1717
  private getDefaults;
1673
1718
  /** Get user-provided overrides for a consumer kind. */
@@ -1718,7 +1763,7 @@ declare class MessageProvider {
1718
1763
  /**
1719
1764
  * Start an ordered consumer for strict sequential delivery.
1720
1765
  *
1721
- * Unlike durable consumers, ordered consumers are ephemeral created at
1766
+ * Unlike durable consumers, ordered consumers are ephemeral: created at
1722
1767
  * consumption time, no durable state. nats.js handles auto-recreation.
1723
1768
  *
1724
1769
  * @param streamName - JetStream stream to consume from.
@@ -1755,13 +1800,9 @@ declare class MessageProvider {
1755
1800
  /**
1756
1801
  * Publishes handler metadata to a NATS KV bucket for external service discovery.
1757
1802
  *
1758
- * Uses TTL + heartbeat to manage entry lifecycle:
1759
- * - Entries are written on startup and refreshed every `ttl / 2`
1760
- * - When the pod stops (graceful or crash), heartbeat stops → entries expire via TTL
1761
- * - No explicit delete needed — NATS handles expiry automatically
1762
- *
1763
- * This provider is fully decoupled from stream/consumer infrastructure —
1764
- * it only depends on the NATS connection and module options.
1803
+ * Entries are written on startup and refreshed every `ttl / 2`. When the pod stops
1804
+ * (graceful or crash), the heartbeat stops and entries expire via TTL, so no
1805
+ * explicit delete is needed.
1765
1806
  */
1766
1807
  declare class MetadataProvider {
1767
1808
  private readonly connection;
@@ -1774,16 +1815,12 @@ declare class MetadataProvider {
1774
1815
  private cachedKv?;
1775
1816
  constructor(options: JetstreamModuleOptions, connection: ConnectionProvider);
1776
1817
  /**
1777
- * Write handler metadata entries to the KV bucket and start heartbeat.
1778
- *
1779
- * Creates the bucket if it doesn't exist (idempotent).
1780
- * Skips silently when entries map is empty.
1781
- * Starts a heartbeat interval that refreshes entries every `ttl / 2`
1782
- * to prevent TTL expiry while the pod is alive.
1818
+ * Write handler metadata entries to the KV bucket and start the heartbeat.
1783
1819
  *
1784
- * Non-critical errors are logged but do not prevent transport startup.
1820
+ * Creates the bucket if missing; skips silently when the map is empty.
1821
+ * Non-critical: errors are logged but do not prevent transport startup.
1785
1822
  *
1786
- * @param entries Map of KV key metadata object.
1823
+ * @param entries Map of KV key to metadata object.
1787
1824
  */
1788
1825
  publish(entries: Map<string, Record<string, unknown>>): Promise<void>;
1789
1826
  /**
@@ -1807,7 +1844,7 @@ declare class MetadataProvider {
1807
1844
  * NATS JetStream API error codes used by the transport.
1808
1845
  *
1809
1846
  * Ref: https://github.com/nats-io/nats-server (server error definitions)
1810
- * Codes verified across NATS 2.12.62.14.1 via integration tests (original codes: 2026-04-02).
1847
+ * Codes verified across NATS 2.12.6-2.14.1 via integration tests (original codes: 2026-04-02).
1811
1848
  */
1812
1849
  declare enum NatsErrorCode {
1813
1850
  /** Consumer does not exist on the specified stream. */
@@ -1816,7 +1853,7 @@ declare enum NatsErrorCode {
1816
1853
  ConsumerAlreadyExists = 10148,
1817
1854
  /** Stream does not exist. */
1818
1855
  StreamNotFound = 10059,
1819
- /** Storage resources exceeded reservation exceeds server `max_file_store`. */
1856
+ /** Storage resources exceeded: reservation exceeds server `max_file_store`. */
1820
1857
  StorageResourcesExceeded = 10047,
1821
1858
  /**
1822
1859
  * No suitable peers for placement (fewer healthy peers than `num_replicas`,
@@ -1828,13 +1865,8 @@ declare enum NatsErrorCode {
1828
1865
  /**
1829
1866
  * NestJS custom transport strategy for NATS JetStream.
1830
1867
  *
1831
- * Coordinates all server-side providers:
1832
- * 1. Registers handlers from NestJS into PatternRegistry
1833
- * 2. Creates required streams and consumers
1834
- * 3. Starts message consumption and routing
1835
- * 4. Handles Core or JetStream RPC based on configuration
1836
- *
1837
- * All dependencies are injected via the NestJS DI container.
1868
+ * Registers handlers, provisions streams and consumers, then starts message
1869
+ * consumption and routing (Core or JetStream RPC based on configuration).
1838
1870
  */
1839
1871
  declare class JetstreamStrategy extends Server implements CustomTransportStrategy {
1840
1872
  private readonly options;
@@ -1861,23 +1893,14 @@ declare class JetstreamStrategy extends Server implements CustomTransportStrateg
1861
1893
  /** Stop all consumers, routers, subscriptions, and metadata heartbeat. Called during shutdown. */
1862
1894
  close(): void;
1863
1895
  /**
1864
- * Override NestJS `Server.addHandler` to fail-fast on duplicate pattern registration.
1896
+ * Override NestJS `Server.addHandler` to fail fast on duplicate pattern registration.
1865
1897
  *
1866
- * The base class silently overwrites duplicate RPC handlers (last wins) and appends
1867
- * duplicate event handlers to a linked list. Both behaviors are hazardous in a
1868
- * JetStream context: silent overwrite drops a handler the user wrote, and double
1869
- * event dispatch double-acks/double-processes the same JetStream message.
1870
- *
1871
- * We treat any pattern collision as a fatal misconfiguration so it surfaces at
1872
- * bootstrap instead of in production traffic.
1898
+ * The base class silently overwrites duplicate RPC handlers and chains duplicate event
1899
+ * handlers, which would double-ack the same JetStream message. Any collision is treated
1900
+ * as a fatal misconfiguration so it surfaces at bootstrap, not in production traffic.
1873
1901
  */
1874
1902
  addHandler(pattern: unknown, callback: MessageHandler, isEventHandler?: boolean, extras?: Record<string, unknown>): void;
1875
- /**
1876
- * Register event listener (required by Server base class).
1877
- *
1878
- * Stores callbacks for client use. Primary lifecycle events
1879
- * are routed through EventBus.
1880
- */
1903
+ /** Register event listener (required by Server base class); lifecycle events use EventBus. */
1881
1904
  on(event: string, callback: Function): void;
1882
1905
  /**
1883
1906
  * Unwrap the underlying NATS connection.
@@ -1912,7 +1935,7 @@ interface Stoppable {
1912
1935
  * 3. Drain and close NATS connection (with timeout safety net)
1913
1936
  * 4. Emit onShutdownComplete hook
1914
1937
  *
1915
- * Idempotent concurrent or repeated calls return the same promise.
1938
+ * Idempotent: concurrent or repeated calls return the same promise.
1916
1939
  * This is critical because NestJS may call `onApplicationShutdown` on
1917
1940
  * multiple module instances (forRoot + forFeature) that share this
1918
1941
  * singleton, and the call order is not guaranteed.
@@ -1927,7 +1950,7 @@ declare class ShutdownManager {
1927
1950
  /**
1928
1951
  * Execute the full shutdown sequence.
1929
1952
  *
1930
- * Idempotent concurrent or repeated calls return the same promise.
1953
+ * Idempotent: concurrent or repeated calls return the same promise.
1931
1954
  *
1932
1955
  * @param strategy Optional stoppable to close (stops consumers and subscriptions).
1933
1956
  */
@@ -1938,16 +1961,16 @@ declare class ShutdownManager {
1938
1961
  /**
1939
1962
  * Root module for the NestJS JetStream transport.
1940
1963
  *
1941
- * - `forRoot()` / `forRootAsync()` registers once in AppModule.
1964
+ * - `forRoot()` / `forRootAsync()`: registers once in AppModule.
1942
1965
  * Creates shared NATS connection, codec, event bus, and optionally
1943
1966
  * the consumer infrastructure.
1944
1967
  *
1945
- * - `forFeature()` registers in feature modules.
1968
+ * - `forFeature()`: registers in feature modules.
1946
1969
  * Creates a lightweight client proxy targeting a specific service.
1947
1970
  *
1948
1971
  * @example
1949
1972
  * ```typescript
1950
- * // AppModule global setup
1973
+ * // AppModule: global setup
1951
1974
  * @Module({
1952
1975
  * imports: [
1953
1976
  * JetstreamModule.forRoot({
@@ -1958,7 +1981,7 @@ declare class ShutdownManager {
1958
1981
  * })
1959
1982
  * export class AppModule {}
1960
1983
  *
1961
- * // Feature module per-service clients
1984
+ * // Feature module: per-service clients
1962
1985
  * @Module({
1963
1986
  * imports: [
1964
1987
  * JetstreamModule.forFeature({ name: 'users' }),
@@ -2045,7 +2068,7 @@ interface PackrLike {
2045
2068
  * MessagePack codec backed by a caller-provided `msgpackr` `Packr` instance.
2046
2069
  *
2047
2070
  * Use this codec when publishing structured payloads larger than roughly
2048
- * 12 KB below that size the default {@link JsonCodec} wins on per-call
2071
+ * 1-2 KB; below that size the default {@link JsonCodec} wins on per-call
2049
2072
  * constant overhead. Above it, MessagePack encodes and decodes several times
2050
2073
  * faster and produces smaller wire frames. The format is cross-language, so
2051
2074
  * Node producers and non-Node consumers (Python, Go, Java, Rust, ...) stay
@@ -2169,7 +2192,7 @@ declare class RpcContext extends BaseRpcContext<[NatsMessage]> {
2169
2192
  terminate(reason?: string): void;
2170
2193
  /** Narrow to JsMsg or return null for Core messages. Used by metadata getters. */
2171
2194
  private asJetStream;
2172
- /** Ensure the message is JetStream settlement actions are not available for Core NATS. */
2195
+ /** Ensure the message is JetStream; settlement actions are not available for Core NATS. */
2173
2196
  private assertJetStream;
2174
2197
  /** @internal */
2175
2198
  get shouldRetry(): boolean;
@@ -2185,7 +2208,7 @@ declare class RpcContext extends BaseRpcContext<[NatsMessage]> {
2185
2208
  * Health indicator result compatible with @nestjs/terminus.
2186
2209
  *
2187
2210
  * Follows the Terminus convention: returns status object on success,
2188
- * throws on failure. Works with Terminus out of the box no wrapper needed:
2211
+ * throws on failure. Works with Terminus out of the box, no wrapper needed:
2189
2212
  *
2190
2213
  * @example
2191
2214
  * ```typescript
@@ -2215,7 +2238,7 @@ declare class JetstreamHealthIndicator {
2215
2238
  * Returns `{ [key]: { status: 'up', ... } }` on success.
2216
2239
  * Throws an error with `{ [key]: { status: 'down', ... } }` on failure.
2217
2240
  *
2218
- * The thrown error sets `isHealthCheckError: true` and `causes` the
2241
+ * The thrown error sets `isHealthCheckError: true` and `causes`, the
2219
2242
  * duck-type contract that Terminus `HealthCheckExecutor` uses to distinguish
2220
2243
  * health failures from unexpected exceptions. Works with both Terminus v10
2221
2244
  * (`instanceof HealthCheckError`) and v11+ (`error?.isHealthCheckError`).
@@ -2326,7 +2349,7 @@ declare enum JetstreamHeader {
2326
2349
  Error = "x-error"
2327
2350
  }
2328
2351
  declare enum JetstreamDlqHeader {
2329
- /** Reason for the message being sent to the DLQ the last handler error message. */
2352
+ /** Reason the message was sent to the DLQ: the last handler error message. */
2330
2353
  DeadLetterReason = "x-dead-letter-reason",
2331
2354
  /** Original NATS subject the message was originally published to */
2332
2355
  OriginalSubject = "x-original-subject",
@@ -2346,14 +2369,6 @@ declare const RESERVED_HEADERS: Set<string>;
2346
2369
  * @returns `{name}__microservice`
2347
2370
  */
2348
2371
  declare const internalName: (name: string) => string;
2349
- /**
2350
- * Build a fully-qualified NATS subject for workqueue events, RPC commands, or ordered events.
2351
- *
2352
- * @param serviceName - Target service name.
2353
- * @param kind - Subject kind ({@link StreamKind.Event}, {@link StreamKind.Command}, or {@link StreamKind.Ordered}).
2354
- * @param pattern - The message pattern (e.g. `'user.created'`).
2355
- * @returns `{serviceName}__microservice.{kind}.{pattern}`
2356
- */
2357
2372
  declare const buildSubject: (serviceName: string, kind: SubjectKind, pattern: string) => string;
2358
2373
  /**
2359
2374
  * Build a broadcast subject.
@@ -2396,7 +2411,7 @@ declare enum PatternPrefix {
2396
2411
  Ordered = "ordered:"
2397
2412
  }
2398
2413
  /** Check if the RPC config specifies JetStream mode. */
2399
- declare const isJetStreamRpcMode: (rpc: RpcConfig | undefined) => boolean;
2414
+ declare const isJetStreamRpcMode: (rpc: RpcConfig | undefined) => rpc is JetStreamRpcConfig;
2400
2415
  /** Check if the RPC config specifies Core mode (default). */
2401
2416
  declare const isCoreRpcMode: (rpc: RpcConfig | undefined) => boolean;
2402
2417
 
@@ -2426,4 +2441,4 @@ declare class JetstreamProvisioningError extends Error {
2426
2441
  constructor(fields: ProvisioningErrorFields);
2427
2442
  }
2428
2443
 
2429
- export { type CaptureBodyOptions, type Codec, ConsumeKind, type ConsumeSourceMsg, DEFAULT_BROADCAST_CONSUMER_CONFIG, DEFAULT_BROADCAST_STREAM_CONFIG, DEFAULT_COMMAND_CONSUMER_CONFIG, DEFAULT_COMMAND_STREAM_CONFIG, DEFAULT_DLQ_STREAM_CONFIG, DEFAULT_EVENT_CONSUMER_CONFIG, DEFAULT_EVENT_STREAM_CONFIG, DEFAULT_JETSTREAM_RPC_TIMEOUT, DEFAULT_METADATA_BUCKET, DEFAULT_METADATA_HISTORY, DEFAULT_METADATA_REPLICAS, DEFAULT_METADATA_TTL, DEFAULT_ORDERED_STREAM_CONFIG, DEFAULT_RPC_TIMEOUT, DEFAULT_SHUTDOWN_TIMEOUT, DEFAULT_TRACES, type DeadLetterInfo, type ErrorClassification, type HandlerMetadata, JETSTREAM_CODEC, JETSTREAM_CONNECTION, JETSTREAM_OPTIONS, JetstreamClient, type JetstreamConsumeContext, JetstreamDlqHeader, type JetstreamFeatureOptions, JetstreamHeader, JetstreamHealthIndicator, type JetstreamHealthStatus, JetstreamModule, type JetstreamModuleAsyncOptions, type JetstreamModuleOptions, JetstreamProvisioningError, type JetstreamPublishContext, JetstreamRecord, JetstreamRecordBuilder, type JetstreamResponseContext, JetstreamStrategy, JetstreamTrace, JsonCodec, MIN_METADATA_TTL, MessageKind, type MetadataRegistryOptions, MsgpackCodec, NatsErrorCode, type OrderedEventOverrides, type OtelOptions, PatternPrefix, type ProvisioningOptions, PublishKind, RESERVED_HEADERS, type RpcConfig, RpcContext, type ScheduleRecordOptions, type ServerEndpoint, type StreamConfigOverrides, type StreamConsumerOverrides, StreamKind, TRACER_NAME, TransportEvent, type TransportHooks, buildBroadcastSubject, buildSubject, consumerName, dlqStreamName, getClientToken, internalName, isCoreRpcMode, isJetStreamRpcMode, metadataKey, streamName, toNanos };
2444
+ export { type CaptureBodyOptions, type Codec, ConsumeKind, type ConsumeSourceMsg, DEFAULT_BROADCAST_CONSUMER_CONFIG, DEFAULT_BROADCAST_STREAM_CONFIG, DEFAULT_COMMAND_CONSUMER_CONFIG, DEFAULT_COMMAND_STREAM_CONFIG, DEFAULT_DLQ_STREAM_CONFIG, DEFAULT_EVENT_CONSUMER_CONFIG, DEFAULT_EVENT_STREAM_CONFIG, DEFAULT_JETSTREAM_RPC_TIMEOUT, DEFAULT_METADATA_BUCKET, DEFAULT_METADATA_HISTORY, DEFAULT_METADATA_REPLICAS, DEFAULT_METADATA_TTL, DEFAULT_ORDERED_STREAM_CONFIG, DEFAULT_RPC_TIMEOUT, DEFAULT_SHUTDOWN_TIMEOUT, DEFAULT_TRACES, type DeadLetterInfo, type EntityManagement, type ErrorClassification, type HandlerMetadata, JETSTREAM_CODEC, JETSTREAM_CONNECTION, JETSTREAM_OPTIONS, JetstreamClient, type JetstreamConsumeContext, JetstreamDlqHeader, type JetstreamFeatureOptions, JetstreamHeader, JetstreamHealthIndicator, type JetstreamHealthStatus, JetstreamModule, type JetstreamModuleAsyncOptions, type JetstreamModuleOptions, JetstreamProvisioningError, type JetstreamPublishContext, JetstreamRecord, JetstreamRecordBuilder, type JetstreamResponseContext, JetstreamStrategy, JetstreamTrace, JsonCodec, MIN_METADATA_TTL, ManagementMode, MessageKind, type MetadataRegistryOptions, MsgpackCodec, NatsErrorCode, type OrderedEventOverrides, type OtelOptions, PatternPrefix, type ProvisioningOptions, PublishKind, RESERVED_HEADERS, type RpcConfig, RpcContext, type ScheduleRecordOptions, type ServerEndpoint, type StreamConfigOverrides, type StreamConsumerOverrides, StreamKind, TRACER_NAME, TransportEvent, type TransportHooks, buildBroadcastSubject, buildSubject, consumerName, dlqStreamName, getClientToken, internalName, isCoreRpcMode, isJetStreamRpcMode, metadataKey, streamName, toNanos };