@horizon-republic/nestjs-jetstream 2.3.2 → 2.3.4
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/README.md +13 -13
- package/dist/index.cjs +79 -61
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +144 -37
- package/dist/index.d.ts +144 -37
- package/dist/index.js +79 -61
- package/dist/index.js.map +1 -1
- package/package.json +4 -2
package/README.md
CHANGED
|
@@ -252,7 +252,7 @@ interface JetstreamModuleOptions {
|
|
|
252
252
|
/** Broadcast event stream/consumer overrides. */
|
|
253
253
|
broadcast?: { stream?: Partial<StreamConfig>; consumer?: Partial<ConsumerConfig> };
|
|
254
254
|
|
|
255
|
-
/** Transport lifecycle hook handlers. Unset hooks
|
|
255
|
+
/** Transport lifecycle hook handlers. Unset hooks are silently ignored. */
|
|
256
256
|
hooks?: Partial<TransportHooks>;
|
|
257
257
|
|
|
258
258
|
/** Async callback for dead letter handling. See Dead Letter Queue section below. */
|
|
@@ -584,7 +584,7 @@ JetstreamModule.forFeature({
|
|
|
584
584
|
|
|
585
585
|
### Lifecycle Hooks
|
|
586
586
|
|
|
587
|
-
Subscribe to transport events for monitoring, alerting, or custom logic:
|
|
587
|
+
Subscribe to transport events for monitoring, alerting, or custom logic. Events without a registered hook are silently ignored — no default logging:
|
|
588
588
|
|
|
589
589
|
```typescript
|
|
590
590
|
import { JetstreamModule, TransportEvent } from '@horizon-republic/nestjs-jetstream';
|
|
@@ -611,17 +611,17 @@ JetstreamModule.forRoot({
|
|
|
611
611
|
|
|
612
612
|
**Available events:**
|
|
613
613
|
|
|
614
|
-
| Event | Arguments |
|
|
615
|
-
|
|
616
|
-
| `connect` | `(server: string)` |
|
|
617
|
-
| `disconnect` | `()` |
|
|
618
|
-
| `reconnect` | `(server: string)` |
|
|
619
|
-
| `error` | `(error: Error, context?: string)` |
|
|
620
|
-
| `rpcTimeout` | `(subject: string, correlationId: string)` |
|
|
621
|
-
| `messageRouted` | `(subject: string, kind: 'rpc' \| 'event')` |
|
|
622
|
-
| `shutdownStart` | `()` |
|
|
623
|
-
| `shutdownComplete` | `()` |
|
|
624
|
-
| `deadLetter` | `(info: DeadLetterInfo)` |
|
|
614
|
+
| Event | Arguments |
|
|
615
|
+
|--------------------|---------------------------------------------|
|
|
616
|
+
| `connect` | `(server: string)` |
|
|
617
|
+
| `disconnect` | `()` |
|
|
618
|
+
| `reconnect` | `(server: string)` |
|
|
619
|
+
| `error` | `(error: Error, context?: string)` |
|
|
620
|
+
| `rpcTimeout` | `(subject: string, correlationId: string)` |
|
|
621
|
+
| `messageRouted` | `(subject: string, kind: 'rpc' \| 'event')` |
|
|
622
|
+
| `shutdownStart` | `()` |
|
|
623
|
+
| `shutdownComplete` | `()` |
|
|
624
|
+
| `deadLetter` | `(info: DeadLetterInfo)` |
|
|
625
625
|
|
|
626
626
|
#### Dead Letter Queue (DLQ)
|
|
627
627
|
|
package/dist/index.cjs
CHANGED
|
@@ -203,7 +203,11 @@ var JetstreamRecordBuilder = class {
|
|
|
203
203
|
constructor(data) {
|
|
204
204
|
this.data = data;
|
|
205
205
|
}
|
|
206
|
-
/**
|
|
206
|
+
/**
|
|
207
|
+
* Set the message payload.
|
|
208
|
+
*
|
|
209
|
+
* @param data - Payload to serialize via the configured {@link Codec}.
|
|
210
|
+
*/
|
|
207
211
|
setData(data) {
|
|
208
212
|
this.data = data;
|
|
209
213
|
return this;
|
|
@@ -211,6 +215,8 @@ var JetstreamRecordBuilder = class {
|
|
|
211
215
|
/**
|
|
212
216
|
* Set a single custom header.
|
|
213
217
|
*
|
|
218
|
+
* @param key - Header name (e.g. `'x-tenant'`).
|
|
219
|
+
* @param value - Header value.
|
|
214
220
|
* @throws Error if the header name is reserved by the transport.
|
|
215
221
|
*/
|
|
216
222
|
setHeader(key, value) {
|
|
@@ -221,6 +227,7 @@ var JetstreamRecordBuilder = class {
|
|
|
221
227
|
/**
|
|
222
228
|
* Set multiple custom headers at once.
|
|
223
229
|
*
|
|
230
|
+
* @param headers - Key-value pairs to set as headers.
|
|
224
231
|
* @throws Error if any header name is reserved by the transport.
|
|
225
232
|
*/
|
|
226
233
|
setHeaders(headers2) {
|
|
@@ -229,12 +236,20 @@ var JetstreamRecordBuilder = class {
|
|
|
229
236
|
}
|
|
230
237
|
return this;
|
|
231
238
|
}
|
|
232
|
-
/**
|
|
239
|
+
/**
|
|
240
|
+
* Set per-request RPC timeout.
|
|
241
|
+
*
|
|
242
|
+
* @param ms - Timeout in milliseconds. Overrides the global RPC timeout for this request only.
|
|
243
|
+
*/
|
|
233
244
|
setTimeout(ms) {
|
|
234
245
|
this.timeout = ms;
|
|
235
246
|
return this;
|
|
236
247
|
}
|
|
237
|
-
/**
|
|
248
|
+
/**
|
|
249
|
+
* Build the immutable {@link JetstreamRecord}.
|
|
250
|
+
*
|
|
251
|
+
* @returns A frozen record ready to pass to `client.send()` or `client.emit()`.
|
|
252
|
+
*/
|
|
238
253
|
build() {
|
|
239
254
|
return new JetstreamRecord(this.data, new Map(this.headers), this.timeout);
|
|
240
255
|
}
|
|
@@ -270,7 +285,14 @@ var JetstreamClient = class extends import_microservices.ClientProxy {
|
|
|
270
285
|
pendingTimeouts = /* @__PURE__ */ new Map();
|
|
271
286
|
/** Subscription to connection status events for disconnect handling. */
|
|
272
287
|
statusSubscription = null;
|
|
273
|
-
/**
|
|
288
|
+
/**
|
|
289
|
+
* Establish connection. Called automatically by NestJS on first use.
|
|
290
|
+
*
|
|
291
|
+
* Sets up the JetStream RPC inbox (if in JetStream mode) and subscribes
|
|
292
|
+
* to connection status events for fail-fast disconnect handling.
|
|
293
|
+
*
|
|
294
|
+
* @returns The underlying NATS connection.
|
|
295
|
+
*/
|
|
274
296
|
async connect() {
|
|
275
297
|
const nc = await this.connection.getConnection();
|
|
276
298
|
if (this.isJetStreamRpcMode() && !this.inboxSubscription) {
|
|
@@ -283,13 +305,17 @@ var JetstreamClient = class extends import_microservices.ClientProxy {
|
|
|
283
305
|
});
|
|
284
306
|
return nc;
|
|
285
307
|
}
|
|
286
|
-
/** Clean up resources. */
|
|
308
|
+
/** Clean up resources: reject pending RPCs, unsubscribe from status events. */
|
|
287
309
|
async close() {
|
|
288
310
|
this.statusSubscription?.unsubscribe();
|
|
289
311
|
this.statusSubscription = null;
|
|
290
312
|
this.rejectPendingRpcs(new Error("Client closed"));
|
|
291
313
|
}
|
|
292
|
-
/**
|
|
314
|
+
/**
|
|
315
|
+
* Direct access to the raw NATS connection.
|
|
316
|
+
*
|
|
317
|
+
* @throws Error if not connected.
|
|
318
|
+
*/
|
|
293
319
|
unwrap() {
|
|
294
320
|
const nc = this.connection.unwrap;
|
|
295
321
|
if (!nc) {
|
|
@@ -585,7 +611,9 @@ var ConnectionProvider = class {
|
|
|
585
611
|
return this.connectionPromise;
|
|
586
612
|
}
|
|
587
613
|
/**
|
|
588
|
-
* Get JetStream manager. Cached after first call.
|
|
614
|
+
* Get the JetStream manager. Cached after first call.
|
|
615
|
+
*
|
|
616
|
+
* @returns The JetStreamManager for stream/consumer administration.
|
|
589
617
|
*/
|
|
590
618
|
async getJetStreamManager() {
|
|
591
619
|
if (this.jsmInstance) return this.jsmInstance;
|
|
@@ -594,7 +622,7 @@ var ConnectionProvider = class {
|
|
|
594
622
|
this.logger.log("JetStream manager initialized");
|
|
595
623
|
return this.jsmInstance;
|
|
596
624
|
}
|
|
597
|
-
/** Direct access to the raw NATS connection
|
|
625
|
+
/** Direct access to the raw NATS connection, or `null` if not yet connected. */
|
|
598
626
|
get unwrap() {
|
|
599
627
|
return this.connection;
|
|
600
628
|
}
|
|
@@ -678,53 +706,21 @@ var EventBus = class {
|
|
|
678
706
|
this.logger = logger;
|
|
679
707
|
this.hooks = hooks ?? {};
|
|
680
708
|
}
|
|
681
|
-
/**
|
|
709
|
+
/**
|
|
710
|
+
* Emit a lifecycle event. Dispatches to custom hook if registered, otherwise no-op.
|
|
711
|
+
*
|
|
712
|
+
* @param event - The {@link TransportEvent} to emit.
|
|
713
|
+
* @param args - Arguments matching the hook signature for this event.
|
|
714
|
+
*/
|
|
682
715
|
emit(event, ...args) {
|
|
683
716
|
const hook = this.hooks[event];
|
|
684
|
-
if (hook)
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
}
|
|
692
|
-
return;
|
|
693
|
-
}
|
|
694
|
-
this.defaultHandler(event, args);
|
|
695
|
-
}
|
|
696
|
-
/** Default Logger-based handlers for each event type. */
|
|
697
|
-
defaultHandler(event, args) {
|
|
698
|
-
switch (event) {
|
|
699
|
-
case "connect" /* Connect */:
|
|
700
|
-
this.logger.log(`Connected to NATS: ${args[0]}`);
|
|
701
|
-
break;
|
|
702
|
-
case "disconnect" /* Disconnect */:
|
|
703
|
-
this.logger.warn("NATS connection lost");
|
|
704
|
-
break;
|
|
705
|
-
case "reconnect" /* Reconnect */:
|
|
706
|
-
this.logger.log(`Reconnected to NATS: ${args[0]}`);
|
|
707
|
-
break;
|
|
708
|
-
case "error" /* Error */:
|
|
709
|
-
this.logger.error(`Transport error: ${args[0]}`, args[1] ?? "");
|
|
710
|
-
break;
|
|
711
|
-
case "rpcTimeout" /* RpcTimeout */:
|
|
712
|
-
this.logger.warn(`RPC timeout: ${args[0]} (cid: ${args[1]})`);
|
|
713
|
-
break;
|
|
714
|
-
case "messageRouted" /* MessageRouted */:
|
|
715
|
-
this.logger.debug(`Message routed: ${args[0]} [${args[1]}]`);
|
|
716
|
-
break;
|
|
717
|
-
case "shutdownStart" /* ShutdownStart */:
|
|
718
|
-
this.logger.log("Graceful shutdown initiated");
|
|
719
|
-
break;
|
|
720
|
-
case "shutdownComplete" /* ShutdownComplete */:
|
|
721
|
-
this.logger.log("Graceful shutdown complete");
|
|
722
|
-
break;
|
|
723
|
-
case "deadLetter" /* DeadLetter */: {
|
|
724
|
-
const info = args[0];
|
|
725
|
-
this.logger.warn(`Dead letter: ${info?.subject ?? "unknown"}`);
|
|
726
|
-
break;
|
|
727
|
-
}
|
|
717
|
+
if (!hook) return;
|
|
718
|
+
try {
|
|
719
|
+
hook(...args);
|
|
720
|
+
} catch (err) {
|
|
721
|
+
this.logger.error(
|
|
722
|
+
`Hook "${event}" threw an error: ${err instanceof Error ? err.message : err}`
|
|
723
|
+
);
|
|
728
724
|
}
|
|
729
725
|
}
|
|
730
726
|
};
|
|
@@ -741,6 +737,8 @@ var JetstreamHealthIndicator = class {
|
|
|
741
737
|
*
|
|
742
738
|
* Returns the current connection status without throwing.
|
|
743
739
|
* Use this for custom health endpoints or monitoring integrations.
|
|
740
|
+
*
|
|
741
|
+
* @returns Connection status with server URL and RTT latency.
|
|
744
742
|
*/
|
|
745
743
|
async check() {
|
|
746
744
|
const nc = this.connection.unwrap;
|
|
@@ -763,7 +761,9 @@ var JetstreamHealthIndicator = class {
|
|
|
763
761
|
* Returns `{ [key]: { status: 'up', ... } }` on success.
|
|
764
762
|
* Throws an error with `{ [key]: { status: 'down', ... } }` on failure.
|
|
765
763
|
*
|
|
766
|
-
* @param key Health indicator key (default: 'jetstream')
|
|
764
|
+
* @param key - Health indicator key (default: `'jetstream'`).
|
|
765
|
+
* @returns Object with status, server, and latency under the given key.
|
|
766
|
+
* @throws Error with `{ [key]: { status: 'down' } }` when disconnected.
|
|
767
767
|
*/
|
|
768
768
|
async isHealthy(key = "jetstream") {
|
|
769
769
|
const status = await this.check();
|
|
@@ -832,7 +832,7 @@ var JetstreamStrategy = class extends import_microservices2.Server {
|
|
|
832
832
|
}
|
|
833
833
|
callback();
|
|
834
834
|
}
|
|
835
|
-
/**
|
|
835
|
+
/** Stop all consumers, routers, and subscriptions. Called during shutdown. */
|
|
836
836
|
close() {
|
|
837
837
|
this.eventRouter.destroy();
|
|
838
838
|
this.rpcRouter.destroy();
|
|
@@ -852,7 +852,11 @@ var JetstreamStrategy = class extends import_microservices2.Server {
|
|
|
852
852
|
existing.push(callback);
|
|
853
853
|
this.listeners.set(event, existing);
|
|
854
854
|
}
|
|
855
|
-
/**
|
|
855
|
+
/**
|
|
856
|
+
* Unwrap the underlying NATS connection.
|
|
857
|
+
*
|
|
858
|
+
* @throws Error if the transport has not started.
|
|
859
|
+
*/
|
|
856
860
|
unwrap() {
|
|
857
861
|
const nc = this.connection.unwrap;
|
|
858
862
|
if (!nc) {
|
|
@@ -893,23 +897,37 @@ var import_nats5 = require("nats");
|
|
|
893
897
|
// src/context/rpc.context.ts
|
|
894
898
|
var import_microservices3 = require("@nestjs/microservices");
|
|
895
899
|
var RpcContext = class extends import_microservices3.BaseRpcContext {
|
|
896
|
-
/**
|
|
900
|
+
/**
|
|
901
|
+
* Get the underlying NATS message.
|
|
902
|
+
*
|
|
903
|
+
* @returns `JsMsg` for JetStream handlers, `Msg` for Core RPC handlers.
|
|
904
|
+
*/
|
|
897
905
|
getMessage() {
|
|
898
906
|
return this.args[0];
|
|
899
907
|
}
|
|
900
|
-
/**
|
|
908
|
+
/** @returns The NATS subject this message was published to. */
|
|
901
909
|
getSubject() {
|
|
902
910
|
return this.args[0].subject;
|
|
903
911
|
}
|
|
904
|
-
/**
|
|
912
|
+
/** @returns All NATS message headers, or `undefined` if none are present. */
|
|
905
913
|
getHeaders() {
|
|
906
914
|
return this.args[0].headers;
|
|
907
915
|
}
|
|
908
|
-
/**
|
|
916
|
+
/**
|
|
917
|
+
* Get a single header value by key.
|
|
918
|
+
*
|
|
919
|
+
* @param key - Header name (e.g. `'x-trace-id'`).
|
|
920
|
+
* @returns Header value, or `undefined` if the header is missing.
|
|
921
|
+
*/
|
|
909
922
|
getHeader(key) {
|
|
910
923
|
return this.args[0].headers?.get(key);
|
|
911
924
|
}
|
|
912
|
-
/**
|
|
925
|
+
/**
|
|
926
|
+
* Type guard: returns `true` when the message is a JetStream message.
|
|
927
|
+
*
|
|
928
|
+
* Narrows `getMessage()` return type to `JsMsg`, giving access to
|
|
929
|
+
* `ack()`, `nak()`, `term()`, and delivery metadata.
|
|
930
|
+
*/
|
|
913
931
|
isJetStream() {
|
|
914
932
|
return "ack" in this.args[0];
|
|
915
933
|
}
|