@horizon-republic/nestjs-jetstream 2.7.0 → 2.8.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.cjs CHANGED
@@ -47,9 +47,13 @@ __export(index_exports, {
47
47
  RpcContext: () => RpcContext,
48
48
  StreamKind: () => StreamKind,
49
49
  TransportEvent: () => TransportEvent,
50
+ buildSubject: () => buildSubject,
51
+ consumerName: () => consumerName,
50
52
  getClientToken: () => getClientToken,
53
+ internalName: () => internalName,
51
54
  isCoreRpcMode: () => isCoreRpcMode,
52
55
  isJetStreamRpcMode: () => isJetStreamRpcMode,
56
+ streamName: () => streamName,
53
57
  toNanos: () => toNanos
54
58
  });
55
59
  module.exports = __toCommonJS(index_exports);
@@ -60,7 +64,8 @@ var import_common12 = require("@nestjs/common");
60
64
  // src/client/jetstream.client.ts
61
65
  var import_common = require("@nestjs/common");
62
66
  var import_microservices = require("@nestjs/microservices");
63
- var import_nats2 = require("nats");
67
+ var import_transport_node = require("@nats-io/transport-node");
68
+ var import_nuid = require("@nats-io/nuid");
64
69
 
65
70
  // src/interfaces/hooks.interface.ts
