@horizon-republic/nestjs-jetstream 2.7.1 → 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
@@ -64,7 +64,8 @@ var import_common12 = require("@nestjs/common");
64
64
  // src/client/jetstream.client.ts
65
65
  var import_common = require("@nestjs/common");
66
66
  var import_microservices = require("@nestjs/microservices");
67
- var import_nats2 = require("nats");
67
+ var import_transport_node = require("@nats-io/transport-node");
68
+ var import_nuid = require("@nats-io/nuid");
68
69
 
69
70
  // src/interfaces/hooks.interface.ts
70
71
  var MessageKind = /* @__PURE__ */ ((MessageKind2) => {
@@ -95,7 +96,7 @@ var StreamKind = /* @__PURE__ */ ((StreamKind2) => {
95
96
  })(StreamKind || {});
96
97
 
97
98
  // src/jetstream.constants.ts
98
- var import_nats = require("nats");
99
+ var import_jetstream = require("@nats-io/jetstream");
99
100
  var JETSTREAM_OPTIONS = /* @__PURE__ */ Symbol("JETSTREAM_OPTIONS");
100
101
  var JETSTREAM_CONNECTION = /* @__PURE__ */ Symbol("JETSTREAM_CONNECTION");
101
102
  var JETSTREAM_CODEC = /* @__PURE__ */ Symbol("JETSTREAM_CODEC");
@@ -113,12 +114,12 @@ var NANOS_PER = {
113
114
  };
114
115
  var toNanos = (value, unit) => value * NANOS_PER[unit];
115
116
  var baseStreamConfig = {
116
- retention: import_nats.RetentionPolicy.Workqueue,
117
- storage: import_nats.StorageType.File,
117
+ retention: import_jetstream.RetentionPolicy.Workqueue,
118
+ storage: import_jetstream.StorageType.File,
118
119
  num_replicas: 1,
119
- discard: import_nats.DiscardPolicy.Old,
120
+ discard: import_jetstream.DiscardPolicy.Old,
120
121
  allow_direct: true,
121
- compression: import_nats.StoreCompression.S2
122
+ compression: import_jetstream.StoreCompression.S2
122
123
  };
123
124
  var DEFAULT_EVENT_STREAM_CONFIG = {
124
125
  ...baseStreamConfig,
@@ -144,7 +145,7 @@ var DEFAULT_COMMAND_STREAM_CONFIG = {
144
145
  };
145
146
  var DEFAULT_BROADCAST_STREAM_CONFIG = {
146
147
  ...baseStreamConfig,
147
- retention: import_nats.RetentionPolicy.Limits,
148
+ retention: import_jetstream.RetentionPolicy.Limits,
148
149
  allow_rollup_hdrs: true,
149
150
  max_consumers: 200,
150
151
  max_msg_size: 10 * MB,
@@ -156,7 +157,7 @@ var DEFAULT_BROADCAST_STREAM_CONFIG = {
156
157
  };
157
158
  var DEFAULT_ORDERED_STREAM_CONFIG = {
158
159
  ...baseStreamConfig,
159
- retention: import_nats.RetentionPolicy.Limits,
160
+ retention: import_jetstream.RetentionPolicy.Limits,
160
161
  allow_rollup_hdrs: false,
161
162
  max_consumers: 100,
162
163
  max_msg_size: 10 * MB,
@@ -170,25 +171,25 @@ var DEFAULT_EVENT_CONSUMER_CONFIG = {
170
171
  ack_wait: toNanos(10, "seconds"),
171
172
  max_deliver: 3,
172
173
  max_ack_pending: 100,
173
- ack_policy: import_nats.AckPolicy.Explicit,
174
- deliver_policy: import_nats.DeliverPolicy.All,
175
- 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
176
177
  };
177
178
  var DEFAULT_COMMAND_CONSUMER_CONFIG = {
178
179
  ack_wait: toNanos(5, "minutes"),
179
180
  max_deliver: 1,
180
181
  max_ack_pending: 100,
181
- ack_policy: import_nats.AckPolicy.Explicit,
182
- deliver_policy: import_nats.DeliverPolicy.All,
183
- 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
184
185
  };
185
186
  var DEFAULT_BROADCAST_CONSUMER_CONFIG = {
186
187
  ack_wait: toNanos(10, "seconds"),
187
188
  max_deliver: 3,
188
189
  max_ack_pending: 100,
189
- ack_policy: import_nats.AckPolicy.Explicit,
190
- deliver_policy: import_nats.DeliverPolicy.All,
191
- 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
192
193
  };
193
194
  var DEFAULT_RPC_TIMEOUT = 3e4;
194
195
  var DEFAULT_JETSTREAM_RPC_TIMEOUT = 18e4;
@@ -227,11 +228,12 @@ var isCoreRpcMode = (rpc) => !rpc || rpc.mode === "core";
227
228
 
228
229
  // src/client/jetstream.record.ts
229
230
  var JetstreamRecord = class {
230
- constructor(data, headers2, timeout, messageId) {
231
+ constructor(data, headers2, timeout, messageId, schedule) {
231
232
  this.data = data;
232
233
  this.headers = headers2;
233
234
  this.timeout = timeout;
234
235
  this.messageId = messageId;
236
+ this.schedule = schedule;
235
237
  }
236
238
  };
237
239
  var JetstreamRecordBuilder = class {
@@ -239,6 +241,7 @@ var JetstreamRecordBuilder = class {
239
241
  headers = /* @__PURE__ */ new Map();
240
242
  timeout;
241
243
  messageId;
244
+ scheduleOptions;
242
245
  constructor(data) {
243
246
  this.data = data;
244
247
  }
@@ -306,17 +309,43 @@ var JetstreamRecordBuilder = class {
306
309
  this.timeout = ms;
307
310
  return this;
308
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
+ }
309
336
  /**
310
337
  * Build the immutable {@link JetstreamRecord}.
311
338
  *
312
339
  * @returns A frozen record ready to pass to `client.send()` or `client.emit()`.
313
340
  */
314
341
  build() {
342
+ const schedule = this.scheduleOptions ? { at: new Date(this.scheduleOptions.at.getTime()) } : void 0;
315
343
  return new JetstreamRecord(
316
344
  this.data,
317
345
  new Map(this.headers),
318
346
  this.timeout,
319
- this.messageId
347
+ this.messageId,
348
+ schedule
320
349
  );
321
350
  }
322
351
  /** Validate that a header key is not reserved. */
@@ -368,7 +397,7 @@ var JetstreamClient = class extends import_microservices.ClientProxy {
368
397
  this.setupInbox(nc);
369
398
  }
370
399
  this.statusSubscription ??= this.connection.status$.subscribe((status) => {
371
- if (status.type === import_nats2.Events.Disconnect) {
400
+ if (status.type === "disconnect") {
372
401
  this.handleDisconnect();
373
402
  }
374
403
  });
@@ -396,19 +425,38 @@ var JetstreamClient = class extends import_microservices.ClientProxy {
396
425
  * Publish a fire-and-forget event to JetStream.
397
426
  *
398
427
  * Events are published to either the workqueue stream or broadcast stream
399
- * 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.
400
431
  */
401
432
  async dispatchEvent(packet) {
402
433
  await this.connect();
403
- const { data, hdrs, messageId } = this.extractRecordData(packet.data);
404
- const subject = this.buildEventSubject(packet.pattern);
405
- const msgHeaders = this.buildHeaders(hdrs, { subject });
406
- const ack = await this.connection.getJetStreamClient().publish(subject, this.codec.encode(data), {
407
- headers: msgHeaders,
408
- msgID: messageId ?? crypto.randomUUID()
409
- });
410
- if (ack.duplicate) {
411
- 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
+ }
412
460
  }
413
461
  return void 0;
414
462
  }
@@ -420,7 +468,12 @@ var JetstreamClient = class extends import_microservices.ClientProxy {
420
468
  */
421
469
  publish(packet, callback) {
422
470
  const subject = buildSubject(this.targetName, "cmd" /* Command */, packet.pattern);
423
- 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
+ }
424
477
  const onUnhandled = (err) => {
425
478
  this.logger.error("Unhandled publish error:", err);
426
479
  callback({ err: new Error("Internal transport error"), response: null, isDisposed: true });
@@ -429,7 +482,7 @@ var JetstreamClient = class extends import_microservices.ClientProxy {
429
482
  if (isCoreRpcMode(this.rootOptions.rpc)) {
430
483
  this.publishCoreRpc(subject, data, hdrs, timeout, callback).catch(onUnhandled);
431
484
  } else {
432
- jetStreamCorrelationId = crypto.randomUUID();
485
+ jetStreamCorrelationId = import_nuid.nuid.next();
433
486
  this.publishJetStreamRpc(subject, data, callback, {
434
487
  headers: hdrs,
435
488
  timeout,
@@ -504,7 +557,7 @@ var JetstreamClient = class extends import_microservices.ClientProxy {
504
557
  });
505
558
  await this.connection.getJetStreamClient().publish(subject, this.codec.encode(data), {
506
559
  headers: hdrs,
507
- msgID: messageId ?? crypto.randomUUID()
560
+ msgID: messageId ?? import_nuid.nuid.next()
508
561
  });
509
562
  } catch (err) {
510
563
  const existingTimeout = this.pendingTimeouts.get(correlationId);
@@ -539,7 +592,7 @@ var JetstreamClient = class extends import_microservices.ClientProxy {
539
592
  }
540
593
  /** Setup shared inbox subscription for JetStream RPC responses. */
541
594
  setupInbox(nc) {
542
- this.inbox = (0, import_nats2.createInbox)(internalName(this.rootOptions.name));
595
+ this.inbox = (0, import_transport_node.createInbox)(internalName(this.rootOptions.name));
543
596
  this.inboxSubscription = nc.subscribe(this.inbox, {
544
597
  callback: (err, msg) => {
545
598
  if (err) {
@@ -601,7 +654,7 @@ var JetstreamClient = class extends import_microservices.ClientProxy {
601
654
  }
602
655
  /** Build NATS headers merging custom headers with transport headers. */
603
656
  buildHeaders(customHeaders, transport) {
604
- const hdrs = (0, import_nats2.headers)();
657
+ const hdrs = (0, import_transport_node.headers)();
605
658
  hdrs.set("x-subject" /* Subject */, transport.subject);
606
659
  hdrs.set("x-caller-name" /* CallerName */, this.callerName);
607
660
  if (transport.correlationId) {
@@ -617,17 +670,51 @@ var JetstreamClient = class extends import_microservices.ClientProxy {
617
670
  }
618
671
  return hdrs;
619
672
  }
620
- /** Extract data, headers, and timeout from raw packet data or JetstreamRecord. */
673
+ /** Extract data, headers, timeout, and schedule from raw packet data or JetstreamRecord. */
621
674
  extractRecordData(rawData) {
622
675
  if (rawData instanceof JetstreamRecord) {
623
676
  return {
624
677
  data: rawData.data,
625
678
  hdrs: rawData.headers.size > 0 ? new Map(rawData.headers) : null,
626
679
  timeout: rawData.timeout,
627
- messageId: rawData.messageId
680
+ messageId: rawData.messageId,
681
+ schedule: rawData.schedule
628
682
  };
629
683
  }
630
- 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}`;
631
718
  }
632
719
  getRpcTimeout() {
633
720
  if (!this.rootOptions.rpc) return DEFAULT_RPC_TIMEOUT;
@@ -637,20 +724,21 @@ var JetstreamClient = class extends import_microservices.ClientProxy {
637
724
  };
638
725
 
639
726
  // src/codec/json.codec.ts
640
- var import_nats3 = require("nats");
727
+ var encoder = new TextEncoder();
728
+ var decoder = new TextDecoder();
641
729
  var JsonCodec = class {
642
- inner = (0, import_nats3.JSONCodec)();
643
730
  encode(data) {
644
- return this.inner.encode(data);
731
+ return encoder.encode(JSON.stringify(data));
645
732
  }
646
733
  decode(data) {
647
- return this.inner.decode(data);
734
+ return JSON.parse(decoder.decode(data));
648
735
  }
649
736
  };
650
737
 
651
738
  // src/connection/connection.provider.ts
652
739
  var import_common2 = require("@nestjs/common");
653
- var import_nats4 = require("nats");
740
+ var import_transport_node2 = require("@nats-io/transport-node");
741
+ var import_jetstream7 = require("@nats-io/jetstream");
654
742
  var import_rxjs = require("rxjs");
655
743
  var DEFAULT_OPTIONS = {
656
744
  maxReconnectAttempts: -1,
@@ -704,14 +792,7 @@ var ConnectionProvider = class {
704
792
  async getJetStreamManager() {
705
793
  if (this.jsmInstance) return this.jsmInstance;
706
794
  if (this.jsmPromise) return this.jsmPromise;
707
- this.jsmPromise = (async () => {
708
- const nc = await this.getConnection();
709
- this.jsmInstance = await nc.jetstreamManager();
710
- this.logger.log("JetStream manager initialized");
711
- return this.jsmInstance;
712
- })().finally(() => {
713
- this.jsmPromise = null;
714
- });
795
+ this.jsmPromise = this.initJetStreamManager();
715
796
  return this.jsmPromise;
716
797
  }
717
798
  /**
@@ -727,7 +808,7 @@ var ConnectionProvider = class {
727
808
  if (!this.connection || this.connection.isClosed()) {
728
809
  throw new Error("Not connected \u2014 call getConnection() before getJetStreamClient()");
729
810
  }
730
- this.jsClient ??= this.connection.jetstream();
811
+ this.jsClient ??= (0, import_jetstream7.jetstream)(this.connection);
731
812
  return this.jsClient;
732
813
  }
733
814
  /** Direct access to the raw NATS connection, or `null` if not yet connected. */
@@ -763,11 +844,21 @@ var ConnectionProvider = class {
763
844
  this.jsmPromise = null;
764
845
  }
765
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
+ }
766
857
  /** Internal: establish the physical connection with reconnect monitoring. */
767
858
  async establish() {
768
859
  const name = internalName(this.options.name);
769
860
  try {
770
- const nc = await (0, import_nats4.connect)({
861
+ const nc = await (0, import_transport_node2.connect)({
771
862
  ...DEFAULT_OPTIONS,
772
863
  ...this.options.connectionOptions,
773
864
  servers: this.options.servers,
@@ -779,7 +870,7 @@ var ConnectionProvider = class {
779
870
  this.monitorStatus(nc);
780
871
  return nc;
781
872
  } catch (err) {
782
- if (err instanceof import_nats4.NatsError && err.code === "CONNECTION_REFUSED") {
873
+ if (err instanceof Error && err.message.includes("REFUSED")) {
783
874
  throw new Error(`NATS connection refused: ${this.options.servers.join(", ")}`);
784
875
  }
785
876
  throw err;
@@ -787,27 +878,33 @@ var ConnectionProvider = class {
787
878
  }
788
879
  /** Subscribe to connection status events and emit hooks. */
789
880
  monitorStatus(nc) {
790
- (async () => {
881
+ void (async () => {
791
882
  for await (const status of nc.status()) {
792
883
  switch (status.type) {
793
- case import_nats4.Events.Disconnect:
884
+ case "disconnect":
794
885
  this.eventBus.emit("disconnect" /* Disconnect */);
795
886
  break;
796
- case import_nats4.Events.Reconnect:
887
+ case "reconnect":
797
888
  this.jsClient = null;
798
889
  this.jsmInstance = null;
799
890
  this.jsmPromise = null;
800
891
  this.eventBus.emit("reconnect" /* Reconnect */, nc.getServer());
801
892
  break;
802
- case import_nats4.Events.Error:
803
- 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
+ );
804
899
  break;
805
- case import_nats4.Events.Update:
806
- case import_nats4.Events.LDM:
807
- case import_nats4.DebugEvents.Reconnecting:
808
- case import_nats4.DebugEvents.PingTimer:
809
- case import_nats4.DebugEvents.StaleConnection:
810
- 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":
811
908
  break;
812
909
  }
813
910
  }
@@ -1069,7 +1166,7 @@ var JetstreamStrategy = class extends import_microservices2.Server {
1069
1166
 
1070
1167
  // src/server/core-rpc.server.ts
1071
1168
  var import_common4 = require("@nestjs/common");
1072
- var import_nats5 = require("nats");
1169
+ var import_transport_node3 = require("@nats-io/transport-node");
1073
1170
 
1074
1171
  // src/context/rpc.context.ts
1075
1172
  var import_microservices3 = require("@nestjs/microservices");
@@ -1355,7 +1452,7 @@ var CoreRpcServer = class {
1355
1452
  /** Send an error response back to the caller with x-error header. */
1356
1453
  respondWithError(msg, error) {
1357
1454
  try {
1358
- const hdrs = (0, import_nats5.headers)();
1455
+ const hdrs = (0, import_transport_node3.headers)();
1359
1456
  hdrs.set("x-error" /* Error */, "true");
1360
1457
  msg.respond(this.codec.encode(serializeError(error)), { headers: hdrs });
1361
1458
  } catch {
@@ -1366,7 +1463,7 @@ var CoreRpcServer = class {
1366
1463
 
1367
1464
  // src/server/infrastructure/stream.provider.ts
1368
1465
  var import_common5 = require("@nestjs/common");
1369
- var import_nats6 = require("nats");
1466
+ var import_jetstream13 = require("@nats-io/jetstream");
1370
1467
  var STREAM_NOT_FOUND = 10059;
1371
1468
  var StreamProvider = class {
1372
1469
  constructor(options, connection) {
@@ -1392,12 +1489,22 @@ var StreamProvider = class {
1392
1489
  getSubjects(kind) {
1393
1490
  const name = internalName(this.options.name);
1394
1491
  switch (kind) {
1395
- case "ev" /* Event */:
1396
- 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
+ }
1397
1499
  case "cmd" /* Command */:
1398
1500
  return [`${name}.${"cmd" /* Command */}.>`];
1399
- case "broadcast" /* Broadcast */:
1400
- 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
+ }
1401
1508
  case "ordered" /* Ordered */:
1402
1509
  return [`${name}.${"ordered" /* Ordered */}.>`];
1403
1510
  }
@@ -1411,7 +1518,7 @@ var StreamProvider = class {
1411
1518
  this.logger.debug(`Stream exists, updating: ${config.name}`);
1412
1519
  return await jsm.streams.update(config.name, config);
1413
1520
  } catch (err) {
1414
- 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) {
1415
1522
  this.logger.log(`Creating stream: ${config.name}`);
1416
1523
  return await jsm.streams.add(config);
1417
1524
  }
@@ -1446,6 +1553,11 @@ var StreamProvider = class {
1446
1553
  return DEFAULT_ORDERED_STREAM_CONFIG;
1447
1554
  }
1448
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
+ }
1449
1561
  /** Get user-provided overrides for a stream kind. */
1450
1562
  getOverrides(kind) {
1451
1563
  switch (kind) {
@@ -1463,7 +1575,7 @@ var StreamProvider = class {
1463
1575
 
1464
1576
  // src/server/infrastructure/consumer.provider.ts
1465
1577
  var import_common6 = require("@nestjs/common");
1466
- var import_nats7 = require("nats");
1578
+ var import_jetstream15 = require("@nats-io/jetstream");
1467
1579
  var CONSUMER_NOT_FOUND = 10014;
1468
1580
  var ConsumerProvider = class {
1469
1581
  constructor(options, connection, streamProvider, patternRegistry) {
@@ -1504,7 +1616,7 @@ var ConsumerProvider = class {
1504
1616
  this.logger.debug(`Consumer exists, updating: ${name}`);
1505
1617
  return await jsm.consumers.update(stream, name, config);
1506
1618
  } catch (err) {
1507
- 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) {
1508
1620
  this.logger.log(`Creating consumer: ${name}`);
1509
1621
  return await jsm.consumers.add(stream, config);
1510
1622
  }
@@ -1563,6 +1675,10 @@ var ConsumerProvider = class {
1563
1675
  return DEFAULT_BROADCAST_CONSUMER_CONFIG;
1564
1676
  case "ordered" /* Ordered */:
1565
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
+ }
1566
1682
  }
1567
1683
  }
1568
1684
  /** Get user-provided overrides for a consumer kind. */
@@ -1576,13 +1692,17 @@ var ConsumerProvider = class {
1576
1692
  return this.options.broadcast?.consumer ?? {};
1577
1693
  case "ordered" /* Ordered */:
1578
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
+ }
1579
1699
  }
1580
1700
  }
1581
1701
  };
1582
1702
 
1583
1703
  // src/server/infrastructure/message.provider.ts
1584
1704
  var import_common7 = require("@nestjs/common");
1585
- var import_nats8 = require("nats");
1705
+ var import_jetstream17 = require("@nats-io/jetstream");
1586
1706
  var import_rxjs3 = require("rxjs");
1587
1707
  var MessageProvider = class {
1588
1708
  constructor(connection, eventBus, consumeOptionsMap = /* @__PURE__ */ new Map()) {
@@ -1641,8 +1761,8 @@ var MessageProvider = class {
1641
1761
  * @param orderedConfig - Optional overrides for ordered consumer options.
1642
1762
  */
1643
1763
  async startOrdered(streamName2, filterSubjects, orderedConfig) {
1644
- const consumerOpts = { filterSubjects };
1645
- 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) {
1646
1766
  consumerOpts.deliver_policy = orderedConfig.deliverPolicy;
1647
1767
  }
1648
1768
  if (orderedConfig?.optStartSeq !== void 0) {
@@ -1726,10 +1846,10 @@ var MessageProvider = class {
1726
1846
  }
1727
1847
  /** Monitor heartbeats and restart the consumer iterator on prolonged silence. */
1728
1848
  monitorConsumerHealth(messages, name) {
1729
- (async () => {
1730
- for await (const status of await messages.status()) {
1731
- if (status.type === import_nats8.ConsumerEvents.HeartbeatsMissed && status.data >= 2) {
1732
- 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`);
1733
1853
  messages.stop();
1734
1854
  break;
1735
1855
  }
@@ -2109,7 +2229,7 @@ var EventRouter = class {
2109
2229
 
2110
2230
  // src/server/routing/rpc.router.ts
2111
2231
  var import_common10 = require("@nestjs/common");
2112
- var import_nats9 = require("nats");
2232
+ var import_transport_node4 = require("@nats-io/transport-node");
2113
2233
  var import_rxjs5 = require("rxjs");
2114
2234
  var RpcRouter = class {
2115
2235
  constructor(messageProvider, patternRegistry, connection, codec, eventBus, rpcOptions, ackWaitMap) {
@@ -2201,7 +2321,7 @@ var RpcRouter = class {
2201
2321
  stopAckExtension?.();
2202
2322
  msg.ack();
2203
2323
  try {
2204
- const hdrs = (0, import_nats9.headers)();
2324
+ const hdrs = (0, import_transport_node4.headers)();
2205
2325
  hdrs.set("x-correlation-id" /* CorrelationId */, correlationId);
2206
2326
  nc.publish(replyTo, this.codec.encode(result), { headers: hdrs });
2207
2327
  } catch (publishErr) {
@@ -2213,7 +2333,7 @@ var RpcRouter = class {
2213
2333
  clearTimeout(timeoutId);
2214
2334
  stopAckExtension?.();
2215
2335
  try {
2216
- const hdrs = (0, import_nats9.headers)();
2336
+ const hdrs = (0, import_transport_node4.headers)();
2217
2337
  hdrs.set("x-correlation-id" /* CorrelationId */, correlationId);
2218
2338
  hdrs.set("x-error" /* Error */, "true");
2219
2339
  nc.publish(replyTo, this.codec.encode(serializeError(err)), { headers: hdrs });