@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,209 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var MessageProvider_1;
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.MessageProvider = void 0;
14
+ const common_1 = require("@nestjs/common");
15
+ const rxjs_1 = require("rxjs");
16
+ const connection_provider_1 = require("../../common/connection.provider");
17
+ const enum_1 = require("../../enum");
18
+ const consumer_provider_1 = require("./consumer.provider");
19
+ /**
20
+ * Manages NATS JetStream pull-based message consumption with automatic reconnection.
21
+ *
22
+ * This provider orchestrates the lifecycle of JetStream consumers, handling:
23
+ * - Initial consumer setup and subscription
24
+ * - Automatic recovery from NATS restarts or connection failures
25
+ * - Separate handling for Event and Command (RPC) messages
26
+ * - Graceful shutdown and resource cleanup.
27
+ *
28
+ * The implementation uses RxJS `defer()` + `repeat()` pattern to ensure consumers
29
+ * automatically restart after the async iterator completes (e.g., during NATS restart),
30
+ * preventing message loss during reconnection windows.
31
+ *
32
+ * Message flow:
33
+ * - Event messages → eventMessages$ subject (ack immediately)
34
+ * - Command messages → commandMessages$ subject (ack after handler success).
35
+ */
36
+ let MessageProvider = MessageProvider_1 = class MessageProvider {
37
+ /**
38
+ * Initializes pull consumers for both Event and Command streams.
39
+ *
40
+ * Uses `take(1)` on a consumer map to prevent recreating observables on every
41
+ * reconnection event. Each consumer observable handles its own reconnection logic
42
+ * through the `repeat()` operator, ensuring continuous message delivery even
43
+ * when NATS restarts.
44
+ *
45
+ * @param connectionProvider Connection provider.
46
+ * @param consumerProvider Consumer provider.
47
+ */
48
+ constructor(connectionProvider, consumerProvider) {
49
+ this.connectionProvider = connectionProvider;
50
+ this.consumerProvider = consumerProvider;
51
+ this.logger = new common_1.Logger(MessageProvider_1.name);
52
+ this.destroy$ = new rxjs_1.Subject();
53
+ /**
54
+ * Subject for Event pattern messages.
55
+ * Events are acknowledged immediately upon receipt, regardless of handler outcome.
56
+ */
57
+ this.eventMessages$ = new rxjs_1.Subject();
58
+ /**
59
+ * Subject for Command (RPC) pattern messages.
60
+ * Commands are acknowledged only after successful handler execution.
61
+ */
62
+ this.commandMessages$ = new rxjs_1.Subject();
63
+ this.subscription = this.consumerProvider.consumerMap$
64
+ .pipe((0, rxjs_1.take)(1), // Only subscribe once to prevent observer recreation on reconnects
65
+ (0, rxjs_1.switchMap)((consumerMap) => this.initializeConsumers(consumerMap)), (0, rxjs_1.takeUntil)(this.destroy$))
66
+ .subscribe();
67
+ }
68
+ /**
69
+ * Observable stream of Event messages for handler processing.
70
+ * Events should be acknowledged immediately after emission.
71
+ *
72
+ * @returns Observable<JsMsg> of Event messages.
73
+ */
74
+ get events$() {
75
+ return this.eventMessages$.asObservable();
76
+ }
77
+ /**
78
+ * Observable stream of Command (RPC) messages for handler processing.
79
+ * Commands should be acknowledged after successful handler execution.
80
+ *
81
+ * @returns Observable<JsMsg> of Command messages.
82
+ */
83
+ get commands$() {
84
+ return this.commandMessages$.asObservable();
85
+ }
86
+ /**
87
+ * Cleans up resources on module destruction.
88
+ *
89
+ * Completes all subjects and the destroy$ subject to stop all active subscriptions
90
+ * and explicitly unsubscribes from the main subscription.
91
+ */
92
+ onModuleDestroy() {
93
+ this.destroy$.next();
94
+ this.destroy$.complete();
95
+ this.eventMessages$.complete();
96
+ this.commandMessages$.complete();
97
+ this.subscription?.unsubscribe();
98
+ }
99
+ /**
100
+ * Initializes and starts consumer flows for available stream types.
101
+ *
102
+ * Creates separate observable flows for Event and Command consumers,
103
+ * each pushing messages to their respective subjects. Returns a merged
104
+ * observable that completes only when all consumers are done.
105
+ *
106
+ * @param consumerMap Map of consumer info by stream kind.
107
+ * @returns Observable that completes when all consumers are initialized.
108
+ */
109
+ initializeConsumers(consumerMap) {
110
+ const flows = [];
111
+ const evConsumer = consumerMap.get(enum_1.JetStreamKind.Event);
112
+ const cmdConsumer = consumerMap.get(enum_1.JetStreamKind.Command);
113
+ if (evConsumer)
114
+ flows.push(this.createConsumerFlow(evConsumer, enum_1.JetStreamKind.Event));
115
+ if (cmdConsumer)
116
+ flows.push(this.createConsumerFlow(cmdConsumer, enum_1.JetStreamKind.Command));
117
+ return (0, rxjs_1.merge)(...flows).pipe((0, rxjs_1.takeUntil)(this.destroy$));
118
+ }
119
+ /**
120
+ * Creates a self-healing consumer flow with automatic restart capability.
121
+ *
122
+ * Uses `defer()` to create a fresh observable on each subscription attempt,
123
+ * and `repeat()` to automatically restart when the async iterator completes
124
+ * (e.g., after NATS restart). This pattern ensures no messages are lost
125
+ * during reconnection periods.
126
+ *
127
+ * Messages are routed to the appropriate subject based on the stream kind:
128
+ * - Event messages → eventMessages$
129
+ * - Command messages → commandMessages$.
130
+ *
131
+ * The flow:
132
+ * 1. Fetches the JetStream consumer instance
133
+ * 2. Calls consume() to get an async iterator
134
+ * 3. Converts iterator to observable and emits messages to the appropriate subject
135
+ * 4. On completion, waits 100ms and restarts (via repeat)
136
+ * 5. On fatal error, logs and stops the flow.
137
+ *
138
+ * @param consumerInfo Consumer metadata from NATS.
139
+ * @param kind Stream kind (Event or Command).
140
+ * @returns Observable that manages the consumer lifecycle.
141
+ */
142
+ createConsumerFlow(consumerInfo, kind) {
143
+ const targetSubject$ = kind === enum_1.JetStreamKind.Event ? this.eventMessages$ : this.commandMessages$;
144
+ return (0, rxjs_1.defer)(() => this.startConsumerIteration(consumerInfo, targetSubject$)).pipe((0, rxjs_1.repeat)({
145
+ delay: () => {
146
+ this.logger.warn(`Consumer ${consumerInfo.name} stream completed. Restarting...`);
147
+ return (0, rxjs_1.timer)(100);
148
+ },
149
+ }), (0, rxjs_1.catchError)((err) => {
150
+ this.logger.error(`Fatal error in consumer ${consumerInfo.name}:`, err);
151
+ return rxjs_1.EMPTY;
152
+ }), (0, rxjs_1.takeUntil)(this.destroy$));
153
+ }
154
+ /**
155
+ * Executes a single iteration of consumer message processing.
156
+ *
157
+ * This method represents one complete lifecycle of the consumer:
158
+ * - Retrieves the consumer from JetStream
159
+ * - Starts the consume() async iterator
160
+ * - Emits messages to the target subject.
161
+ *
162
+ * When the async iterator completes (e.g., connection lost), this observable
163
+ * completes, triggering the `repeat()` operator to restart the flow.
164
+ *
165
+ * @param consumerInfo Consumer metadata.
166
+ * @param targetSubject$ Subject to emit messages to (events$ or commands$).
167
+ * @returns Observable that completes when the iteration ends.
168
+ */
169
+ startConsumerIteration(consumerInfo, targetSubject$) {
170
+ return (0, rxjs_1.of)(consumerInfo).pipe((0, rxjs_1.switchMap)((info) => this.getConsumer(info)), (0, rxjs_1.switchMap)((consumer) => this.consumeMessages(consumer, targetSubject$)));
171
+ }
172
+ /**
173
+ * Converts the consumer's async iterator into an RxJS observable stream.
174
+ *
175
+ * Calls consumer.consume() to get the async message iterator, converts it
176
+ * to an observable, and emits each message to the target subject.
177
+ *
178
+ * @param consumer JetStream consumer instance.
179
+ * @param targetSubject$ Subject to emit messages to.
180
+ * @returns Observable that emits void and completes when iterator ends.
181
+ */
182
+ consumeMessages(consumer, targetSubject$) {
183
+ return (0, rxjs_1.from)(consumer.consume()).pipe((0, rxjs_1.switchMap)((messages) => (0, rxjs_1.from)(messages)), (0, rxjs_1.switchMap)((msg) => {
184
+ targetSubject$.next(msg);
185
+ return (0, rxjs_1.of)(void 0);
186
+ }));
187
+ }
188
+ /**
189
+ * Retrieves a JetStream consumer instance by stream and consumer name.
190
+ *
191
+ * @param consumerInfo Consumer metadata containing stream and consumer names.
192
+ * @returns Observable of the consumer instance.
193
+ */
194
+ getConsumer(consumerInfo) {
195
+ return this.connectionProvider.jsm.pipe((0, rxjs_1.switchMap)((jsm) => {
196
+ const consumerPromise = jsm
197
+ .jetstream()
198
+ .consumers.get(consumerInfo.stream_name, consumerInfo.name);
199
+ return (0, rxjs_1.from)(consumerPromise);
200
+ }));
201
+ }
202
+ };
203
+ exports.MessageProvider = MessageProvider;
204
+ exports.MessageProvider = MessageProvider = MessageProvider_1 = __decorate([
205
+ (0, common_1.Injectable)(),
206
+ __metadata("design:paramtypes", [connection_provider_1.ConnectionProvider,
207
+ consumer_provider_1.ConsumerProvider])
208
+ ], MessageProvider);
209
+ //# sourceMappingURL=message.provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"message.provider.js","sourceRoot":"","sources":["../../../src/server/providers/message.provider.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,320 @@
1
+ import { StreamConfig, StreamInfo, StreamUpdateConfig } from 'nats';
2
+ import { Observable } from 'rxjs';
3
+ import { ConnectionProvider } from '../../common/connection.provider';
4
+ import { IJetstreamTransportOptions } from '../../common/types';
5
+ import { JetStreamKind } from '../../enum';
6
+ /**
7
+ * Provider responsible for managing JetStream stream lifecycle.
8
+ *
9
+ * @description
10
+ * This provider handles the creation, updating, and configuration of JetStream streams
11
+ * that serve as the foundation for message storage and delivery in the transport.
12
+ * It ensures that both Event and Command streams exist and are properly configured
13
+ * before any message consumption begins.
14
+ *
15
+ * @remarks
16
+ * **Core responsibilities:**
17
+ *
18
+ * 1. **Stream creation and updates:**
19
+ * - Creates Event and Command streams on initialization
20
+ * - Updates existing streams if configuration changes
21
+ * - Ensures streams match the required configuration
22
+ * - Handles idempotent operations (safe to call multiple times)
23
+ *
24
+ * 2. **Stream naming convention:**
25
+ * - Format: `{serviceName}_{kind}-stream`
26
+ * - Examples: `orders-service_event-stream`, `orders-service_command-stream`
27
+ * - Ensures unique streams per service instance
28
+ *
29
+ * 3. **Subject patterns:**
30
+ * - Event subjects: `{serviceName}.event.>`
31
+ * - Command subjects: `{serviceName}.command.>`
32
+ * - The `>` wildcard allows hierarchical message routing
33
+ *
34
+ * 4. **Configuration management:**
35
+ * - Applies base configuration common to all streams
36
+ * - Applies kind-specific configuration (event vs command)
37
+ * - Merges user-provided custom configuration
38
+ *
39
+ * **Stream types:**
40
+ *
41
+ * - **Event streams:**
42
+ * Designed for pub/sub patterns and event broadcasting.
43
+ * Multiple consumers can process the same events independently.
44
+ * Typical configuration: longer retention, interest-based retention policy.
45
+ *
46
+ * - **Command streams:**
47
+ * Designed for work queue patterns and RPC-style communication.
48
+ * Messages are distributed across consumers (load balancing).
49
+ * Typical configuration: shorter retention, work queue retention policy.
50
+ *
51
+ * **Idempotency:**
52
+ *
53
+ * The create() method is idempotent:
54
+ * - If streams don't exist: creates them
55
+ * - If streams exist with different config: updates them
56
+ * - If streams exist with same config: no-op (returns existing info)
57
+ *
58
+ * This makes it safe to call on every application startup and reconnection.
59
+ *
60
+ * @example
61
+ * ```typescript
62
+ * // Create both event and command streams
63
+ * streamProvider.create().subscribe(() => {
64
+ * console.log('All streams ready');
65
+ * });
66
+ *
67
+ * // Get stream name for a specific kind
68
+ * const streamName = streamProvider.getStreamName(JetStreamKind.Event);
69
+ * // Returns: "my-service_event-stream"
70
+ * ```
71
+ *
72
+ * @see {@link https://docs.nats.io/nats-concepts/jetstream/streams | JetStream Streams Documentation}
73
+ * @see {@link https://docs.nats.io/using-nats/developer/develop_jetstream/model_deep_dive | Stream Configuration Guide}
74
+ */
75
+ export declare class StreamProvider {
76
+ private readonly options;
77
+ private readonly connectionProvider;
78
+ private readonly logger;
79
+ /**
80
+ * Creates a StreamProvider instance.
81
+ *
82
+ * @param options JetStream transport options containing service name and custom stream configurations.
83
+ * @param connectionProvider Provider that manages NATS connection and JetStream manager access.
84
+ */
85
+ constructor(options: IJetstreamTransportOptions, connectionProvider: ConnectionProvider);
86
+ /**
87
+ * Creates or updates both Event and Command streams.
88
+ *
89
+ * @description
90
+ * Orchestrates the creation of both stream types in parallel using forkJoin.
91
+ * This ensures both streams are ready before the observable completes.
92
+ *
93
+ * The operation is idempotent:
94
+ * - Creates streams if they don't exist
95
+ * - Updates streams if configuration changed
96
+ * - No-op if streams exist with correct configuration.
97
+ *
98
+ * **Error handling:**
99
+ * - If one stream fails to create, the entire operation fails
100
+ * - Errors are not caught here, allowing caller to handle retry logic
101
+ * - Common errors: permission denied, invalid configuration, network issues.
102
+ *
103
+ * @returns Observable that completes when both streams are ready (emits void).
104
+ *
105
+ * @example
106
+ * ```typescript
107
+ * streamProvider.create().subscribe({
108
+ * next: () => console.log('Streams ready'),
109
+ * error: (err) => console.error('Stream creation failed:', err),
110
+ * });
111
+ * ```
112
+ */
113
+ create(): Observable<void>;
114
+ /**
115
+ * Generates the stream name for a specific kind.
116
+ *
117
+ * @description
118
+ * Constructs the stream name using the naming convention:
119
+ * `{serviceName}_{kind}-stream`.
120
+ *
121
+ * This ensures:
122
+ * - Stream names are unique per service
123
+ * - Stream names are predictable and discoverable
124
+ * - Different services don't interfere with each other.
125
+ *
126
+ * @param kind The stream kind (Event or Command).
127
+ * @returns The formatted stream name.
128
+ *
129
+ * @example
130
+ * ```typescript
131
+ * streamProvider.getStreamName(JetStreamKind.Event);
132
+ * // Returns: "orders-service_event-stream"
133
+ *
134
+ * streamProvider.getStreamName(JetStreamKind.Command);
135
+ * // Returns: "orders-service_command-stream"
136
+ * ```
137
+ */
138
+ getStreamName(kind: JetStreamKind): string;
139
+ /**
140
+ * Generates subject patterns for a specific stream kind.
141
+ *
142
+ * @description
143
+ * Constructs subject patterns that the stream will capture messages from.
144
+ * The pattern format is: `{serviceName}.{kind}.>`.
145
+ *
146
+ * The `>` wildcard means "match all tokens after this point", enabling:
147
+ * - Hierarchical subject organization
148
+ * - Flexible message routing
149
+ * - Namespace isolation per service.
150
+ *
151
+ * **Examples of matched subjects:**
152
+ * - Pattern: `orders.event.>`
153
+ * - Matches: `orders.event.created`, `orders.event.updated`, `orders.event.deleted.v2`
154
+ * - Does NOT match: `orders.command.create`, `payments.event.created`.
155
+ *
156
+ * @param kind The stream kind (Event or Command).
157
+ * @returns Array of subject patterns (currently single pattern, but array for future extensibility).
158
+ *
159
+ * @example
160
+ * ```typescript
161
+ * streamProvider.getSubjects(JetStreamKind.Event);
162
+ * // Returns: ["orders-service.event.>"]
163
+ * ```
164
+ */
165
+ protected getSubjects(kind: JetStreamKind): string[];
166
+ /**
167
+ * Creates or updates a stream for a specific kind.
168
+ *
169
+ * @description
170
+ * Implements the stream ensure logic with the following flow:
171
+ *
172
+ * 1. **Build configuration:**
173
+ * - Merge base config (common settings)
174
+ * - Merge kind-specific config (event vs command)
175
+ * - Set stream name and subjects
176
+ * - Add descriptive metadata.
177
+ *
178
+ * 2. **Check if stream exists:**
179
+ * - Query stream info via `info()`
180
+ * - If exists: proceed to update
181
+ * - If not found: catch error and create new.
182
+ *
183
+ * 3. **Update existing stream:**
184
+ * - Apply new configuration via `update()`
185
+ * - JetStream validates if update is allowed
186
+ * - Some changes require stream recreation.
187
+ *
188
+ * 4. **Create new stream:**
189
+ * - Triggered by StreamNotFound error
190
+ * - Creates stream with full configuration
191
+ * - Logs successful creation.
192
+ *
193
+ * **Error handling:**
194
+ * - StreamNotFound → creates new stream
195
+ * - Other errors → propagated to caller.
196
+ *
197
+ * @param kind The stream kind to create/update.
198
+ * @returns Observable that emits StreamInfo when complete.
199
+ *
200
+ * @example
201
+ * ```typescript
202
+ * // Internal usage, called by create()
203
+ * this.createForKind(JetStreamKind.Event).subscribe(info => {
204
+ * console.log('Stream created:', info.config.name);
205
+ * });
206
+ * ```
207
+ */
208
+ protected createForKind(kind: JetStreamKind): Observable<StreamInfo>;
209
+ /**
210
+ * Retrieves information about an existing stream.
211
+ *
212
+ * @description
213
+ * Queries the JetStream manager for stream metadata and configuration.
214
+ * This is used to:
215
+ * - Check if a stream exists
216
+ * - Verify stream configuration
217
+ * - Monitor stream state.
218
+ *
219
+ * **Stream info includes:**
220
+ * - Configuration (retention, limits, subjects)
221
+ * - State (messages count, bytes, first/last sequence)
222
+ * - Cluster information (if clustered)
223
+ * - Consumer count.
224
+ *
225
+ * @param streamName The name of the stream to query.
226
+ * @returns Observable that emits StreamInfo or errors if stream not found.
227
+ *
228
+ * @throws {NatsError} With code StreamNotFound if stream doesn't exist.
229
+ *
230
+ * @example
231
+ * ```typescript
232
+ * this.info('orders-service_event-stream').subscribe(info => {
233
+ * console.log('Messages in stream:', info.state.messages);
234
+ * });
235
+ * ```
236
+ */
237
+ protected info(streamName: string): Observable<StreamInfo>;
238
+ /**
239
+ * Creates a new stream with the provided configuration.
240
+ *
241
+ * @description
242
+ * Creates a new JetStream stream from scratch. This is called when
243
+ * a stream doesn't exist yet (typically on first application start
244
+ * or after manual deletion).
245
+ *
246
+ * **Configuration validation:**
247
+ * - JetStream validates all configuration parameters
248
+ * - Invalid configs will cause the operation to fail
249
+ * - Common validations: subject uniqueness, retention policy compatibility.
250
+ *
251
+ * **Stream creation is atomic:**
252
+ * - Either the stream is fully created or it fails
253
+ * - No partial state
254
+ * - Safe to retry on failure.
255
+ *
256
+ * @param config Complete stream configuration including name, subjects, and policies.
257
+ * @returns Observable that emits StreamInfo of the newly created stream.
258
+ *
259
+ * @throws {NatsError} If creation fails (permissions, invalid config, etc.).
260
+ *
261
+ * @example
262
+ * ```typescript
263
+ * const config = {
264
+ * name: 'my-stream',
265
+ * subjects: ['my.service.>'],
266
+ * retention: RetentionPolicy.Limits,
267
+ * };
268
+ *
269
+ * this.new(config).subscribe(info => {
270
+ * console.log('Stream created:', info.config.name);
271
+ * });
272
+ * ```
273
+ */
274
+ protected new(config: StreamConfig): Observable<StreamInfo>;
275
+ /**
276
+ * Updates an existing stream with new configuration.
277
+ *
278
+ * @description
279
+ * Applies configuration changes to an existing stream. Not all changes
280
+ * are allowed - some require stream recreation.
281
+ *
282
+ * **Allowed updates:**
283
+ * - Subject list modifications (add/remove subjects)
284
+ * - Limit adjustments (max_msgs, max_bytes, max_age)
285
+ * - Description changes
286
+ * - Some policy changes.
287
+ *
288
+ * **Updates requiring recreation:**
289
+ * - Storage type change (file ↔ memory)
290
+ * - Retention policy change (in some cases)
291
+ * - Discard policy change (in some cases)
292
+ * - Changing stream name.
293
+ *
294
+ * **Behavior:**
295
+ * - If update is allowed: applies changes and returns updated info
296
+ * - If update is not allowed: returns error explaining why
297
+ * - No automatic recreation - caller must handle explicitly.
298
+ *
299
+ * @param streamName Name of the stream to update.
300
+ * @param config New configuration to apply.
301
+ * @returns Observable that emits updated StreamInfo.
302
+ *
303
+ * @throws {NatsError} If update is not allowed or fails.
304
+ *
305
+ * @example
306
+ * ```typescript
307
+ * const newConfig = {
308
+ * name: 'my-stream',
309
+ * subjects: ['my.service.>', 'other.service.>'], // Added subject
310
+ * max_msgs: 10000,
311
+ * };
312
+ *
313
+ * this.update('my-stream', newConfig).subscribe(info => {
314
+ * console.log('Stream updated, subjects:', info.config.subjects);
315
+ * });
316
+ * ```
317
+ */
318
+ protected update(streamName: string, config: StreamUpdateConfig): Observable<StreamInfo>;
319
+ }
320
+ //# sourceMappingURL=stream.provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stream.provider.d.ts","sourceRoot":"","sources":["../../../src/server/providers/stream.provider.ts"],"names":[],"mappings":"AACA,OAAO,EAAa,YAAY,EAAE,UAAU,EAAE,kBAAkB,EAAE,MAAM,MAAM,CAAC;AAC/E,OAAO,EAAmC,UAAU,EAAkB,MAAM,MAAM,CAAC;AAEnF,OAAO,EAAE,kBAAkB,EAAE,MAAM,kCAAkC,CAAC;AACtE,OAAO,EAAE,0BAA0B,EAAE,MAAM,oBAAoB,CAAC;AAChE,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAI3C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoEG;AACH,qBACa,cAAc;IAUvB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,kBAAkB;IAVrC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAmC;IAE1D;;;;;OAKG;gBAEgB,OAAO,EAAE,0BAA0B,EACnC,kBAAkB,EAAE,kBAAkB;IAGzD;;;;;;;;;;;;;;;;;;;;;;;;;;OA0BG;IACI,MAAM,IAAI,UAAU,CAAC,IAAI,CAAC;IAOjC;;;;;;;;;;;;;;;;;;;;;;;OAuBG;IACI,aAAa,CAAC,IAAI,EAAE,aAAa,GAAG,MAAM;IAIjD;;;;;;;;;;;;;;;;;;;;;;;;;OAyBG;IACH,SAAS,CAAC,WAAW,CAAC,IAAI,EAAE,aAAa,GAAG,MAAM,EAAE;IAIpD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAyCG;IACH,SAAS,CAAC,aAAa,CAAC,IAAI,EAAE,aAAa,GAAG,UAAU,CAAC,UAAU,CAAC;IAwBpE;;;;;;;;;;;;;;;;;;;;;;;;;;;OA2BG;IACH,SAAS,CAAC,IAAI,CAAC,UAAU,EAAE,MAAM,GAAG,UAAU,CAAC,UAAU,CAAC;IAU1D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAmCG;IACH,SAAS,CAAC,GAAG,CAAC,MAAM,EAAE,YAAY,GAAG,UAAU,CAAC,UAAU,CAAC;IAU3D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA0CG;IACH,SAAS,CAAC,MAAM,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,kBAAkB,GAAG,UAAU,CAAC,UAAU,CAAC;CAWzF"}