66
71
  var MessageKind = /* @__PURE__ */ ((MessageKind2) => {
@@ -91,7 +96,7 @@ var StreamKind = /* @__PURE__ */ ((StreamKind2) => {
91
96
  })(StreamKind || {});
92
97
 
93
98
  // src/jetstream.constants.ts
94
- var import_nats = require("nats");
99
+ var import_jetstream = require("@nats-io/jetstream");
95
100
  var JETSTREAM_OPTIONS = /* @__PURE__ */ Symbol("JETSTREAM_OPTIONS");
96
101
  var JETSTREAM_CONNECTION = /* @__PURE__ */ Symbol("JETSTREAM_CONNECTION");
97
102
  var JETSTREAM_CODEC = /* @__PURE__ */ Symbol("JETSTREAM_CODEC");
@@ -109,12 +114,12 @@ var NANOS_PER = {
109
114
  };
110
115
  var toNanos = (value, unit) => value * NANOS_PER[unit];
111
116
  var baseStreamConfig = {
112
- retention: import_nats.RetentionPolicy.Workqueue,
113
- storage: import_nats.StorageType.File,
117
+ retention: import_jetstream.RetentionPolicy.Workqueue,
118
+ storage: import_jetstream.StorageType.File,
114
119
  num_replicas: 1,
115
- discard: import_nats.DiscardPolicy.Old,
120
+ discard: import_jetstream.DiscardPolicy.Old,
116
121
  allow_direct: true,
117
- compression: import_nats.StoreCompression.S2
122
+ compression: import_jetstream.StoreCompression.S2
118
123
  };
119
124
  var DEFAULT_EVENT_STREAM_CONFIG = {
120
125
  ...baseStreamConfig,
@@ -140,7 +145,7 @@ var DEFAULT_COMMAND_STREAM_CONFIG = {
140
145
  };
141
146
  var DEFAULT_BROADCAST_STREAM_CONFIG = {
142
147
  ...baseStreamConfig,
143
- retention: import_nats.RetentionPolicy.Limits,
148
+ retention: import_jetstream.RetentionPolicy.Limits,
144
149
  allow_rollup_hdrs: true,
145
150
  max_consumers: 200,
146
151
  max_msg_size: 10 * MB,
@@ -152,7 +157,7 @@ var DEFAULT_BROADCAST_STREAM_CONFIG = {
152
157
  };
153
158
  var DEFAULT_ORDERED_STREAM_CONFIG = {
154
159
  ...baseStreamConfig,
155
- retention: import_nats.RetentionPolicy.Limits,
160
+ retention: import_jetstream.RetentionPolicy.Limits,
156
161
  allow_rollup_hdrs: false,
157
162
  max_consumers: 100,
158
163
  max_msg_size: 10 * MB,
@@ -166,25 +171,25 @@ var DEFAULT_EVENT_CONSUMER_CONFIG = {
166
171
  ack_wait: toNanos(10, "seconds"),
167
172
  max_deliver: 3,
168
173
  max_ack_pending: 100,
169
- ack_policy: import_nats.AckPolicy.Explicit,
170
- deliver_policy: import_nats.DeliverPolicy.All,
171
- replay_policy: import_nats.ReplayPolicy.Instant
174
+ ack_policy: import_jetstream.AckPolicy.Explicit,
175
+ deliver_policy: import_jetstream.DeliverPolicy.All,
176
+ replay_policy: import_jetstream.ReplayPolicy.Instant
172
177
  };
173
178
  var DEFAULT_COMMAND_CONSUMER_CONFIG = {
174
179
  ack_wait: toNanos(5, "minutes"),
175
180
  max_deliver: 1,
176
181
  max_ack_pending: 100,
177
- ack_policy: import_nats.AckPolicy.Explicit,
178
- deliver_policy: import_nats.DeliverPolicy.All,
179
- replay_policy: import_nats.ReplayPolicy.Instant
182
+ ack_policy: import_jetstream.AckPolicy.Explicit,
183
+ deliver_policy: import_jetstream.DeliverPolicy.All,
184
+ replay_policy: import_jetstream.ReplayPolicy.Instant
180
185
  };
181
186
  var DEFAULT_BROADCAST_CONSUMER_CONFIG = {
182
187
  ack_wait: toNanos(10, "seconds"),
183
188
  max_deliver: 3,
184
189
  max_ack_pending: 100,
185
- ack_policy: import_nats.AckPolicy.Explicit,
186
- deliver_policy: import_nats.DeliverPolicy.All,
187
- replay_policy: import_nats.ReplayPolicy.Instant
190
+ ack_policy: import_jetstream.AckPolicy.Explicit,
191
+ deliver_policy: import_jetstream.DeliverPolicy.All,
192
+ replay_policy: import_jetstream.ReplayPolicy.Instant
188
193
  };
189
194
  var DEFAULT_RPC_TIMEOUT = 3e4;
190
195
  var DEFAULT_JETSTREAM_RPC_TIMEOUT = 18e4;
@@ -223,11 +228,12 @@ var isCoreRpcMode = (rpc) => !rpc || rpc.mode === "core";
223
228
 
224
229
  // src/client/jetstream.record.ts
225
230
  var JetstreamRecord = class {
226
- constructor(data, headers2, timeout, messageId) {
231
+ constructor(data, headers2, timeout, messageId, schedule) {
227
232
  this.data = data;
228
233
  this.headers = headers2;
229
234
  this.timeout = timeout;
230
235
  this.messageId = messageId;
236
+ this.schedule = schedule;
231
237
  }
232
238
  };
233
239
  var JetstreamRecordBuilder = class {
@@ -235,6 +241,7 @@ var JetstreamRecordBuilder = class {
235
241
  headers = /* @__PURE__ */ new Map();
236
242
  timeout;
237
243
  messageId;
244
+ scheduleOptions;
238
245
  constructor(data) {
239
246
  this.data = data;
240
247
  }
@@ -302,17 +309,43 @@ var JetstreamRecordBuilder = class {
302
309
  this.timeout = ms;
303
310
  return this;
304
311
  }
312
+ /**
313
+ * Schedule one-shot delayed delivery.
314
+ *
315
+ * The message is held by NATS and delivered to the event consumer
316
+ * at the specified time. Requires NATS >= 2.12 and `allow_msg_schedules: true`
317
+ * on the event stream (via `events: { stream: { allow_msg_schedules: true } }`).
318
+ *
319
+ * Only meaningful for events (`client.emit()`). If used with RPC
320
+ * (`client.send()`), a warning is logged and the schedule is ignored.
321
+ *
322
+ * @param date - Delivery time. Must be in the future.
323
+ * @throws Error if the date is not in the future.
324
+ */
325
+ scheduleAt(date) {
326
+ const ts = date.getTime();
327
+ if (Number.isNaN(ts)) {
328
+ throw new Error("Schedule date is invalid");
329
+ }
330
+ if (ts <= Date.now()) {
331
+ throw new Error("Schedule date must be in the future");
332
+ }
333
+ this.scheduleOptions = { at: new Date(ts) };
334
+ return this;
335
+ }
305
336
  /**
306
337
  * Build the immutable {@link JetstreamRecord}.
307
338
  *
308
339
  * @returns A frozen record ready to pass to `client.send()` or `client.emit()`.
309
340
  */
310
341
  build() {
342
+ const schedule = this.scheduleOptions ? { at: new Date(this.scheduleOptions.at.getTime()) } : void 0;
311
343
  return new JetstreamRecord(
312
344
  this.data,
313
345
  new Map(this.headers),
314
346
  this.timeout,
315
- this.messageId
347
+ this.messageId,
348
+ schedule
316
349
  );
317
350
  }
318
351
  /** Validate that a header key is not reserved. */
@@ -364,7 +397,7 @@ var JetstreamClient = class extends import_microservices.ClientProxy {
364
397
  this.setupInbox(nc);
365
398
  }
366
399
  this.statusSubscription ??= this.connection.status$.subscribe((status) => {
367
- if (status.type === import_nats2.Events.Disconnect) {
400
+ if (status.type === "disconnect") {
368
401
  this.handleDisconnect();
369
402
  }
370
403
  });
@@ -392,19 +425,38 @@ var JetstreamClient = class extends import_microservices.ClientProxy {
392
425
  * Publish a fire-and-forget event to JetStream.
393
426
  *
394
427
  * Events are published to either the workqueue stream or broadcast stream
395
- * depending on the subject prefix.
428
+ * depending on the subject prefix. When a schedule is present the message
429
+ * is published to a `_sch` subject within the same stream, with the target
430
+ * set to the original event subject.
396
431
  */
397
432
  async dispatchEvent(packet) {
398
433
  await this.connect();
399
- const { data, hdrs, messageId } = this.extractRecordData(packet.data);
400
- const subject = this.buildEventSubject(packet.pattern);
401
- const msgHeaders = this.buildHeaders(hdrs, { subject });
402
- const ack = await this.connection.getJetStreamClient().publish(subject, this.codec.encode(data), {
403
- headers: msgHeaders,
404
- msgID: messageId ?? crypto.randomUUID()
405
- });
406
- if (ack.duplicate) {
407
- this.logger.warn(`Duplicate event publish detected: ${subject} (seq: ${ack.seq})`);
434
+ const { data, hdrs, messageId, schedule } = this.extractRecordData(packet.data);
435
+ const eventSubject = this.buildEventSubject(packet.pattern);
436
+ const msgHeaders = this.buildHeaders(hdrs, { subject: eventSubject });
437
+ if (schedule) {
438
+ const scheduleSubject = this.buildScheduleSubject(eventSubject);
439
+ const ack = await this.connection.getJetStreamClient().publish(scheduleSubject, this.codec.encode(data), {
440
+ headers: msgHeaders,
441
+ msgID: messageId ?? import_nuid.nuid.next(),
442
+ schedule: {
443
+ specification: schedule.at,
444
+ target: eventSubject
445
+ }
446
+ });
447
+ if (ack.duplicate) {
448
+ this.logger.warn(
449
+ `Duplicate scheduled publish detected: ${scheduleSubject} (seq: ${ack.seq})`
450
+ );
451
+ }
452
+ } else {
453
+ const ack = await this.connection.getJetStreamClient().publish(eventSubject, this.codec.encode(data), {
454
+ headers: msgHeaders,
455
+ msgID: messageId ?? import_nuid.nuid.next()
456
+ });
457
+ if (ack.duplicate) {
458
+ this.logger.warn(`Duplicate event publish detected: ${eventSubject} (seq: ${ack.seq})`);
459
+ }
408
460
  }
409
461
  return void 0;
410
462
  }
@@ -416,7 +468,12 @@ var JetstreamClient = class extends import_microservices.ClientProxy {
416
468
  */
417
469
  publish(packet, callback) {
418
470
  const subject = buildSubject(this.targetName, "cmd" /* Command */, packet.pattern);
419
- const { data, hdrs, timeout, messageId } = this.extractRecordData(packet.data);
471
+ const { data, hdrs, timeout, messageId, schedule } = this.extractRecordData(packet.data);
472
+ if (schedule) {
473
+ this.logger.warn(
474
+ "scheduleAt() is ignored for RPC (client.send()). Use client.emit() for scheduled events."
475
+ );
476
+ }
420
477
  const onUnhandled = (err) => {
421
478
  this.logger.error("Unhandled publish error:", err);
422
479
  callback({ err: new Error("Internal transport error"), response: null, isDisposed: true });
@@ -425,7 +482,7 @@ var JetstreamClient = class extends import_microservices.ClientProxy {
425
482
  if (isCoreRpcMode(this.rootOptions.rpc)) {
426
483
  this.publishCoreRpc(subject, data, hdrs, timeout, callback).catch(onUnhandled);
427
484
  } else {
428
- jetStreamCorrelationId = crypto.randomUUID();
485
+ jetStreamCorrelationId = import_nuid.nuid.next();
429
486
  this.publishJetStreamRpc(subject, data, callback, {
430
487
  headers: hdrs,
431
488
  timeout,
@@ -500,7 +557,7 @@ var JetstreamClient = class extends import_microservices.ClientProxy {
500
557
  });
501
558
  await this.connection.getJetStreamClient().publish(subject, this.codec.encode(data), {
502
559
  headers: hdrs,
503
- msgID: messageId ?? crypto.randomUUID()
560
+ msgID: messageId ?? import_nuid.nuid.next()
504
561
  });
505
562
  } catch (err) {
506
563
  const existingTimeout = this.pendingTimeouts.get(correlationId);
@@ -535,7 +592,7 @@ var JetstreamClient = class extends import_microservices.ClientProxy {
535
592
  }
536
593
  /** Setup shared inbox subscription for JetStream RPC responses. */
537
594
  setupInbox(nc) {
538
- this.inbox = (0, import_nats2.createInbox)(internalName(this.rootOptions.name));
595
+ this.inbox = (0, import_transport_node.createInbox)(internalName(this.rootOptions.name));
539
596
  this.inboxSubscription = nc.subscribe(this.inbox, {
540
597
  callback: (err, msg) => {
541
598
  if (err) {
@@ -597,7 +654,7 @@ var JetstreamClient = class extends import_microservices.ClientProxy {
597
654
  }
598
655
  /** Build NATS headers merging custom headers with transport headers. */
599
656
  buildHeaders(customHeaders, transport) {
600
- const hdrs = (0, import_nats2.headers)();
657
+ const hdrs = (0, import_transport_node.headers)();
601
658
  hdrs.set("x-subject" /* Subject */, transport.subject);
602
659
  hdrs.set("x-caller-name" /* CallerName */, this.callerName);
603
660
  if (transport.correlationId) {
@@ -613,17 +670,51 @@ var JetstreamClient = class extends import_microservices.ClientProxy {
613
670
  }
614
671
  return hdrs;
615
672
  }
616
- /** Extract data, headers, and timeout from raw packet data or JetstreamRecord. */
673
+ /** Extract data, headers, timeout, and schedule from raw packet data or JetstreamRecord. */
617
674
  extractRecordData(rawData) {
618
675
  if (rawData instanceof JetstreamRecord) {
619
676
  return {
620
677
  data: rawData.data,
621
678
  hdrs: rawData.headers.size > 0 ? new Map(rawData.headers) : null,
622
679
  timeout: rawData.timeout,
623
- messageId: rawData.messageId
680
+ messageId: rawData.messageId,
681
+ schedule: rawData.schedule
624
682
  };
625
683
  }
626
- return { data: rawData, hdrs: null, timeout: void 0, messageId: void 0 };
684
+ return {
685
+ data: rawData,
686
+ hdrs: null,
687
+ timeout: void 0,
688
+ messageId: void 0,
689
+ schedule: void 0
690
+ };
691
+ }
692
+ /**
693
+ * Build a schedule-holder subject for NATS message scheduling.
694
+ *
695
+ * The schedule-holder subject resides in the same stream as the target but
696
+ * uses a separate `_sch` namespace that is NOT matched by any consumer filter.
697
+ * NATS holds the message and publishes it to the target subject after the delay.
698
+ *
699
+ * Examples:
700
+ * - `{svc}__microservice.ev.order.reminder` → `{svc}__microservice._sch.order.reminder`
701
+ * - `broadcast.config.updated` → `broadcast._sch.config.updated`
702
+ */
703
+ buildScheduleSubject(eventSubject) {
704
+ if (eventSubject.startsWith("broadcast.")) {
705
+ return eventSubject.replace("broadcast.", "broadcast._sch.");
706
+ }
707
+ const targetPrefix = `${internalName(this.targetName)}.`;
708
+ if (!eventSubject.startsWith(targetPrefix)) {
709
+ throw new Error(`Unexpected event subject format: ${eventSubject}`);
710
+ }
711
+ const withoutPrefix = eventSubject.slice(targetPrefix.length);
712
+ const dotIndex = withoutPrefix.indexOf(".");
713
+ if (dotIndex === -1) {
714
+ throw new Error(`Event subject missing pattern segment: ${eventSubject}`);
715
+ }
716
+ const pattern = withoutPrefix.slice(dotIndex + 1);
717
+ return `${targetPrefix}_sch.${pattern}`;
627
718
  }
628
719
  getRpcTimeout() {
629
720
  if (!this.rootOptions.rpc) return DEFAULT_RPC_TIMEOUT;
@@ -633,20 +724,21 @@ var JetstreamClient = class extends import_microservices.ClientProxy {
633
724
  };
634
725
 
635
726
  // src/codec/json.codec.ts
636
- var import_nats3 = require("nats");
727
+ var encoder = new TextEncoder();
728
+ var decoder = new TextDecoder();
637
729
  var JsonCodec = class {
638
- inner = (0, import_nats3.JSONCodec)();
639
730
  encode(data) {
640
- return this.inner.encode(data);
731
+ return encoder.encode(JSON.stringify(data));
641
732
  }
642
733
  decode(data) {
643
- return this.inner.decode(data);
734
+ return JSON.parse(decoder.decode(data));
644
735
  }
645
736
  };
646
737
 
647
738
  // src/connection/connection.provider.ts
648
739
  var import_common2 = require("@nestjs/common");
649
- var import_nats4 = require("nats");
740
+ var import_transport_node2 = require("@nats-io/transport-node");
741
+ var import_jetstream7 = require("@nats-io/jetstream");
650
742
  var import_rxjs = require("rxjs");
651
743
  var DEFAULT_OPTIONS = {
652
744
  maxReconnectAttempts: -1,
@@ -700,14 +792,7 @@ var ConnectionProvider = class {
700
792
  async getJetStreamManager() {
701
793
  if (this.jsmInstance) return this.jsmInstance;
702
794
  if (this.jsmPromise) return this.jsmPromise;
703
- this.jsmPromise = (async () => {
704
- const nc = await this.getConnection();
705
- this.jsmInstance = await nc.jetstreamManager();
706
- this.logger.log("JetStream manager initialized");
707
- return this.jsmInstance;
708
- })().finally(() => {
709
- this.jsmPromise = null;
710
- });
795
+ this.jsmPromise = this.initJetStreamManager();
711
796
  return this.jsmPromise;
712
797
  }
713
798
  /**
@@ -723,7 +808,7 @@ var ConnectionProvider = class {
723
808
  if (!this.connection || this.connection.isClosed()) {
724
809
  throw new Error("Not connected \u2014 call getConnection() before getJetStreamClient()");
725
810
  }
726
- this.jsClient ??= this.connection.jetstream();
811
+ this.jsClient ??= (0, import_jetstream7.jetstream)(this.connection);
727
812
  return this.jsClient;
728
813
  }
729
814
  /** Direct access to the raw NATS connection, or `null` if not yet connected. */
@@ -759,11 +844,21 @@ var ConnectionProvider = class {
759
844
  this.jsmPromise = null;
760
845
  }
761
846
  }
847
+ async initJetStreamManager() {
848
+ try {
849
+ const nc = await this.getConnection();
850
+ this.jsmInstance = await (0, import_jetstream7.jetstreamManager)(nc);
851
+ this.logger.log("JetStream manager initialized");
852
+ return this.jsmInstance;
853
+ } finally {
854
+ this.jsmPromise = null;
855
+ }
856
+ }
762
857
  /** Internal: establish the physical connection with reconnect monitoring. */
763
858
  async establish() {
764
859
  const name = internalName(this.options.name);
765
860
  try {
766
- const nc = await (0, import_nats4.connect)({
861
+ const nc = await (0, import_transport_node2.connect)({
767
862
  ...DEFAULT_OPTIONS,
768
863
  ...this.options.connectionOptions,
769
864
  servers: this.options.servers,
@@ -775,7 +870,7 @@ var ConnectionProvider = class {
775
870
  this.monitorStatus(nc);
776
871
  return nc;
777
872
  } catch (err) {
778
- if (err instanceof import_nats4.NatsError && err.code === "CONNECTION_REFUSED") {
873
+ if (err instanceof Error && err.message.includes("REFUSED")) {
779
874
  throw new Error(`NATS connection refused: ${this.options.servers.join(", ")}`);
780
875
  }
781
876
  throw err;
@@ -783,27 +878,33 @@ var ConnectionProvider = class {
783
878
  }
784
879
  /** Subscribe to connection status events and emit hooks. */
785
880
  monitorStatus(nc) {
786
- (async () => {
881
+ void (async () => {
787
882
  for await (const status of nc.status()) {
788
883
  switch (status.type) {
789
- case import_nats4.Events.Disconnect:
884
+ case "disconnect":
790
885
  this.eventBus.emit("disconnect" /* Disconnect */);
791
886
  break;
792
- case import_nats4.Events.Reconnect:
887
+ case "reconnect":
793
888
  this.jsClient = null;
794
889
  this.jsmInstance = null;
795
890
  this.jsmPromise = null;
796
891
  this.eventBus.emit("reconnect" /* Reconnect */, nc.getServer());
797
892
  break;
798
- case import_nats4.Events.Error:
799
- this.eventBus.emit("error" /* Error */, new Error(String(status.data)), "connection");
893
+ case "error":
894
+ this.eventBus.emit(
895
+ "error" /* Error */,
896
+ status.error,
897
+ "connection"
898
+ );
800
899
  break;
801
- case import_nats4.Events.Update:
802
- case import_nats4.Events.LDM:
803
- case import_nats4.DebugEvents.Reconnecting:
804
- case import_nats4.DebugEvents.PingTimer:
805
- case import_nats4.DebugEvents.StaleConnection:
806
- case import_nats4.DebugEvents.ClientInitiatedReconnect:
900
+ case "update":
901
+ case "ldm":
902
+ case "reconnecting":
903
+ case "ping":
904
+ case "staleConnection":
905
+ case "forceReconnect":
906
+ case "slowConsumer":
907
+ case "close":
807
908
  break;
808
909
  }
809
910
  }
@@ -1065,7 +1166,7 @@ var JetstreamStrategy = class extends import_microservices2.Server {
1065
1166
 
1066
1167
  // src/server/core-rpc.server.ts
1067
1168
  var import_common4 = require("@nestjs/common");
1068
- var import_nats5 = require("nats");
1169
+ var import_transport_node3 = require("@nats-io/transport-node");
1069
1170
 
1070
1171
  // src/context/rpc.context.ts
1071
1172
  var import_microservices3 = require("@nestjs/microservices");
@@ -1351,7 +1452,7 @@ var CoreRpcServer = class {
1351
1452
  /** Send an error response back to the caller with x-error header. */
1352
1453
  respondWithError(msg, error) {
1353
1454
  try {
1354
- const hdrs = (0, import_nats5.headers)();
1455
+ const hdrs = (0, import_transport_node3.headers)();
1355
1456
  hdrs.set("x-error" /* Error */, "true");
1356
1457
  msg.respond(this.codec.encode(serializeError(error)), { headers: hdrs });
1357
1458
  } catch {
@@ -1362,7 +1463,7 @@ var CoreRpcServer = class {
1362
1463
 
1363
1464
  // src/server/infrastructure/stream.provider.ts
1364
1465
  var import_common5 = require("@nestjs/common");
1365
- var import_nats6 = require("nats");
1466
+ var import_jetstream13 = require("@nats-io/jetstream");
1366
1467
  var STREAM_NOT_FOUND = 10059;
1367
1468
  var StreamProvider = class {
1368
1469
  constructor(options, connection) {
@@ -1388,12 +1489,22 @@ var StreamProvider = class {
1388
1489
  getSubjects(kind) {
1389
1490
  const name = internalName(this.options.name);
1390
1491
  switch (kind) {
1391
- case "ev" /* Event */:
1392
- return [`${name}.${"ev" /* Event */}.>`];
1492
+ case "ev" /* Event */: {
1493
+ const subjects = [`${name}.${"ev" /* Event */}.>`];
1494
+ if (this.isSchedulingEnabled(kind)) {
1495
+ subjects.push(`${name}._sch.>`);
1496
+ }
1497
+ return subjects;
1498
+ }
1393
1499
  case "cmd" /* Command */:
1394
1500
  return [`${name}.${"cmd" /* Command */}.>`];
1395
- case "broadcast" /* Broadcast */:
1396
- return ["broadcast.>"];
1501
+ case "broadcast" /* Broadcast */: {
1502
+ const subjects = ["broadcast.>"];
1503
+ if (this.isSchedulingEnabled(kind)) {
1504
+ subjects.push("broadcast._sch.>");
1505
+ }
1506
+ return subjects;
1507
+ }
1397
1508
  case "ordered" /* Ordered */:
1398
1509
  return [`${name}.${"ordered" /* Ordered */}.>`];
1399
1510
  }
@@ -1407,7 +1518,7 @@ var StreamProvider = class {
1407
1518
  this.logger.debug(`Stream exists, updating: ${config.name}`);
1408
1519
  return await jsm.streams.update(config.name, config);
1409
1520
  } catch (err) {
1410
- if (err instanceof import_nats6.NatsError && err.api_error?.err_code === STREAM_NOT_FOUND) {
1521
+ if (err instanceof import_jetstream13.JetStreamApiError && err.apiError().err_code === STREAM_NOT_FOUND) {
1411
1522
  this.logger.log(`Creating stream: ${config.name}`);
1412
1523
  return await jsm.streams.add(config);
1413
1524
  }
@@ -1442,6 +1553,11 @@ var StreamProvider = class {
1442
1553
  return DEFAULT_ORDERED_STREAM_CONFIG;
1443
1554
  }
1444
1555
  }
1556
+ /** Check if scheduling is enabled for a stream kind via `allow_msg_schedules` override. */
1557
+ isSchedulingEnabled(kind) {
1558
+ const overrides = this.getOverrides(kind);
1559
+ return overrides.allow_msg_schedules === true;
1560
+ }
1445
1561
  /** Get user-provided overrides for a stream kind. */
1446
1562
  getOverrides(kind) {
1447
1563
  switch (kind) {
@@ -1459,7 +1575,7 @@ var StreamProvider = class {
1459
1575
 
1460
1576
  // src/server/infrastructure/consumer.provider.ts
1461
1577
  var import_common6 = require("@nestjs/common");
1462
- var import_nats7 = require("nats");
1578
+ var import_jetstream15 = require("@nats-io/jetstream");
1463
1579
  var CONSUMER_NOT_FOUND = 10014;
1464
1580
  var ConsumerProvider = class {
1465
1581
  constructor(options, connection, streamProvider, patternRegistry) {
@@ -1500,7 +1616,7 @@ var ConsumerProvider = class {
1500
1616
  this.logger.debug(`Consumer exists, updating: ${name}`);
1501
1617
  return await jsm.consumers.update(stream, name, config);
1502
1618
  } catch (err) {
1503
- if (err instanceof import_nats7.NatsError && err.api_error?.err_code === CONSUMER_NOT_FOUND) {
1619
+ if (err instanceof import_jetstream15.JetStreamApiError && err.apiError().err_code === CONSUMER_NOT_FOUND) {
1504
1620
  this.logger.log(`Creating consumer: ${name}`);
1505
1621
  return await jsm.consumers.add(stream, config);
1506
1622
  }
@@ -1559,6 +1675,10 @@ var ConsumerProvider = class {
1559
1675
  return DEFAULT_BROADCAST_CONSUMER_CONFIG;
1560
1676
  case "ordered" /* Ordered */:
1561
1677
  throw new Error("Ordered consumers are ephemeral and should not use durable config");
1678
+ default: {
1679
+ const _exhaustive = kind;
1680
+ throw new Error(`Unexpected StreamKind: ${_exhaustive}`);
1681
+ }
1562
1682
  }
1563
1683
  }
1564
1684
  /** Get user-provided overrides for a consumer kind. */
@@ -1572,13 +1692,17 @@ var ConsumerProvider = class {
1572
1692
  return this.options.broadcast?.consumer ?? {};
1573
1693
  case "ordered" /* Ordered */:
1574
1694
  throw new Error("Ordered consumers are ephemeral and should not use durable config");
1695
+ default: {
1696
+ const _exhaustive = kind;
1697
+ throw new Error(`Unexpected StreamKind: ${_exhaustive}`);
1698
+ }
1575
1699
  }
1576
1700
  }
1577
1701
  };
1578
1702
 
1579
1703
  // src/server/infrastructure/message.provider.ts
1580
1704
  var import_common7 = require("@nestjs/common");
1581
- var import_nats8 = require("nats");
1705
+ var import_jetstream17 = require("@nats-io/jetstream");
1582
1706
  var import_rxjs3 = require("rxjs");
1583
1707
  var MessageProvider = class {
1584
1708
  constructor(connection, eventBus, consumeOptionsMap = /* @__PURE__ */ new Map()) {
@@ -1637,8 +1761,8 @@ var MessageProvider = class {
1637
1761
  * @param orderedConfig - Optional overrides for ordered consumer options.
1638
1762
  */
1639
1763
  async startOrdered(streamName2, filterSubjects, orderedConfig) {
1640
- const consumerOpts = { filterSubjects };
1641
- if (orderedConfig?.deliverPolicy !== void 0 && orderedConfig.deliverPolicy !== import_nats8.DeliverPolicy.All) {
1764
+ const consumerOpts = { filter_subjects: filterSubjects };
1765
+ if (orderedConfig?.deliverPolicy !== void 0 && orderedConfig.deliverPolicy !== import_jetstream17.DeliverPolicy.All) {
1642
1766
  consumerOpts.deliver_policy = orderedConfig.deliverPolicy;
1643
1767
  }
1644
1768
  if (orderedConfig?.optStartSeq !== void 0) {
@@ -1722,10 +1846,10 @@ var MessageProvider = class {
1722
1846
  }
1723
1847
  /** Monitor heartbeats and restart the consumer iterator on prolonged silence. */
1724
1848
  monitorConsumerHealth(messages, name) {
1725
- (async () => {
1726
- for await (const status of await messages.status()) {
1727
- if (status.type === import_nats8.ConsumerEvents.HeartbeatsMissed && status.data >= 2) {
1728
- this.logger.warn(`Consumer ${name}: ${status.data} heartbeats missed, restarting`);
1849
+ void (async () => {
1850
+ for await (const status of messages.status()) {
1851
+ if (status.type === "heartbeats_missed" && status.count >= 2) {
1852
+ this.logger.warn(`Consumer ${name}: ${status.count} heartbeats missed, restarting`);
1729
1853
  messages.stop();
1730
1854
  break;
1731
1855
  }
@@ -2105,7 +2229,7 @@ var EventRouter = class {
2105
2229
 
2106
2230
  // src/server/routing/rpc.router.ts
2107
2231
  var import_common10 = require("@nestjs/common");
2108
- var import_nats9 = require("nats");
2232
+ var import_transport_node4 = require("@nats-io/transport-node");
2109
2233
  var import_rxjs5 = require("rxjs");
2110
2234
  var RpcRouter = class {
2111
2235
  constructor(messageProvider, patternRegistry, connection, codec, eventBus, rpcOptions, ackWaitMap) {
@@ -2197,7 +2321,7 @@ var RpcRouter = class {
2197
2321
  stopAckExtension?.();
2198
2322
  msg.ack();
2199
2323
  try {
2200
- const hdrs = (0, import_nats9.headers)();
2324
+ const hdrs = (0, import_transport_node4.headers)();
2201
2325
  hdrs.set("x-correlation-id" /* CorrelationId */, correlationId);
2202
2326
  nc.publish(replyTo, this.codec.encode(result), { headers: hdrs });
2203
2327
  } catch (publishErr) {
@@ -2209,7 +2333,7 @@ var RpcRouter = class {
2209
2333
  clearTimeout(timeoutId);
2210
2334
  stopAckExtension?.();
2211
2335
  try {
2212
- const hdrs = (0, import_nats9.headers)();
2336
+ const hdrs = (0, import_transport_node4.headers)();
2213
2337
  hdrs.set("x-correlation-id" /* CorrelationId */, correlationId);
2214
2338
  hdrs.set("x-error" /* Error */, "true");
2215
2339
  nc.publish(replyTo, this.codec.encode(serializeError(err)), { headers: hdrs });
@@ -2659,8 +2783,12 @@ JetstreamModule = __decorateClass([
2659
2783
  RpcContext,
2660
2784
  StreamKind,
2661
2785
  TransportEvent,
2786
+ buildSubject,
2787
+ consumerName,
2662
2788
  getClientToken,
2789
+ internalName,
2663
2790
  isCoreRpcMode,
2664
2791
  isJetStreamRpcMode,
2792
+ streamName,
2665
2793
  toNanos
2666
2794
  });