@horizon-republic/nestjs-jetstream 2.10.0 → 2.11.1
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 +58 -71
- package/dist/index.cjs +988 -290
- package/dist/index.d.cts +209 -46
- package/dist/index.d.ts +209 -46
- package/dist/index.js +973 -281
- package/package.json +25 -20
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Logger, ModuleMetadata, FactoryProvider, Type, OnApplicationShutdown, DynamicModule } from '@nestjs/common';
|
|
2
2
|
import { MsgHdrs, NatsConnection, Status, ConnectionOptions, Msg } from '@nats-io/transport-node';
|
|
3
3
|
import { JetStreamManager, JetStreamClient, StreamConfig, ConsumerConfig, ConsumeOptions, DeliverPolicy, ReplayPolicy, ConsumerInfo, JsMsg } from '@nats-io/jetstream';
|
|
4
|
+
import { Registry } from 'prom-client';
|
|
4
5
|
import { Span } from '@opentelemetry/api';
|
|
5
6
|
import { ClientProxy, ReadPacket, WritePacket, MessageHandler, Server, CustomTransportStrategy, BaseRpcContext } from '@nestjs/microservices';
|
|
6
7
|
import { Observable } from 'rxjs';
|
|
@@ -33,11 +34,47 @@ interface Codec {
|
|
|
33
34
|
decode(data: Uint8Array): unknown;
|
|
34
35
|
}
|
|
35
36
|
|
|
37
|
+
/**
|
|
38
|
+
* Identifies a JetStream stream/consumer kind.
|
|
39
|
+
*
|
|
40
|
+
* - `Event` — Workqueue events (at-least-once delivery to one consumer).
|
|
41
|
+
* - `Command` — RPC commands (JetStream mode only).
|
|
42
|
+
* - `Broadcast` — Broadcast events (fan-out to all consumers).
|
|
43
|
+
* - `Ordered` — Ordered events (strict sequential delivery, Limits retention).
|
|
44
|
+
*/
|
|
45
|
+
declare enum StreamKind {
|
|
46
|
+
Event = "ev",
|
|
47
|
+
Command = "cmd",
|
|
48
|
+
Broadcast = "broadcast",
|
|
49
|
+
Ordered = "ordered"
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Subset of {@link StreamKind} used for direct subject building.
|
|
53
|
+
*
|
|
54
|
+
* Excludes `Broadcast` because broadcast subjects use a different
|
|
55
|
+
* naming convention (`broadcast.{pattern}` instead of `{service}.{kind}.{pattern}`).
|
|
56
|
+
*/
|
|
57
|
+
type SubjectKind = Exclude<StreamKind, StreamKind.Broadcast>;
|
|
58
|
+
|
|
36
59
|
/** Discriminates the kind of message routed through the transport. */
|
|
37
60
|
declare enum MessageKind {
|
|
38
61
|
Event = "event",
|
|
39
62
|
Rpc = "rpc"
|
|
40
63
|
}
|
|
64
|
+
/** Outcome of a handler invocation, used as a label on processing metrics. */
|
|
65
|
+
type HandlerStatus = 'success' | 'error' | 'retried' | 'terminated';
|
|
66
|
+
/**
|
|
67
|
+
* Outcome of a client publish (event emit or RPC publish leg). Outbound
|
|
68
|
+
* operations either acknowledge cleanly or surface a transport error — there
|
|
69
|
+
* is no retried/terminated dimension at the publish boundary.
|
|
70
|
+
*/
|
|
71
|
+
type PublishStatus = 'success' | 'error';
|
|
72
|
+
/**
|
|
73
|
+
* Outcome of a full RPC round-trip from the caller's perspective. Adds the
|
|
74
|
+
* `timeout` dimension on top of {@link PublishStatus} so percentile analysis
|
|
75
|
+
* can distinguish slow successes from deadline-exceeded calls.
|
|
76
|
+
*/
|
|
77
|
+
type RpcOutcomeStatus = 'success' | 'error' | 'timeout';
|
|
41
78
|
declare enum TransportEvent {
|
|
42
79
|
Connect = "connect",
|
|
43
80
|
Disconnect = "disconnect",
|
|
@@ -47,7 +84,11 @@ declare enum TransportEvent {
|
|
|
47
84
|
MessageRouted = "messageRouted",
|
|
48
85
|
ShutdownStart = "shutdownStart",
|
|
49
86
|
ShutdownComplete = "shutdownComplete",
|
|
50
|
-
DeadLetter = "deadLetter"
|
|
87
|
+
DeadLetter = "deadLetter",
|
|
88
|
+
ConsumerRecovered = "consumerRecovered",
|
|
89
|
+
HandlerCompleted = "handlerCompleted",
|
|
90
|
+
Published = "published",
|
|
91
|
+
RpcCompleted = "rpcCompleted"
|
|
51
92
|
}
|
|
52
93
|
/**
|
|
53
94
|
* Hook callbacks for transport lifecycle and operational events.
|
|
@@ -85,7 +126,59 @@ interface TransportHooks {
|
|
|
85
126
|
[TransportEvent.ShutdownComplete](): void;
|
|
86
127
|
/** Fired when a message exhausts all delivery attempts (dead letter). */
|
|
87
128
|
[TransportEvent.DeadLetter](info: DeadLetterInfo): void;
|
|
129
|
+
/**
|
|
130
|
+
* Fired when a consumer's self-healing flow successfully recovers after
|
|
131
|
+
* one or more failed restart attempts. Useful for "service is back" alerts
|
|
132
|
+
* and to balance the noise from preceding error/restart logs.
|
|
133
|
+
*
|
|
134
|
+
* @param label Stream kind label (`event`, `broadcast`, `ordered`, etc.)
|
|
135
|
+
* or consumer name passed to `createSelfHealingFlow`.
|
|
136
|
+
* @param attempts How many consecutive failed attempts preceded the recovery.
|
|
137
|
+
*/
|
|
138
|
+
[TransportEvent.ConsumerRecovered](label: string, attempts: number): void;
|
|
139
|
+
/**
|
|
140
|
+
* Fired immediately after a handler returns or throws.
|
|
141
|
+
*
|
|
142
|
+
* Used by built-in metrics; users can register their own handler for
|
|
143
|
+
* latency tracking, slow-handler alerting, or custom observability.
|
|
144
|
+
*
|
|
145
|
+
* @param subject The declared NATS pattern (from `@EventPattern` / `@MessagePattern`).
|
|
146
|
+
* @param kind Stream kind: `Event`, `Command`, `Broadcast`, `Ordered`.
|
|
147
|
+
* @param durationMs Wall-clock time in milliseconds from handler entry to settlement.
|
|
148
|
+
* @param status Outcome: `success`, `error`, `retried`, or `terminated`.
|
|
149
|
+
*/
|
|
150
|
+
[TransportEvent.HandlerCompleted](subject: string, kind: StreamKind, durationMs: number, status: HandlerStatus): void;
|
|
151
|
+
/**
|
|
152
|
+
* Fired after every client-side publish (event emit or RPC publish leg)
|
|
153
|
+
* completes, regardless of outcome.
|
|
154
|
+
*
|
|
155
|
+
* @param subject Declared user pattern (e.g. `orders.created`) — bounded
|
|
156
|
+
* by handler registration, safe for high-cardinality labels.
|
|
157
|
+
* @param kind Stream kind the publish targets: `Event`, `Broadcast`,
|
|
158
|
+
* `Ordered`, or `Command` (RPC publish leg).
|
|
159
|
+
* @param durationMs Wall-clock time from publish initiation to ack/error.
|
|
160
|
+
* @param status `success` when the publish acked, `error` otherwise.
|
|
161
|
+
*/
|
|
162
|
+
[TransportEvent.Published](subject: string, kind: StreamKind, durationMs: number, status: PublishStatus): void;
|
|
163
|
+
/**
|
|
164
|
+
* Fired after an RPC round-trip completes from the caller's perspective —
|
|
165
|
+
* either a reply is received, the call errors out, or the deadline expires.
|
|
166
|
+
*
|
|
167
|
+
* Distinct from {@link Published} which only covers the publish leg.
|
|
168
|
+
*
|
|
169
|
+
* @param subject Declared command pattern (e.g. `orders.get`).
|
|
170
|
+
* @param durationMs Wall-clock time from request initiation to settlement.
|
|
171
|
+
* @param status `success` for a successful reply, `error` for transport/
|
|
172
|
+
* handler errors, `timeout` when the deadline expired.
|
|
173
|
+
*/
|
|
174
|
+
[TransportEvent.RpcCompleted](subject: string, durationMs: number, status: RpcOutcomeStatus): void;
|
|
88
175
|
}
|
|
176
|
+
/**
|
|
177
|
+
* Internal subscriber for a transport event. Multiple subscribers may be
|
|
178
|
+
* registered per event via `EventBus.subscribe()` — used by built-in
|
|
179
|
+
* observers (e.g. metrics) without overriding the user-provided hook.
|
|
180
|
+
*/
|
|
181
|
+
type TransportEventSubscriber<K extends keyof TransportHooks> = (...args: Parameters<TransportHooks[K]>) => unknown;
|
|
89
182
|
/**
|
|
90
183
|
* Context passed to the onDeadLetter callback when a message exhausts all delivery attempts.
|
|
91
184
|
*/
|
|
@@ -118,6 +211,49 @@ interface JetstreamHealthStatus {
|
|
|
118
211
|
latency: number | null;
|
|
119
212
|
}
|
|
120
213
|
|
|
214
|
+
/**
|
|
215
|
+
* Labels (in seconds) for histogram bucket configuration.
|
|
216
|
+
* Override defaults via `JetstreamModuleOptions.metrics.buckets`.
|
|
217
|
+
*/
|
|
218
|
+
interface HistogramBuckets {
|
|
219
|
+
/** Buckets for `jetstream_handler_duration_seconds`. */
|
|
220
|
+
handlerDuration?: number[];
|
|
221
|
+
/** Buckets for `jetstream_publish_duration_seconds`. */
|
|
222
|
+
publishDuration?: number[];
|
|
223
|
+
/** Buckets for `jetstream_rpc_duration_seconds`. */
|
|
224
|
+
rpcDuration?: number[];
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Configuration for built-in Prometheus metrics. All fields are optional;
|
|
228
|
+
* sensible production defaults are applied when missing.
|
|
229
|
+
*/
|
|
230
|
+
interface MetricsConfig {
|
|
231
|
+
/**
|
|
232
|
+
* `prom-client` registry to write metrics into. Defaults to the global
|
|
233
|
+
* `register` from `prom-client`, which is also what
|
|
234
|
+
* `@willsoto/nestjs-prometheus` exposes via `/metrics`.
|
|
235
|
+
*/
|
|
236
|
+
register?: Registry;
|
|
237
|
+
/** Metric name prefix. Defaults to `'jetstream_'`. */
|
|
238
|
+
prefix?: string;
|
|
239
|
+
/** Labels merged into every metric. Useful for service/env tagging. */
|
|
240
|
+
defaultLabels?: Record<string, string>;
|
|
241
|
+
/**
|
|
242
|
+
* Polling interval (ms) for gauge metrics that query `JetStreamManager`
|
|
243
|
+
* (consumer pending, stream messages, etc.). Default `15_000`.
|
|
244
|
+
* Set to `0` to disable polling — counter/histogram metrics still update
|
|
245
|
+
* via the event bus.
|
|
246
|
+
*/
|
|
247
|
+
pollInterval?: number;
|
|
248
|
+
/** Override default histogram buckets. */
|
|
249
|
+
buckets?: HistogramBuckets;
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Shorthand for `MetricsConfig`. Pass `true` to enable with all defaults,
|
|
253
|
+
* `false` (or omit) to disable entirely.
|
|
254
|
+
*/
|
|
255
|
+
type MetricsOption = boolean | MetricsConfig;
|
|
256
|
+
|
|
121
257
|
/**
|
|
122
258
|
* Instrumentation scope name reported on every span the library emits.
|
|
123
259
|
* Matches the npm package name — the convention used by
|
|
@@ -188,31 +324,27 @@ declare const DEFAULT_TRACES: readonly JetstreamTrace[];
|
|
|
188
324
|
/**
|
|
189
325
|
* Central event bus for transport lifecycle notifications.
|
|
190
326
|
*
|
|
191
|
-
*
|
|
192
|
-
* registered
|
|
327
|
+
* Two emission paths:
|
|
328
|
+
* - User hooks registered via `forRoot({ hooks })` — at most one per event.
|
|
329
|
+
* - Internal subscribers added via `subscribe()` — many per event, used by
|
|
330
|
+
* metrics and other built-in observers.
|
|
193
331
|
*
|
|
194
|
-
*
|
|
195
|
-
*
|
|
196
|
-
* const bus = new EventBus(logger, {
|
|
197
|
-
* [TransportEvent.Error]: (err) => sentry.captureException(err),
|
|
198
|
-
* });
|
|
199
|
-
*
|
|
200
|
-
* bus.emit(TransportEvent.Error, new Error('timeout'), 'rpc-router');
|
|
201
|
-
* // → calls sentry
|
|
202
|
-
*
|
|
203
|
-
* bus.emit(TransportEvent.Connect, 'nats://localhost:4222');
|
|
204
|
-
* // → no-op (no hook registered)
|
|
205
|
-
* ```
|
|
332
|
+
* Both fire on every `emit()` call. Subscriber failures are isolated and
|
|
333
|
+
* logged; they do not block other subscribers or the user hook.
|
|
206
334
|
*/
|
|
207
335
|
declare class EventBus {
|
|
208
336
|
private readonly hooks;
|
|
209
337
|
private readonly logger;
|
|
338
|
+
private readonly subscribers;
|
|
210
339
|
constructor(logger: Logger, hooks?: Partial<TransportHooks>);
|
|
211
340
|
/**
|
|
212
|
-
*
|
|
213
|
-
*
|
|
214
|
-
|
|
215
|
-
|
|
341
|
+
* Subscribe to a transport event. Used by built-in observers (e.g. metrics).
|
|
342
|
+
* Multiple subscribers per event are supported; each is called independently.
|
|
343
|
+
*/
|
|
344
|
+
subscribe<K extends keyof TransportHooks>(event: K, handler: TransportEventSubscriber<K>): void;
|
|
345
|
+
/**
|
|
346
|
+
* Emit a lifecycle event. Dispatches to all internal subscribers and the
|
|
347
|
+
* registered user hook (if any).
|
|
216
348
|
*/
|
|
217
349
|
emit<K extends keyof TransportHooks>(event: K, ...args: Parameters<TransportHooks[K]>): void;
|
|
218
350
|
/**
|
|
@@ -221,12 +353,12 @@ declare class EventBus {
|
|
|
221
353
|
*/
|
|
222
354
|
emitMessageRouted(subject: string, kind: MessageKind): void;
|
|
223
355
|
/**
|
|
224
|
-
* Check whether
|
|
225
|
-
*
|
|
226
|
-
*
|
|
227
|
-
* transport owner did not register a listener.
|
|
356
|
+
* Check whether any listener (user hook or internal subscriber) is registered
|
|
357
|
+
* for the given event. Used by routing hot path to elide the emit call when
|
|
358
|
+
* no one is listening.
|
|
228
359
|
*/
|
|
229
360
|
hasHook(event: keyof TransportHooks): boolean;
|
|
361
|
+
private dispatch;
|
|
230
362
|
private callHook;
|
|
231
363
|
}
|
|
232
364
|
|
|
@@ -391,6 +523,8 @@ declare class JetstreamClient extends ClientProxy {
|
|
|
391
523
|
private publishCoreRpc;
|
|
392
524
|
/** JetStream mode: publish to stream + wait for inbox response. */
|
|
393
525
|
private publishJetStreamRpc;
|
|
526
|
+
private reportPublished;
|
|
527
|
+
private reportRpcCompleted;
|
|
394
528
|
/** Fail-fast all pending JetStream RPC callbacks on connection loss. */
|
|
395
529
|
private handleDisconnect;
|
|
396
530
|
/** Reject all pending RPC callbacks, clear timeouts, and tear down inbox. */
|
|
@@ -1069,6 +1203,30 @@ interface JetstreamModuleOptions {
|
|
|
1069
1203
|
* Merged with `name` and `servers` — those take precedence.
|
|
1070
1204
|
*/
|
|
1071
1205
|
connectionOptions?: Partial<ConnectionOptions>;
|
|
1206
|
+
/**
|
|
1207
|
+
* Built-in Prometheus metrics.
|
|
1208
|
+
*
|
|
1209
|
+
* Pass `true` to enable with defaults, or a {@link MetricsConfig} object for
|
|
1210
|
+
* full control (custom registry, prefix, labels, polling, buckets).
|
|
1211
|
+
* When omitted or `false`, the metrics module is not registered and
|
|
1212
|
+
* `prom-client` is not imported — zero overhead.
|
|
1213
|
+
*
|
|
1214
|
+
* Requires `prom-client` peer dependency to be installed when enabled.
|
|
1215
|
+
* The service writes to `prom-client`'s global `register` by default,
|
|
1216
|
+
* making integration with `@willsoto/nestjs-prometheus` (or any
|
|
1217
|
+
* `prom-client`-based `/metrics` exporter) work without coordination.
|
|
1218
|
+
*
|
|
1219
|
+
* @see MetricsConfig
|
|
1220
|
+
* @example
|
|
1221
|
+
* ```typescript
|
|
1222
|
+
* JetstreamModule.forRoot({
|
|
1223
|
+
* name: 'orders',
|
|
1224
|
+
* servers: ['nats://localhost:4222'],
|
|
1225
|
+
* metrics: true,
|
|
1226
|
+
* })
|
|
1227
|
+
* ```
|
|
1228
|
+
*/
|
|
1229
|
+
metrics?: MetricsOption;
|
|
1072
1230
|
/**
|
|
1073
1231
|
* OpenTelemetry integration. When omitted, sensible defaults are applied:
|
|
1074
1232
|
* tracing is enabled, default trace kinds are emitted, only standard
|
|
@@ -1076,9 +1234,12 @@ interface JetstreamModuleOptions {
|
|
|
1076
1234
|
* consuming application, all tracer calls are no-ops — there is no
|
|
1077
1235
|
* runtime cost.
|
|
1078
1236
|
*
|
|
1237
|
+
* Accepts a full {@link OtelOptions} object, or the boolean shorthand
|
|
1238
|
+
* `true` (== defaults) / `false` (== `{ enabled: false }`).
|
|
1239
|
+
*
|
|
1079
1240
|
* @see OtelOptions
|
|
1080
1241
|
*/
|
|
1081
|
-
otel?: OtelOptions;
|
|
1242
|
+
otel?: OtelOptions | boolean;
|
|
1082
1243
|
}
|
|
1083
1244
|
/** Options for `JetstreamModule.forFeature()`. */
|
|
1084
1245
|
interface JetstreamFeatureOptions {
|
|
@@ -1117,28 +1278,6 @@ type JetstreamModuleAsyncOptions = {
|
|
|
1117
1278
|
useExisting?: never;
|
|
1118
1279
|
});
|
|
1119
1280
|
|
|
1120
|
-
/**
|
|
1121
|
-
* Identifies a JetStream stream/consumer kind.
|
|
1122
|
-
*
|
|
1123
|
-
* - `Event` — Workqueue events (at-least-once delivery to one consumer).
|
|
1124
|
-
* - `Command` — RPC commands (JetStream mode only).
|
|
1125
|
-
* - `Broadcast` — Broadcast events (fan-out to all consumers).
|
|
1126
|
-
* - `Ordered` — Ordered events (strict sequential delivery, Limits retention).
|
|
1127
|
-
*/
|
|
1128
|
-
declare enum StreamKind {
|
|
1129
|
-
Event = "ev",
|
|
1130
|
-
Command = "cmd",
|
|
1131
|
-
Broadcast = "broadcast",
|
|
1132
|
-
Ordered = "ordered"
|
|
1133
|
-
}
|
|
1134
|
-
/**
|
|
1135
|
-
* Subset of {@link StreamKind} used for direct subject building.
|
|
1136
|
-
*
|
|
1137
|
-
* Excludes `Broadcast` because broadcast subjects use a different
|
|
1138
|
-
* naming convention (`broadcast.{pattern}` instead of `{service}.{kind}.{pattern}`).
|
|
1139
|
-
*/
|
|
1140
|
-
type SubjectKind = Exclude<StreamKind, StreamKind.Broadcast>;
|
|
1141
|
-
|
|
1142
1281
|
/** Options for one-shot delayed delivery via NATS 2.12 message scheduling. */
|
|
1143
1282
|
interface ScheduleRecordOptions {
|
|
1144
1283
|
/** When to deliver the message. Must be in the future. */
|
|
@@ -1211,6 +1350,17 @@ declare class PatternRegistry {
|
|
|
1211
1350
|
registerHandlers(handlers: Map<string, MessageHandler>): void;
|
|
1212
1351
|
/** Find handler for a full NATS subject. */
|
|
1213
1352
|
getHandler(subject: string): MessageHandler | null;
|
|
1353
|
+
/**
|
|
1354
|
+
* Resolve the declared pattern and {@link StreamKind} for a full NATS subject.
|
|
1355
|
+
*
|
|
1356
|
+
* Returns `null` when the subject is not registered. The declared pattern is
|
|
1357
|
+
* the value the user passed to `@EventPattern`/`@MessagePattern` — stable and
|
|
1358
|
+
* bounded, suitable for use as a Prometheus label without cardinality risk.
|
|
1359
|
+
*/
|
|
1360
|
+
resolveDeclared(subject: string): {
|
|
1361
|
+
pattern: string;
|
|
1362
|
+
kind: StreamKind;
|
|
1363
|
+
} | null;
|
|
1214
1364
|
/** Get all registered broadcast patterns (for consumer filter_subject setup). */
|
|
1215
1365
|
getBroadcastPatterns(): string[];
|
|
1216
1366
|
hasBroadcastHandlers(): boolean;
|
|
@@ -1262,6 +1412,7 @@ declare class CoreRpcServer {
|
|
|
1262
1412
|
stop(): void;
|
|
1263
1413
|
/** Handle an incoming Core NATS request. */
|
|
1264
1414
|
private handleRequest;
|
|
1415
|
+
private reportHandlerCompleted;
|
|
1265
1416
|
/** Send an error response back to the caller with x-error header. */
|
|
1266
1417
|
private respondWithError;
|
|
1267
1418
|
}
|
|
@@ -1660,6 +1811,18 @@ declare class JetstreamStrategy extends Server implements CustomTransportStrateg
|
|
|
1660
1811
|
listen(callback: () => void): Promise<void>;
|
|
1661
1812
|
/** Stop all consumers, routers, subscriptions, and metadata heartbeat. Called during shutdown. */
|
|
1662
1813
|
close(): void;
|
|
1814
|
+
/**
|
|
1815
|
+
* Override NestJS `Server.addHandler` to fail-fast on duplicate pattern registration.
|
|
1816
|
+
*
|
|
1817
|
+
* The base class silently overwrites duplicate RPC handlers (last wins) and appends
|
|
1818
|
+
* duplicate event handlers to a linked list. Both behaviors are hazardous in a
|
|
1819
|
+
* JetStream context: silent overwrite drops a handler the user wrote, and double
|
|
1820
|
+
* event dispatch double-acks/double-processes the same JetStream message.
|
|
1821
|
+
*
|
|
1822
|
+
* We treat any pattern collision as a fatal misconfiguration so it surfaces at
|
|
1823
|
+
* bootstrap instead of in production traffic.
|
|
1824
|
+
*/
|
|
1825
|
+
addHandler(pattern: unknown, callback: MessageHandler, isEventHandler?: boolean, extras?: Record<string, unknown>): void;
|
|
1663
1826
|
/**
|
|
1664
1827
|
* Register event listener (required by Server base class).
|
|
1665
1828
|
*
|