@horizon-republic/nestjs-jetstream 2.12.1 → 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,42 +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: invoke onDeadLetter, then term on success. On failure the
1536
- * message is nak'd — never redelivered past max_deliver, but preserved.
1537
- */
1538
- private fallbackToOnDeadLetterCallback;
1539
- /**
1540
- * Copy headers for the DLQ republish, dropping NATS control headers — a
1541
- * copied Nats-TTL would expire the DLQ entry, Nats-Msg-Id trips dedup.
1542
- */
1543
- private buildDlqHeaders;
1544
- /**
1545
- * Past max_deliver the server never redelivers, so these in-process attempts
1546
- * are the only second chance a dead letter gets. No artificial delay — an
1547
- * unreachable broker already spaces attempts via its own request timeout.
1548
- */
1549
- private publishToDlqWithRetry;
1550
- /**
1551
- * Publish a dead letter to the configured Dead-Letter Queue (DLQ) stream.
1552
- *
1553
- * Appends diagnostic metadata headers to the original message and preserves
1554
- * the primary payload. If publishing succeeds, it notifies the standard
1555
- * `onDeadLetter` callback and terminates the message. If it fails, it falls
1556
- * back to the callback entirely to prevent silent data loss.
1557
- */
1558
- private publishToDlq;
1559
- /**
1560
- * Orchestrates the handling of a message that has exhausted delivery limits.
1561
- *
1562
- * Emits a system event and delegates either to the robust DLQ stream publisher
1563
- * or directly to the fallback callback based on the active module configuration.
1564
- */
1565
- private handleDeadLetter;
1566
1522
  }
1567
1523
 
1568
1524
  /**
@@ -1575,7 +1531,7 @@ declare class EventRouter {
1575
1531
  * - Timeout -> no response -> term
1576
1532
  * - No handler / decode error -> term immediately
1577
1533
  *
1578
- * Nak is never used for RPC prevents duplicate side effects.
1534
+ * Nak is never used for RPC; it would risk duplicate side effects.
1579
1535
  */
