@horizon-republic/nestjs-jetstream 1.0.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.
Files changed (108) hide show
  1. package/LICENSE.md +21 -0
  2. package/README.md +180 -0
  3. package/dist/client/index.d.ts +2 -0
  4. package/dist/client/index.d.ts.map +1 -0
  5. package/dist/client/index.js +18 -0
  6. package/dist/client/index.js.map +1 -0
  7. package/dist/client/jetstream-client.module.d.ts +6 -0
  8. package/dist/client/jetstream-client.module.d.ts.map +1 -0
  9. package/dist/client/jetstream-client.module.js +68 -0
  10. package/dist/client/jetstream-client.module.js.map +1 -0
  11. package/dist/client/jetstream.client-proxy.d.ts +179 -0
  12. package/dist/client/jetstream.client-proxy.d.ts.map +1 -0
  13. package/dist/client/jetstream.client-proxy.js +300 -0
  14. package/dist/client/jetstream.client-proxy.js.map +1 -0
  15. package/dist/client/types/index.d.ts +7 -0
  16. package/dist/client/types/index.d.ts.map +1 -0
  17. package/dist/client/types/index.js +3 -0
  18. package/dist/client/types/index.js.map +1 -0
  19. package/dist/common/connection.provider.d.ts +309 -0
  20. package/dist/common/connection.provider.d.ts.map +1 -0
  21. package/dist/common/connection.provider.js +326 -0
  22. package/dist/common/connection.provider.js.map +1 -0
  23. package/dist/common/enum/service-type.enum.d.ts +5 -0
  24. package/dist/common/enum/service-type.enum.d.ts.map +1 -0
  25. package/dist/common/enum/service-type.enum.js +9 -0
  26. package/dist/common/enum/service-type.enum.js.map +1 -0
  27. package/dist/common/helpers.d.ts +14 -0
  28. package/dist/common/helpers.d.ts.map +1 -0
  29. package/dist/common/helpers.js +21 -0
  30. package/dist/common/helpers.js.map +1 -0
  31. package/dist/common/index.d.ts +2 -0
  32. package/dist/common/index.d.ts.map +1 -0
  33. package/dist/common/index.js +7 -0
  34. package/dist/common/index.js.map +1 -0
  35. package/dist/common/pattern-registry.d.ts +51 -0
  36. package/dist/common/pattern-registry.d.ts.map +1 -0
  37. package/dist/common/pattern-registry.js +86 -0
  38. package/dist/common/pattern-registry.js.map +1 -0
  39. package/dist/common/rpc.context.d.ts +8 -0
  40. package/dist/common/rpc.context.d.ts.map +1 -0
  41. package/dist/common/rpc.context.js +14 -0
  42. package/dist/common/rpc.context.js.map +1 -0
  43. package/dist/common/types/index.d.ts +2 -0
  44. package/dist/common/types/index.d.ts.map +1 -0
  45. package/dist/common/types/index.js +18 -0
  46. package/dist/common/types/index.js.map +1 -0
  47. package/dist/common/types/jetstream-transport.options.d.ts +60 -0
  48. package/dist/common/types/jetstream-transport.options.d.ts.map +1 -0
  49. package/dist/common/types/jetstream-transport.options.js +3 -0
  50. package/dist/common/types/jetstream-transport.options.js.map +1 -0
  51. package/dist/enum/index.d.ts +16 -0
  52. package/dist/enum/index.d.ts.map +1 -0
  53. package/dist/enum/index.js +21 -0
  54. package/dist/enum/index.js.map +1 -0
  55. package/dist/index.d.ts +4 -0
  56. package/dist/index.d.ts.map +1 -0
  57. package/dist/index.js +20 -0
  58. package/dist/index.js.map +1 -0
  59. package/dist/server/const/index.d.ts +4 -0
  60. package/dist/server/const/index.d.ts.map +1 -0
  61. package/dist/server/const/index.js +96 -0
  62. package/dist/server/const/index.js.map +1 -0
  63. package/dist/server/enum/index.d.ts +5 -0
  64. package/dist/server/enum/index.d.ts.map +1 -0
  65. package/dist/server/enum/index.js +9 -0
  66. package/dist/server/enum/index.js.map +1 -0
  67. package/dist/server/index.d.ts +3 -0
  68. package/dist/server/index.d.ts.map +1 -0
  69. package/dist/server/index.js +19 -0
  70. package/dist/server/index.js.map +1 -0
  71. package/dist/server/jetstream-server.module.d.ts +157 -0
  72. package/dist/server/jetstream-server.module.d.ts.map +1 -0
  73. package/dist/server/jetstream-server.module.js +375 -0
  74. package/dist/server/jetstream-server.module.js.map +1 -0
  75. package/dist/server/jetstream.strategy.d.ts +150 -0
  76. package/dist/server/jetstream.strategy.d.ts.map +1 -0
  77. package/dist/server/jetstream.strategy.js +192 -0
  78. package/dist/server/jetstream.strategy.js.map +1 -0
  79. package/dist/server/jetstream.transport.d.ts +9 -0
  80. package/dist/server/jetstream.transport.d.ts.map +1 -0
  81. package/dist/server/jetstream.transport.js +26 -0
  82. package/dist/server/jetstream.transport.js.map +1 -0
  83. package/dist/server/providers/consumer.provider.d.ts +226 -0
  84. package/dist/server/providers/consumer.provider.d.ts.map +1 -0
  85. package/dist/server/providers/consumer.provider.js +272 -0
  86. package/dist/server/providers/consumer.provider.js.map +1 -0
  87. package/dist/server/providers/message-routing.provider.d.ts +295 -0
  88. package/dist/server/providers/message-routing.provider.d.ts.map +1 -0
  89. package/dist/server/providers/message-routing.provider.js +420 -0
  90. package/dist/server/providers/message-routing.provider.js.map +1 -0
  91. package/dist/server/providers/message.provider.d.ts +142 -0
  92. package/dist/server/providers/message.provider.d.ts.map +1 -0
  93. package/dist/server/providers/message.provider.js +209 -0
  94. package/dist/server/providers/message.provider.js.map +1 -0
  95. package/dist/server/providers/stream.provider.d.ts +320 -0
  96. package/dist/server/providers/stream.provider.d.ts.map +1 -0
  97. package/dist/server/providers/stream.provider.js +376 -0
  98. package/dist/server/providers/stream.provider.js.map +1 -0
  99. package/dist/server/types/index.d.ts +7 -0
  100. package/dist/server/types/index.d.ts.map +1 -0
  101. package/dist/server/types/index.js +3 -0
  102. package/dist/server/types/index.js.map +1 -0
  103. package/dist/server/types/nats.events-map.d.ts +22 -0
  104. package/dist/server/types/nats.events-map.d.ts.map +1 -0
  105. package/dist/server/types/nats.events-map.js +4 -0
  106. package/dist/server/types/nats.events-map.js.map +1 -0
  107. package/dist/tsconfig.tsbuildinfo +1 -0
  108. package/package.json +76 -0
