@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 +213 -85
- package/dist/index.d.cts +90 -9
- package/dist/index.d.ts +90 -9
- package/dist/index.js +191 -71
- package/package.json +8 -3
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
|
|
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
|
|
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:
|
|
113
|
-
storage:
|
|
117
|
+
retention: import_jetstream.RetentionPolicy.Workqueue,
|
|
118
|
+
storage: import_jetstream.StorageType.File,
|
|
114
119
|
num_replicas: 1,
|
|
115
|
-
discard:
|
|
120
|
+
discard: import_jetstream.DiscardPolicy.Old,
|
|
116
121
|
allow_direct: true,
|
|
117
|
-
compression:
|
|
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:
|
|
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:
|
|
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:
|
|
170
|
-
deliver_policy:
|
|
171
|
-
replay_policy:
|
|
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:
|
|
178
|
-
deliver_policy:
|
|
179
|
-
replay_policy:
|
|
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:
|
|
186
|
-
deliver_policy:
|
|
187
|
-
replay_policy:
|
|
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 ===
|
|
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
|
|
401
|
-
const msgHeaders = this.buildHeaders(hdrs, { subject });
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
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 =
|
|
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 ??
|
|
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,
|
|
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,
|
|
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
|
|
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 {
|
|
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
|
|
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
|
|
731
|
+
return encoder.encode(JSON.stringify(data));
|
|
641
732
|
}
|
|
642
733
|
decode(data) {
|
|
643
|
-
return
|
|
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
|
|
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 = (
|
|
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
|
|
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,
|
|
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
|
|
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
|
|
884
|
+
case "disconnect":
|
|
790
885
|
this.eventBus.emit("disconnect" /* Disconnect */);
|
|
791
886
|
break;
|
|
792
|
-
case
|
|
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
|
|
799
|
-
this.eventBus.emit(
|
|
893
|
+
case "error":
|
|
894
|
+
this.eventBus.emit(
|
|
895
|
+
"error" /* Error */,
|
|
896
|
+
status.error,
|
|
897
|
+
"connection"
|
|
898
|
+
);
|
|
800
899
|
break;
|
|
801
|
-
case
|
|
802
|
-
case
|
|
803
|
-
case
|
|
804
|
-
case
|
|
805
|
-
case
|
|
806
|
-
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":
|
|
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
|
|
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,
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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 !==
|
|
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
|
|
1727
|
-
if (status.type ===
|
|
1728
|
-
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`);
|
|
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
|
|
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,
|
|
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,
|
|
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
|
});
|