@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 +205 -85
- package/dist/index.d.cts +54 -12
- package/dist/index.d.ts +54 -12
- package/dist/index.js +187 -71
- package/package.json +8 -3
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
|
|
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
|
|
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:
|
|
117
|
-
storage:
|
|
117
|
+
retention: import_jetstream.RetentionPolicy.Workqueue,
|
|
118
|
+
storage: import_jetstream.StorageType.File,
|
|
118
119
|
num_replicas: 1,
|
|
119
|
-
discard:
|
|
120
|
+
discard: import_jetstream.DiscardPolicy.Old,
|
|
120
121
|
allow_direct: true,
|
|
121
|
-
compression:
|
|
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:
|
|
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:
|
|
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:
|
|
174
|
-
deliver_policy:
|
|
175
|
-
replay_policy:
|
|
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:
|
|
182
|
-
deliver_policy:
|
|
183
|
-
replay_policy:
|
|
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:
|
|
190
|
-
deliver_policy:
|
|
191
|
-
replay_policy:
|
|
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 ===
|
|
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
|
|
405
|
-
const msgHeaders = this.buildHeaders(hdrs, { subject });
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
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 =
|
|
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 ??
|
|
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,
|
|
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,
|
|
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
|
|
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 {
|
|
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
|
|
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
|
|
731
|
+
return encoder.encode(JSON.stringify(data));
|
|
645
732
|
}
|
|
646
733
|
decode(data) {
|
|
647
|
-
return
|
|
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
|
|
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 = (
|
|
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
|
|
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,
|
|
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
|
|
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
|
|
884
|
+
case "disconnect":
|
|
794
885
|
this.eventBus.emit("disconnect" /* Disconnect */);
|
|
795
886
|
break;
|
|
796
|
-
case
|
|
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
|
|
803
|
-
this.eventBus.emit(
|
|
893
|
+
case "error":
|
|
894
|
+
this.eventBus.emit(
|
|
895
|
+
"error" /* Error */,
|
|
896
|
+
status.error,
|
|
897
|
+
"connection"
|
|
898
|
+
);
|
|
804
899
|
break;
|
|
805
|
-
case
|
|
806
|
-
case
|
|
807
|
-
case
|
|
808
|
-
case
|
|
809
|
-
case
|
|
810
|
-
case
|
|
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
|
|
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,
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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 !==
|
|
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
|
|
1731
|
-
if (status.type ===
|
|
1732
|
-
this.logger.warn(`Consumer ${name}: ${status.
|
|
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
|
|
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,
|
|
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,
|
|
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 });
|