@@ -0,0 +1,300 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.JetstreamClientProxy = void 0;
4
+ const common_1 = require("@nestjs/common");
5
+ const microservices_1 = require("@nestjs/microservices");
6
+ const nats_1 = require("nats");
7
+ const rxjs_1 = require("rxjs");
8
+ const uuid_1 = require("uuid");
9
+ const enum_1 = require("../enum");
10
+ /**
11
+ * NATS JetStream client proxy for NestJS microservices.
12
+ *
13
+ * Implements hybrid messaging pattern:
14
+ * - Events: Fire-and-forget via JetStream (guaranteed delivery, no response)
15
+ * - Commands: Request-reply via JetStream + Core NATS inbox (RPC with response).
16
+ *
17
+ * Architecture:.
18
+ * ```
19
+ * Events: Client --[JetStream publish]--> Stream --> Consumers
20
+ * └─> returns immediately
21
+ *
22
+ * Commands: Client --[JetStream publish]--> Stream --> Consumer
23
+ * └─[inbox subscribe]<--[Core NATS publish]<-- Response
24
+ * └─> waits for response via callback
25
+ * ```
26
+ *
27
+ * @example
28
+ * ```typescript
29
+ * // Fire-and-forget event
30
+ * await firstValueFrom(client.emit('user.created', { id: 1 }));
31
+ *
32
+ * // Request-reply command
33
+ * const user = await firstValueFrom(client.send('get.user', { id: 1 }));
34
+ * ```
35
+ */
36
+ class JetstreamClientProxy extends microservices_1.ClientProxy {
37
+ constructor(providers) {
38
+ super();
39
+ this.providers = providers;
40
+ this.logger = new common_1.Logger(JetstreamClientProxy.name);
41
+ this.destroy$ = new rxjs_1.Subject();
42
+ /**
43
+ * Unique inbox subject for receiving RPC responses.
44
+ * Format: <service_name>.<random>
45
+ * Shared across all command requests from this client instance.
46
+ */
47
+ this.inbox = (0, nats_1.createInbox)(this.providers.options.name);
48
+ // todo: make configurable
49
+ this.codec = (0, nats_1.JSONCodec)();
50
+ /**
51
+ * Map of pending RPC requests awaiting responses.
52
+ * Key: correlation ID (UUID v7)
53
+ * Value: callback to invoke when response arrives.
54
+ */
55
+ this.pendingMessages = new Map();
56
+ /**
57
+ * Flag to prevent duplicate inbox subscriptions.
58
+ * Reset to false on connection errors to allow re-subscription.
59
+ */
60
+ this.isInboxSubscribed = false;
61
+ }
62
+ /**
63
+ * Establish connection and setup inbox on module initialization to don't wait for the first request.
64
+ */
65
+ onModuleInit() {
66
+ void this.connect();
67
+ }
68
+ /**
69
+ * Establishes NATS connection and sets up an inbox subscription for RPC responses.
70
+ *
71
+ * Idempotent: multiple calls reuse existing connection and subscription.
72
+ * Automatically recovers subscription after reconnection.
73
+ *
74
+ * @returns Promise resolving to active NATS connection.
75
+ */
76
+ async connect() {
77
+ const nc = await (0, rxjs_1.firstValueFrom)(this.providers.connectionProvider.nc);
78
+ if (!this.isInboxSubscribed) {
79
+ this.isInboxSubscribed = true;
80
+ this.providers.connectionProvider.nc
81
+ .pipe((0, rxjs_1.tap)((connection) => {
82
+ if (!connection.isClosed() && !connection.isDraining()) {
83
+ this.setupInboxSubscription(connection);
84
+ }
85
+ }), (0, rxjs_1.takeUntil)(this.destroy$))
86
+ .subscribe({
87
+ error: (err) => {
88
+ this.logger.error('Connection stream error, will retry on next connect()', err);
89
+ this.isInboxSubscribed = false;
90
+ },
91
+ });
92
+ }
93
+ return nc;
94
+ }
95
+ /**
96
+ * Gracefully closes connection and cleans up resources.
97
+ *
98
+ * Emits destroy signal to stop connection monitoring,
99
+ * completes all pending observables, and closes NATS connection.
100
+ */
101
+ async close() {
102
+ this.logger.debug('Closing client and cleaning up resources');
103
+ this.destroy$.next();
104
+ this.destroy$.complete();
105
+ const nc = await (0, rxjs_1.firstValueFrom)(this.providers.connectionProvider.nc);
106
+ await nc.close();
107
+ }
108
+ /**
109
+ * Returns raw NATS connection for advanced use cases.
110
+ *
111
+ * @returns Raw NATS connection instance.
112
+ */
113
+ unwrap() {
114
+ return this.providers.connectionProvider.unwrap;
115
+ }
116
+ /**
117
+ * Publishes fire-and-forget event to JetStream.
118
+ *
119
+ * Does not wait for acknowledgment or response.
120
+ * JetStream guarantees persistence and at-least-once delivery to consumers.
121
+ *
122
+ * @param packet Event packet containing pattern and data.
123
+ * @returns Promise resolving immediately after publish (undefined).
124
+ */
125
+ async dispatchEvent(packet) {
126
+ const subject = this.buildSubject(enum_1.JetStreamKind.Event, packet.pattern);
127
+ const messageId = (0, uuid_1.v7)();
128
+ const nc = await this.connect();
129
+ const hdrs = this.createHeaders({ messageId, subject });
130
+ // Fire-and-forget: don't await acknowledgment
131
+ void nc.jetstream().publish(subject, this.codec.encode(packet.data), { headers: hdrs });
132
+ return undefined;
133
+ }
134
+ /**
135
+ * Publishes RPC command to JetStream and registers callback for response.
136
+ *
137
+ * Command is persisted in JetStream for guaranteed delivery.
138
+ * Response arrives via Core NATS inbox subscription.
139
+ *
140
+ * Pattern:
141
+ * 1. Register callback in pending map with correlation ID
142
+ * 2. Publish command with reply-to inbox address
143
+ * 3. Consumer processes command and publishes response to inbox
144
+ * 4. Inbox subscription routes response to callback via correlation ID.
145
+ *
146
+ * @param packet Command packet containing pattern and data.
147
+ * @param callback Function to invoke when response arrives or error occurs.
148
+ * @returns Cleanup function to cancel pending request.
149
+ */
150
+ publish(packet, callback) {
151
+ const subject = this.buildSubject(enum_1.JetStreamKind.Command, packet.pattern);
152
+ const correlationId = (0, uuid_1.v7)();
153
+ const messageId = (0, uuid_1.v7)();
154
+ this.pendingMessages.set(correlationId, callback);
155
+ void this.publishCommand(subject, packet.data, { correlationId, messageId, callback });
156
+ return () => {
157
+ this.pendingMessages.delete(correlationId);
158
+ };
159
+ }
160
+ /**
161
+ * Internal: executes command publication with error handling.
162
+ *
163
+ * Invokes callback immediately on publish error to fail fast.
164
+ * On success, response will arrive asynchronously via inbox.
165
+ *
166
+ * @param subject Fully-qualified NATS subject to publish to.
167
+ * @param data Payload data to encode and send.
168
+ * @param ctx Context object containing correlation metadata.
169
+ * @param ctx.correlationId UUID v7 linking request and response.
170
+ * @param ctx.messageId Unique message identifier for tracing.
171
+ * @param ctx.callback Function to invoke on error or when response arrives.
172
+ */
173
+ async publishCommand(subject, data, ctx) {
174
+ try {
175
+ const nc = await this.connect();
176
+ const hdrs = this.createHeaders({
177
+ correlationId: ctx.correlationId,
178
+ messageId: ctx.messageId,
179
+ subject,
180
+ replyTo: this.inbox,
181
+ });
182
+ await nc.jetstream().publish(subject, this.codec.encode(data), { headers: hdrs });
183
+ }
184
+ catch (error) {
185
+ this.logger.error(`Command publish failed: ${subject}`, error);
186
+ // Fail fast: invoke callback with error
187
+ ctx.callback({
188
+ err: error instanceof Error ? error.message : 'Unknown error',
189
+ response: null,
190
+ });
191
+ this.pendingMessages.delete(ctx.correlationId);
192
+ }
193
+ }
194
+ /**
195
+ * Sets up Core NATS subscription to inbox for receiving RPC responses.
196
+ *
197
+ * Inbox subscription persists across multiple command requests.
198
+ * Each response is routed to the correct callback via correlation ID.
199
+ *
200
+ * Note: Uses Core NATS (not JetStream) for low-latency, ephemeral replies.
201
+ *
202
+ * @param nc Active NATS connection to subscribe with.
203
+ */
204
+ setupInboxSubscription(nc) {
205
+ this.logger.log(`Inbox subscription established: ${this.inbox}`);
206
+ nc.subscribe(this.inbox, {
207
+ callback: (error, msg) => {
208
+ if (error) {
209
+ this.logger.error('Inbox subscription error:', error);
210
+ return;
211
+ }
212
+ this.routeReply(msg);
213
+ },
214
+ });
215
+ }
216
+ /**
217
+ * Routes inbox message to pending callback using correlation ID.
218
+ *
219
+ * Handles:
220
+ * - Missing correlation ID (warns and ignores)
221
+ * - No matching handler (warns - possible timeout/cleanup race)
222
+ * - Decoding errors (invokes callback with error)
223
+ * - Success (invokes callback with response).
224
+ *
225
+ * Always cleans up pending message entry after processing.
226
+ *
227
+ * @param msg NATS message received in inbox subscription.
228
+ */
229
+ routeReply(msg) {
230
+ const correlationId = msg.headers?.get(enum_1.JetstreamHeaders.CorrelationId);
231
+ if (!correlationId) {
232
+ this.logger.warn('Received reply without correlation ID, ignoring');
233
+ return;
234
+ }
235
+ const handler = this.pendingMessages.get(correlationId);
236
+ if (!handler) {
237
+ this.logger.warn(`No pending handler for correlation ID: ${correlationId} ` +
238
+ '(possible timeout or already processed)');
239
+ return;
240
+ }
241
+ try {
242
+ const response = this.codec.decode(msg.data);
243
+ handler({ err: null, response, isDisposed: true });
244
+ }
245
+ catch (error) {
246
+ this.logger.error(`Failed to decode response (cid: ${correlationId})`, error);
247
+ handler({ err: error.message, response: null, isDisposed: true });
248
+ }
249
+ finally {
250
+ this.pendingMessages.delete(correlationId);
251
+ }
252
+ }
253
+ /**
254
+ * Creates NATS message headers with common metadata.
255
+ *
256
+ * Standard headers:
257
+ * - message-id: Unique identifier for idempotency and tracing
258
+ * - subject: Full subject name for routing and debugging.
259
+ *
260
+ * Optional headers:
261
+ * - correlation-id: Links request and response for RPC pattern
262
+ * - reply-to: Inbox address for receiving responses.
263
+ *
264
+ * @param data Header data configuration object.
265
+ * @param data.messageId Unique message identifier (UUID v7).
266
+ * @param data.subject Fully-qualified NATS subject.
267
+ * @param data.correlationId Optional correlation ID for RPC linking.
268
+ * @param data.replyTo Optional inbox subject for receiving responses.
269
+ * @returns NATS message headers instance.
270
+ */
271
+ createHeaders(data) {
272
+ const hdrs = (0, nats_1.headers)();
273
+ hdrs.set(enum_1.JetstreamHeaders.MessageId, data.messageId);
274
+ hdrs.set(enum_1.JetstreamHeaders.Subject, data.subject);
275
+ if (data.correlationId) {
276
+ hdrs.set(enum_1.JetstreamHeaders.CorrelationId, data.correlationId);
277
+ }
278
+ if (data.replyTo) {
279
+ hdrs.set(enum_1.JetstreamHeaders.ReplyTo, data.replyTo);
280
+ }
281
+ return hdrs;
282
+ }
283
+ /**
284
+ * Builds fully-qualified NATS subject from kind and pattern.
285
+ *
286
+ * Format: <service-name>.<kind>.<pattern>
287
+ * Example: "user-service.Command.get.user".
288
+ *
289
+ * This namespacing prevents collisions between services and message types.
290
+ *
291
+ * @param kind Message type (Event or Command).
292
+ * @param pattern User-defined pattern from decorator (e.g., "get.user").
293
+ * @returns Fully-qualified NATS subject string.
294
+ */
295
+ buildSubject(kind, pattern) {
296
+ return `${this.providers.options.name}.${kind}.${pattern}`;
297
+ }
298
+ }
299
+ exports.JetstreamClientProxy = JetstreamClientProxy;
300
+ //# sourceMappingURL=jetstream.client-proxy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jetstream.client-proxy.js","sourceRoot":"","sources":["../../src/client/jetstream.client-proxy.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import { ConnectionProvider } from '../../common/connection.provider';
2
+ import { IJetstreamTransportOptions } from '../../common/types';
3
+ export interface IClientProviders {
4
+ options: IJetstreamTransportOptions;
5
+ connectionProvider: ConnectionProvider;
6
+ }
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/client/types/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,kCAAkC,CAAC;AACtE,OAAO,EAAE,0BAA0B,EAAE,MAAM,oBAAoB,CAAC;AAEhE,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,0BAA0B,CAAC;IACpC,kBAAkB,EAAE,kBAAkB,CAAC;CACxC"}
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/client/types/index.ts"],"names":[],"mappings":""}
@@ -0,0 +1,309 @@
1
+ import { OnModuleDestroy } from '@nestjs/common';
2
+ import { JetStreamManager, NatsConnection, NatsError, Status } from 'nats';
3
+ import { Observable } from 'rxjs';
4
+ import { IJetstreamTransportOptions } from './types';
5
+ /**
6
+ * Provider that manages the lifecycle of a NATS connection and JetStream manager.
7
+ *
8
+ * @description
9
+ * This provider is responsible for establishing and maintaining a connection to NATS servers,
10
+ * providing access to the JetStream manager, and handling connection lifecycle events.
11
+ * It serves as the foundation for all NATS JetStream operations in the transport.
12
+ *
13
+ * @remarks
14
+ * **Key responsibilities:**
15
+ *
16
+ * 1. **Connection management:**
17
+ * - Establishes connection to NATS servers on initialization
18
+ * - Provides reactive access to the connection via observables
19
+ * - Handles connection errors and reconnection events
20
+ * - Implements graceful shutdown with proper drain/close sequence
21
+ *
22
+ * 2. **JetStream integration:**
23
+ * - Creates and caches a JetStream manager instance
24
+ * - Provides reactive access to the manager via observable
25
+ * - Ensures manager is available before stream/consumer operations
26
+ *
27
+ * 3. **Status monitoring:**
28
+ * - Exposes connection status as an observable stream
29
+ * - Emits status events (connect, disconnect, reconnect, etc.)
30
+ * - Allows other components to react to connection state changes
31
+ *
32
+ * 4. **Resource cleanup:**
33
+ * - Implements OnModuleDestroy for proper lifecycle management
34
+ * - Ensures subscriptions are cleaned up on module destruction
35
+ * - Handles graceful shutdown on application termination
36
+ *
37
+ * **Observable caching:**
38
+ *
39
+ * The provider uses `shareReplay({ bufferSize: 1, refCount: false })` for connection
40
+ * and JetStream manager observables. This ensures:
41
+ * - Single connection instance shared across all subscribers
42
+ * - New subscribers immediately receive the cached connection
43
+ * - Connection persists even when all subscribers unsubscribe
44
+ * - No duplicate connection attempts
45
+ *
46
+ * **Error handling:**
47
+ *
48
+ * Connection errors are categorized:
49
+ * - `CONNECTION_REFUSED`: Terminal error, throws RuntimeException
50
+ * - Other errors: Non-terminal, returns EMPTY to allow reconnection attempts
51
+ *
52
+ * @example
53
+ * ```typescript
54
+ * // Basic usage in a provider
55
+ * class MyProvider {
56
+ * constructor(private connectionProvider: ConnectionProvider) {
57
+ * this.connectionProvider.nc.pipe(
58
+ * take(1),
59
+ * tap(connection => console.log('Connected to:', connection.nc))
60
+ * ).subscribe();
61
+ * }
62
+ * }
63
+ *
64
+ * // Monitoring connection status
65
+ * connectionProvider.status.subscribe(status => {
66
+ * console.log('Connection status:', status.type);
67
+ * });
68
+ *
69
+ * // Graceful shutdown
70
+ * connectionProvider.gracefulShutdown().subscribe(() => {
71
+ * console.log('Connection closed gracefully');
72
+ * });
73
+ * ```
74
+ *
75
+ * @see {@link https://docs.nats.io/using-nats/developer/connecting | NATS Connection Documentation}
76
+ * @see {@link https://docs.nats.io/nats-concepts/jetstream | JetStream Documentation}
77
+ */
78
+ export declare class ConnectionProvider implements OnModuleDestroy {
79
+ private readonly options;
80
+ private readonly logger;
81
+ /**
82
+ * Observable that emits the NATS connection once established.
83
+ * Cached and shared across all subscribers.
84
+ *
85
+ */
86
+ private nc$;
87
+ /**
88
+ * Observable that emits the JetStream manager once available.
89
+ * Cached and shared across all subscribers.
90
+ *
91
+ */
92
+ private jsm$;
93
+ /**
94
+ * Observable stream of connection status events.
95
+ * Emits events like connect, disconnect, reconnect, error, etc.
96
+ *
97
+ */
98
+ private status$;
99
+ /**
100
+ * Raw unwrapped NATS connection instance.
101
+ * Stored for direct access and graceful shutdown.
102
+ *
103
+ */
104
+ private unwrappedConnection;
105
+ /**
106
+ * Optional subscription for internal cleanup.
107
+ * Currently unused but available for future enhancements.
108
+ *
109
+ */
110
+ private readonly subscription?;
111
+ /**
112
+ * Creates a ConnectionProvider instance.
113
+ *
114
+ * @param options JetStream transport options including NATS connection configuration.
115
+ *
116
+ * @description
117
+ * Initializes the connection setup immediately in the constructor.
118
+ * The actual connection is established lazily when the nc$ observable is subscribed to.
119
+ */
120
+ constructor(options: IJetstreamTransportOptions);
121
+ /**
122
+ * Observable stream of connection status events.
123
+ *
124
+ * @description
125
+ * Provides access to the NATS connection status stream. Status events include:
126
+ * - `connect`: Initial connection established
127
+ * - `disconnect`: Connection lost
128
+ * - `reconnect`: Connection re-established after disconnect
129
+ * - `update`: Server discovery or cluster changes
130
+ * - `error`: Connection errors.
131
+ *
132
+ * This stream does NOT replay previous events (uses `share()` instead of `shareReplay`),
133
+ * so subscribers only receive events that occur after subscription.
134
+ *
135
+ * @returns Observable that emits connection status events.
136
+ *
137
+ * @example
138
+ * ```typescript
139
+ * connectionProvider.status.subscribe(status => {
140
+ * if (status.type === 'disconnect') {
141
+ * console.log('Connection lost, will attempt reconnect...');
142
+ * }
143
+ * });
144
+ * ```
145
+ */
146
+ get status(): Observable<Status>;
147
+ /**
148
+ * Observable that emits the NATS connection once established.
149
+ *
150
+ * @description
151
+ * Provides reactive access to the NATS connection. The connection is:
152
+ * - Established on first subscription (lazy)
153
+ * - Cached and shared across all subsequent subscribers
154
+ * - Persists even when all subscribers unsubscribe.
155
+ *
156
+ * Multiple subscriptions will share the same connection instance.
157
+ *
158
+ * @returns Observable that emits the NATS connection.
159
+ *
160
+ * @example
161
+ * ```typescript
162
+ * connectionProvider.nc.pipe(
163
+ * take(1),
164
+ * tap(nc => console.log('Server:', nc.getServer()))
165
+ * ).subscribe();
166
+ * ```
167
+ */
168
+ get nc(): Observable<NatsConnection>;
169
+ /**
170
+ * Observable that emits the JetStream manager once available.
171
+ *
172
+ * @description
173
+ * Provides reactive access to the JetStream manager instance.
174
+ * The manager is created from the NATS connection and enables:
175
+ * - Stream management (create, update, delete streams)
176
+ * - Consumer management (create, update, delete consumers)
177
+ * - Stream and consumer info queries.
178
+ *
179
+ * Like the connection, the manager is cached and shared.
180
+ *
181
+ * @returns Observable that emits the JetStream manager.
182
+ *
183
+ * @example
184
+ * ```typescript
185
+ * connectionProvider.jsm.pipe(
186
+ * take(1),
187
+ * switchMap(jsm => from(jsm.streams.list()))
188
+ * ).subscribe(streams => console.log('Streams:', streams));
189
+ * ```
190
+ */
191
+ get jsm(): Observable<JetStreamManager>;
192
+ /**
193
+ * Direct access to the unwrapped NATS connection.
194
+ *
195
+ * @description
196
+ * Provides synchronous access to the raw NATS connection instance.
197
+ * Use this when you need immediate access without subscribing to an observable.
198
+ *
199
+ * **Warning:** This getter assumes the connection has already been established.
200
+ * If called before the connection is ready, it will return undefined.
201
+ *
202
+ * @returns The raw NATS connection instance.
203
+ *
204
+ * @example
205
+ * ```typescript
206
+ * const nc = connectionProvider.unwrap;
207
+ * const serverUrl = nc.getServer();
208
+ * ```
209
+ */
210
+ get unwrap(): NatsConnection;
211
+ /**
212
+ * Lifecycle hook called when the module is being destroyed.
213
+ *
214
+ * @description
215
+ * Cleans up any active subscriptions to prevent memory leaks.
216
+ * Currently, the subscription is optional and may not be used.
217
+ */
218
+ onModuleDestroy(): void;
219
+ /**
220
+ * Gracefully shuts down the NATS connection.
221
+ *
222
+ * @description
223
+ * Implements a proper shutdown sequence:
224
+ *
225
+ * 1. Checks if connection is already closed
226
+ * - If yes: returns immediately (no-op)
227
+ * - If no: proceeds with shutdown.
228
+ *
229
+ * 2. Drains the connection:
230
+ * - Stops accepting new messages
231
+ * - Waits for pending outbound messages to be sent
232
+ * - Waits for pending subscriptions to be flushed.
233
+ *
234
+ * 3. Waits for connection close:
235
+ * - Waits for the connection to fully close
236
+ * - Ensures all resources are released.
237
+ *
238
+ * 4. Error handling:
239
+ * - If drain fails: attempts force close
240
+ * - If close fails: swallows error and returns void.
241
+ *
242
+ * This ensures messages are not lost during shutdown and resources
243
+ * are properly cleaned up.
244
+ *
245
+ * @returns Observable that completes when shutdown is finished or emits error if shutdown fails.
246
+ *
247
+ * @example
248
+ * ```typescript
249
+ * // In application shutdown hook
250
+ * connectionProvider.gracefulShutdown().subscribe({
251
+ * next: () => console.log('Connection closed'),
252
+ * error: (err) => console.error('Shutdown error:', err),
253
+ * });
254
+ * ```
255
+ */
256
+ gracefulShutdown(): Observable<void | Error | undefined>;
257
+ /**
258
+ * Sets up the NATS connection and related observables.
259
+ *
260
+ * @description
261
+ * This method initializes three key observables:
262
+ *
263
+ * 1. **Connection observable (nc$):**
264
+ * - Creates connection to NATS servers using provided options
265
+ * - Adds service type suffix to connection name for identification
266
+ * - Handles connection errors via handleError()
267
+ * - Logs successful connection with server URL
268
+ * - Stores raw connection reference in unwrappedConnection
269
+ * - Uses shareReplay to cache and share connection.
270
+ *
271
+ * 2. **JetStream manager observable (jsm$):**
272
+ * - Derives from connection observable
273
+ * - Creates JetStream manager from connection
274
+ * - Logs manager initialization
275
+ * - Uses shareReplay to cache and share manager.
276
+ *
277
+ * 3. **Status observable (status$):**
278
+ * - Derives from connection observable
279
+ * - Maps connection to its status iterator
280
+ * - Converts async iterator to observable
281
+ * - Uses share() for event bus behavior (no replay).
282
+ *
283
+ * The setup is lazy - actual connection happens on first subscription.
284
+ */
285
+ protected setupConnection(): void;
286
+ /**
287
+ * Handles connection errors with appropriate error strategies.
288
+ *
289
+ * @description
290
+ * Implements error categorization:
291
+ *
292
+ * - **CONNECTION_REFUSED:**
293
+ * This is a terminal error indicating NATS servers are unreachable.
294
+ * Throws RuntimeException to fail fast and prevent the application
295
+ * from starting in an inconsistent state.
296
+ *
297
+ * - **Other errors:**
298
+ * Non-terminal errors that may be transient (network issues, etc.).
299
+ * Returns EMPTY to complete the observable without emitting.
300
+ * This allows retry logic at higher levels to attempt reconnection.
301
+ *
302
+ * @param err The NATS error to handle.
303
+ * @returns Observable that either throws or completes empty.
304
+ *
305
+ * @throws {RuntimeException} When connection is refused (servers unreachable).
306
+ */
307
+ protected handleError(err: NatsError): Observable<NatsConnection>;
308
+ }
309
+ //# sourceMappingURL=connection.provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connection.provider.d.ts","sourceRoot":"","sources":["../../src/common/connection.provider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAErE,OAAO,EAGL,gBAAgB,EAChB,cAAc,EACd,SAAS,EACT,MAAM,EACP,MAAM,MAAM,CAAC;AACd,OAAO,EAKL,UAAU,EAQX,MAAM,MAAM,CAAC;AAEd,OAAO,EAAE,0BAA0B,EAAE,MAAM,SAAS,CAAC;AAErD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwEG;AACH,qBACa,kBAAmB,YAAW,eAAe;IA+CrC,OAAO,CAAC,QAAQ,CAAC,OAAO;IA9C3C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAuC;IAE9D;;;;OAIG;IACH,OAAO,CAAC,GAAG,CAA8B;IAEzC;;;;OAIG;IACH,OAAO,CAAC,IAAI,CAAgC;IAE5C;;;;OAIG;IACH,OAAO,CAAC,OAAO,CAAsB;IAErC;;;;OAIG;IACH,OAAO,CAAC,mBAAmB,CAAkB;IAE7C;;;;OAIG;IACH,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAe;IAE7C;;;;;;;;OAQG;gBACiC,OAAO,EAAE,0BAA0B;IAIvE;;;;;;;;;;;;;;;;;;;;;;;;OAwBG;IACH,IAAW,MAAM,IAAI,UAAU,CAAC,MAAM,CAAC,CAEtC;IAED;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,IAAW,EAAE,IAAI,UAAU,CAAC,cAAc,CAAC,CAE1C;IAED;;;;;;;;;;;;;;;;;;;;;OAqBG;IACH,IAAW,GAAG,IAAI,UAAU,CAAC,gBAAgB,CAAC,CAE7C;IAED;;;;;;;;;;;;;;;;;OAiBG;IACH,IAAW,MAAM,IAAI,cAAc,CAElC;IAED;;;;;;OAMG;IACI,eAAe,IAAI,IAAI;IAI9B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAoCG;IACI,gBAAgB,IAAI,UAAU,CAAC,IAAI,GAAG,KAAK,GAAG,SAAS,CAAC;IAiB/D;;;;;;;;;;;;;;;;;;;;;;;;;;;OA2BG;IACH,SAAS,CAAC,eAAe,IAAI,IAAI;IA+BjC;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,SAAS,CAAC,WAAW,CAAC,GAAG,EAAE,SAAS,GAAG,UAAU,CAAC,cAAc,CAAC;CAKlE"}