@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.
- package/LICENSE.md +21 -0
- package/README.md +180 -0
- package/dist/client/index.d.ts +2 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +18 -0
- package/dist/client/index.js.map +1 -0
- package/dist/client/jetstream-client.module.d.ts +6 -0
- package/dist/client/jetstream-client.module.d.ts.map +1 -0
- package/dist/client/jetstream-client.module.js +68 -0
- package/dist/client/jetstream-client.module.js.map +1 -0
- package/dist/client/jetstream.client-proxy.d.ts +179 -0
- package/dist/client/jetstream.client-proxy.d.ts.map +1 -0
- package/dist/client/jetstream.client-proxy.js +300 -0
- package/dist/client/jetstream.client-proxy.js.map +1 -0
- package/dist/client/types/index.d.ts +7 -0
- package/dist/client/types/index.d.ts.map +1 -0
- package/dist/client/types/index.js +3 -0
- package/dist/client/types/index.js.map +1 -0
- package/dist/common/connection.provider.d.ts +309 -0
- package/dist/common/connection.provider.d.ts.map +1 -0
- package/dist/common/connection.provider.js +326 -0
- package/dist/common/connection.provider.js.map +1 -0
- package/dist/common/enum/service-type.enum.d.ts +5 -0
- package/dist/common/enum/service-type.enum.d.ts.map +1 -0
- package/dist/common/enum/service-type.enum.js +9 -0
- package/dist/common/enum/service-type.enum.js.map +1 -0
- package/dist/common/helpers.d.ts +14 -0
- package/dist/common/helpers.d.ts.map +1 -0
- package/dist/common/helpers.js +21 -0
- package/dist/common/helpers.js.map +1 -0
- package/dist/common/index.d.ts +2 -0
- package/dist/common/index.d.ts.map +1 -0
- package/dist/common/index.js +7 -0
- package/dist/common/index.js.map +1 -0
- package/dist/common/pattern-registry.d.ts +51 -0
- package/dist/common/pattern-registry.d.ts.map +1 -0
- package/dist/common/pattern-registry.js +86 -0
- package/dist/common/pattern-registry.js.map +1 -0
- package/dist/common/rpc.context.d.ts +8 -0
- package/dist/common/rpc.context.d.ts.map +1 -0
- package/dist/common/rpc.context.js +14 -0
- package/dist/common/rpc.context.js.map +1 -0
- package/dist/common/types/index.d.ts +2 -0
- package/dist/common/types/index.d.ts.map +1 -0
- package/dist/common/types/index.js +18 -0
- package/dist/common/types/index.js.map +1 -0
- package/dist/common/types/jetstream-transport.options.d.ts +60 -0
- package/dist/common/types/jetstream-transport.options.d.ts.map +1 -0
- package/dist/common/types/jetstream-transport.options.js +3 -0
- package/dist/common/types/jetstream-transport.options.js.map +1 -0
- package/dist/enum/index.d.ts +16 -0
- package/dist/enum/index.d.ts.map +1 -0
- package/dist/enum/index.js +21 -0
- package/dist/enum/index.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -0
- package/dist/server/const/index.d.ts +4 -0
- package/dist/server/const/index.d.ts.map +1 -0
- package/dist/server/const/index.js +96 -0
- package/dist/server/const/index.js.map +1 -0
- package/dist/server/enum/index.d.ts +5 -0
- package/dist/server/enum/index.d.ts.map +1 -0
- package/dist/server/enum/index.js +9 -0
- package/dist/server/enum/index.js.map +1 -0
- package/dist/server/index.d.ts +3 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +19 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/jetstream-server.module.d.ts +157 -0
- package/dist/server/jetstream-server.module.d.ts.map +1 -0
- package/dist/server/jetstream-server.module.js +375 -0
- package/dist/server/jetstream-server.module.js.map +1 -0
- package/dist/server/jetstream.strategy.d.ts +150 -0
- package/dist/server/jetstream.strategy.d.ts.map +1 -0
- package/dist/server/jetstream.strategy.js +192 -0
- package/dist/server/jetstream.strategy.js.map +1 -0
- package/dist/server/jetstream.transport.d.ts +9 -0
- package/dist/server/jetstream.transport.d.ts.map +1 -0
- package/dist/server/jetstream.transport.js +26 -0
- package/dist/server/jetstream.transport.js.map +1 -0
- package/dist/server/providers/consumer.provider.d.ts +226 -0
- package/dist/server/providers/consumer.provider.d.ts.map +1 -0
- package/dist/server/providers/consumer.provider.js +272 -0
- package/dist/server/providers/consumer.provider.js.map +1 -0
- package/dist/server/providers/message-routing.provider.d.ts +295 -0
- package/dist/server/providers/message-routing.provider.d.ts.map +1 -0
- package/dist/server/providers/message-routing.provider.js +420 -0
- package/dist/server/providers/message-routing.provider.js.map +1 -0
- package/dist/server/providers/message.provider.d.ts +142 -0
- package/dist/server/providers/message.provider.d.ts.map +1 -0
- package/dist/server/providers/message.provider.js +209 -0
- package/dist/server/providers/message.provider.js.map +1 -0
- package/dist/server/providers/stream.provider.d.ts +320 -0
- package/dist/server/providers/stream.provider.d.ts.map +1 -0
- package/dist/server/providers/stream.provider.js +376 -0
- package/dist/server/providers/stream.provider.js.map +1 -0
- package/dist/server/types/index.d.ts +7 -0
- package/dist/server/types/index.d.ts.map +1 -0
- package/dist/server/types/index.js +3 -0
- package/dist/server/types/index.js.map +1 -0
- package/dist/server/types/nats.events-map.d.ts +22 -0
- package/dist/server/types/nats.events-map.d.ts.map +1 -0
- package/dist/server/types/nats.events-map.js +4 -0
- package/dist/server/types/nats.events-map.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- 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"}
|