1580
1536
  declare class RpcRouter {
1581
1537
  private readonly messageProvider;
@@ -1603,6 +1559,108 @@ declare class RpcRouter {
1603
1559
  destroy(): void;
1604
1560
  }
1605
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
+
1606
1664
  /**
1607
1665
  * Manages JetStream consumer lifecycle: creation and idempotent ensures.
1608
1666
  *
@@ -1614,11 +1672,13 @@ declare class ConsumerProvider {
1614
1672
  private readonly connection;
1615
1673
  private readonly streamProvider;
1616
1674
  private readonly patternRegistry;
1675
+ private readonly names;
1676
+ private readonly binder;
1617
1677
  private readonly logger;
1618
1678
  private readonly otel;
1619
1679
  private readonly otelServiceName;
1620
1680
  private readonly otelEndpoint;
1621
- constructor(options: JetstreamModuleOptions, connection: ConnectionProvider, streamProvider: StreamProvider, patternRegistry: PatternRegistry);
1681
+ constructor(options: JetstreamModuleOptions, connection: ConnectionProvider, streamProvider: StreamProvider, patternRegistry: PatternRegistry, names: NameResolver, binder: InfrastructureBinder);
1622
1682
  /**
1623
1683
  * Ensure consumers exist for the specified kinds.
1624
1684
  *
@@ -1629,22 +1689,16 @@ declare class ConsumerProvider {
1629
1689
  getConsumerName(kind: StreamKind): string;
1630
1690
  /**
1631
1691
  * Ensure a single consumer exists with the desired config.
1632
- * Used at **startup** — creates or updates the consumer to match
1633
- * the current pod's configuration.
1692
+ * Startup path: creates or updates the consumer to match the current pod's configuration.
1634
1693
  */
1635
1694
  ensureConsumer(jsm: Awaited<ReturnType<ConnectionProvider['getJetStreamManager']>>, kind: StreamKind): Promise<ConsumerInfo>;
1636
1695
  /**
1637
1696
  * Recover a consumer that disappeared during runtime.
1638
- * Used by **self-healing** — creates if missing, but NEVER updates config.
1639
- *
1640
- * If a migration backup stream exists, another pod is mid-migration — we
1641
- * throw so the self-healing retry loop waits with backoff until migration
1642
- * completes and the backup is cleaned up.
1643
1697
  *
1644
- * This prevents old pods from:
1645
- * - Overwriting a newer pod's consumer config during rolling updates
1646
- * - Creating consumers during migration (which would consume and delete
1647
- * 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.
1648
1702
  */
1649
1703
  recoverConsumer(jsm: Awaited<ReturnType<ConnectionProvider['getJetStreamManager']>>, kind: StreamKind): Promise<ConsumerInfo>;
1650
1704
  /**
@@ -1653,13 +1707,12 @@ declare class ConsumerProvider {
1653
1707
  * naturally waiting until the migrating pod finishes and cleans up the backup.
1654
1708
  */
1655
1709
  private assertNoMigrationInProgress;
1656
- /**
1657
- * Create a consumer, handling the race where another pod creates it first.
1658
- */
1710
+ /** Create a consumer, handling the race where another pod creates it first. */
1659
1711
  private createConsumer;
1660
1712
  private runConsumerOp;
1661
1713
  /** Build consumer config by merging defaults with user overrides. */
1662
1714
  private buildConfig;
1715
+ private buildCustomPrefixConfig;
1663
1716
  /** Get default config for a consumer kind. */
1664
1717
  private getDefaults;
1665
1718
  /** Get user-provided overrides for a consumer kind. */
@@ -1710,7 +1763,7 @@ declare class MessageProvider {
1710
1763
  /**
1711
1764
  * Start an ordered consumer for strict sequential delivery.
1712
1765
  *
1713
- * Unlike durable consumers, ordered consumers are ephemeral created at
1766
+ * Unlike durable consumers, ordered consumers are ephemeral: created at
1714
1767
  * consumption time, no durable state. nats.js handles auto-recreation.
1715
1768
  *
1716
1769
  * @param streamName - JetStream stream to consume from.
@@ -1747,13 +1800,9 @@ declare class MessageProvider {
1747
1800
  /**
1748
1801
  * Publishes handler metadata to a NATS KV bucket for external service discovery.
1749
1802
  *
1750
- * Uses TTL + heartbeat to manage entry lifecycle:
1751
- * - Entries are written on startup and refreshed every `ttl / 2`
1752
- * - When the pod stops (graceful or crash), heartbeat stops → entries expire via TTL
1753
- * - No explicit delete needed — NATS handles expiry automatically
1754
- *
1755
- * This provider is fully decoupled from stream/consumer infrastructure —
1756
- * 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.
1757
1806
  */
1758
1807
  declare class MetadataProvider {
1759
1808
  private readonly connection;
@@ -1766,16 +1815,12 @@ declare class MetadataProvider {
1766
1815
  private cachedKv?;
1767
1816
  constructor(options: JetstreamModuleOptions, connection: ConnectionProvider);
1768
1817
  /**
1769
- * Write handler metadata entries to the KV bucket and start heartbeat.
1770
- *
1771
- * Creates the bucket if it doesn't exist (idempotent).
1772
- * Skips silently when entries map is empty.
1773
- * Starts a heartbeat interval that refreshes entries every `ttl / 2`
1774
- * to prevent TTL expiry while the pod is alive.
1818
+ * Write handler metadata entries to the KV bucket and start the heartbeat.
1775
1819
  *
1776
- * 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.
1777
1822
  *
1778
- * @param entries Map of KV key metadata object.
1823
+ * @param entries Map of KV key to metadata object.
1779
1824
  */
1780
1825
  publish(entries: Map<string, Record<string, unknown>>): Promise<void>;
1781
1826
  /**
@@ -1799,7 +1844,7 @@ declare class MetadataProvider {
1799
1844
  * NATS JetStream API error codes used by the transport.
1800
1845
  *
1801
1846
  * Ref: https://github.com/nats-io/nats-server (server error definitions)
1802
- * 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).
1803
1848
  */
1804
1849
  declare enum NatsErrorCode {
1805
1850
  /** Consumer does not exist on the specified stream. */
@@ -1808,7 +1853,7 @@ declare enum NatsErrorCode {
1808
1853
  ConsumerAlreadyExists = 10148,
1809
1854
  /** Stream does not exist. */
1810
1855
  StreamNotFound = 10059,
1811
- /** Storage resources exceeded reservation exceeds server `max_file_store`. */
1856
+ /** Storage resources exceeded: reservation exceeds server `max_file_store`. */
1812
1857
  StorageResourcesExceeded = 10047,
1813
1858
  /**
1814
1859
  * No suitable peers for placement (fewer healthy peers than `num_replicas`,
@@ -1820,13 +1865,8 @@ declare enum NatsErrorCode {
1820
1865
  /**
1821
1866
  * NestJS custom transport strategy for NATS JetStream.
1822
1867
  *
1823
- * Coordinates all server-side providers:
1824
- * 1. Registers handlers from NestJS into PatternRegistry
1825
- * 2. Creates required streams and consumers
1826
- * 3. Starts message consumption and routing
1827
- * 4. Handles Core or JetStream RPC based on configuration
1828
- *
1829
- * 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).
1830
1870
  */
1831
1871
  declare class JetstreamStrategy extends Server implements CustomTransportStrategy {
1832
1872
  private readonly options;
@@ -1853,23 +1893,14 @@ declare class JetstreamStrategy extends Server implements CustomTransportStrateg
1853
1893
  /** Stop all consumers, routers, subscriptions, and metadata heartbeat. Called during shutdown. */
1854
1894
  close(): void;
1855
1895
  /**
1856
- * Override NestJS `Server.addHandler` to fail-fast on duplicate pattern registration.
1896
+ * Override NestJS `Server.addHandler` to fail fast on duplicate pattern registration.
1857
1897
  *
1858
- * The base class silently overwrites duplicate RPC handlers (last wins) and appends
1859
- * duplicate event handlers to a linked list. Both behaviors are hazardous in a
1860
- * JetStream context: silent overwrite drops a handler the user wrote, and double
1861
- * event dispatch double-acks/double-processes the same JetStream message.
1862
- *
1863
- * We treat any pattern collision as a fatal misconfiguration so it surfaces at
1864
- * 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.
1865
1901
  */
1866
1902
  addHandler(pattern: unknown, callback: MessageHandler, isEventHandler?: boolean, extras?: Record<string, unknown>): void;
1867
- /**
1868
- * Register event listener (required by Server base class).
1869
- *
1870
- * Stores callbacks for client use. Primary lifecycle events
1871
- * are routed through EventBus.
1872
- */
1903
+ /** Register event listener (required by Server base class); lifecycle events use EventBus. */
1873
1904
  on(event: string, callback: Function): void;
1874
1905
  /**
1875
1906
  * Unwrap the underlying NATS connection.
@@ -1904,7 +1935,7 @@ interface Stoppable {
1904
1935
  * 3. Drain and close NATS connection (with timeout safety net)
1905
1936
  * 4. Emit onShutdownComplete hook
1906
1937
  *
1907
- * Idempotent concurrent or repeated calls return the same promise.
1938
+ * Idempotent: concurrent or repeated calls return the same promise.
1908
1939
  * This is critical because NestJS may call `onApplicationShutdown` on
1909
1940
  * multiple module instances (forRoot + forFeature) that share this
1910
1941
  * singleton, and the call order is not guaranteed.
@@ -1919,7 +1950,7 @@ declare class ShutdownManager {
1919
1950
  /**
1920
1951
  * Execute the full shutdown sequence.
1921
1952
  *
1922
- * Idempotent concurrent or repeated calls return the same promise.
1953
+ * Idempotent: concurrent or repeated calls return the same promise.
1923
1954
  *
1924
1955
  * @param strategy Optional stoppable to close (stops consumers and subscriptions).
1925
1956
  */
@@ -1930,16 +1961,16 @@ declare class ShutdownManager {
1930
1961
  /**
1931
1962
  * Root module for the NestJS JetStream transport.
1932
1963
  *
1933
- * - `forRoot()` / `forRootAsync()` registers once in AppModule.
1964
+ * - `forRoot()` / `forRootAsync()`: registers once in AppModule.
1934
1965
  * Creates shared NATS connection, codec, event bus, and optionally
1935
1966
  * the consumer infrastructure.
1936
1967
  *
1937
- * - `forFeature()` registers in feature modules.
1968
+ * - `forFeature()`: registers in feature modules.
1938
1969
  * Creates a lightweight client proxy targeting a specific service.
1939
1970
  *
1940
1971
  * @example
1941
1972
  * ```typescript
1942
- * // AppModule global setup
1973
+ * // AppModule: global setup
1943
1974
  * @Module({
1944
1975
  * imports: [
1945
1976
  * JetstreamModule.forRoot({
@@ -1950,7 +1981,7 @@ declare class ShutdownManager {
1950
1981
  * })
1951
1982
  * export class AppModule {}
1952
1983
  *
1953
- * // Feature module per-service clients
1984
+ * // Feature module: per-service clients
1954
1985
  * @Module({
1955
1986
  * imports: [
1956
1987
  * JetstreamModule.forFeature({ name: 'users' }),
@@ -2037,7 +2068,7 @@ interface PackrLike {
2037
2068
  * MessagePack codec backed by a caller-provided `msgpackr` `Packr` instance.
2038
2069
  *
2039
2070
  * Use this codec when publishing structured payloads larger than roughly
2040
- * 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
2041
2072
  * constant overhead. Above it, MessagePack encodes and decodes several times
2042
2073
  * faster and produces smaller wire frames. The format is cross-language, so
2043
2074
  * Node producers and non-Node consumers (Python, Go, Java, Rust, ...) stay
@@ -2161,7 +2192,7 @@ declare class RpcContext extends BaseRpcContext<[NatsMessage]> {
2161
2192
  terminate(reason?: string): void;
2162
2193
  /** Narrow to JsMsg or return null for Core messages. Used by metadata getters. */
2163
2194
  private asJetStream;
2164
- /** 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. */
2165
2196
  private assertJetStream;
2166
2197
  /** @internal */
2167
2198
  get shouldRetry(): boolean;
@@ -2177,7 +2208,7 @@ declare class RpcContext extends BaseRpcContext<[NatsMessage]> {
2177
2208
  * Health indicator result compatible with @nestjs/terminus.
2178
2209
  *
2179
2210
  * Follows the Terminus convention: returns status object on success,
2180
- * 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:
2181
2212
  *
2182
2213
  * @example
2183
2214
  * ```typescript
@@ -2207,7 +2238,7 @@ declare class JetstreamHealthIndicator {
2207
2238
  * Returns `{ [key]: { status: 'up', ... } }` on success.
2208
2239
  * Throws an error with `{ [key]: { status: 'down', ... } }` on failure.
2209
2240
  *
2210
- * The thrown error sets `isHealthCheckError: true` and `causes` the
2241
+ * The thrown error sets `isHealthCheckError: true` and `causes`, the
2211
2242
  * duck-type contract that Terminus `HealthCheckExecutor` uses to distinguish
2212
2243
  * health failures from unexpected exceptions. Works with both Terminus v10
2213
2244
  * (`instanceof HealthCheckError`) and v11+ (`error?.isHealthCheckError`).
@@ -2318,7 +2349,7 @@ declare enum JetstreamHeader {
2318
2349
  Error = "x-error"
2319
2350
  }
2320
2351
  declare enum JetstreamDlqHeader {
2321
- /** 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. */
2322
2353
  DeadLetterReason = "x-dead-letter-reason",
2323
2354
  /** Original NATS subject the message was originally published to */
2324
2355
  OriginalSubject = "x-original-subject",
@@ -2338,14 +2369,6 @@ declare const RESERVED_HEADERS: Set<string>;
2338
2369
  * @returns `{name}__microservice`
2339
2370
  */
2340
2371
  declare const internalName: (name: string) => string;
2341
- /**
2342
- * Build a fully-qualified NATS subject for workqueue events, RPC commands, or ordered events.
2343
- *
2344
- * @param serviceName - Target service name.
2345
- * @param kind - Subject kind ({@link StreamKind.Event}, {@link StreamKind.Command}, or {@link StreamKind.Ordered}).
2346
- * @param pattern - The message pattern (e.g. `'user.created'`).
2347
- * @returns `{serviceName}__microservice.{kind}.{pattern}`
2348
- */
2349
2372
  declare const buildSubject: (serviceName: string, kind: SubjectKind, pattern: string) => string;
2350
2373
  /**
2351
2374
  * Build a broadcast subject.
@@ -2388,7 +2411,7 @@ declare enum PatternPrefix {
2388
2411
  Ordered = "ordered:"
2389
2412
  }
2390
2413
  /** Check if the RPC config specifies JetStream mode. */
2391
- declare const isJetStreamRpcMode: (rpc: RpcConfig | undefined) => boolean;
2414
+ declare const isJetStreamRpcMode: (rpc: RpcConfig | undefined) => rpc is JetStreamRpcConfig;
2392
2415
  /** Check if the RPC config specifies Core mode (default). */
2393
2416
  declare const isCoreRpcMode: (rpc: RpcConfig | undefined) => boolean;
2394
2417
 
@@ -2418,4 +2441,4 @@ declare class JetstreamProvisioningError extends Error {
2418
2441
  constructor(fields: ProvisioningErrorFields);
2419
2442
  }
2420
2443
 
2421
- 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 };