@lakutata/nats 2.3.0 → 3.0.0-beta.0
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 +23 -0
- package/README.md +288 -25
- package/dist/cjs/codecs/JSONCodec.d.ts +32 -0
- package/dist/cjs/codecs/JSONCodec.js +44 -0
- package/dist/cjs/codecs/MessagePackCodec.d.ts +22 -0
- package/dist/cjs/codecs/MessagePackCodec.js +35 -0
- package/dist/cjs/components/NATS.d.ts +376 -0
- package/dist/cjs/components/NATS.js +772 -0
- package/dist/cjs/entrypoints/NatsServiceEntrypoint.d.ts +102 -0
- package/dist/cjs/entrypoints/NatsServiceEntrypoint.js +127 -0
- package/dist/cjs/exceptions/NatsBadRequestException.d.ts +11 -0
- package/dist/cjs/exceptions/NatsBadRequestException.js +18 -0
- package/dist/cjs/exceptions/NatsBulkException.d.ts +19 -0
- package/dist/cjs/exceptions/NatsBulkException.js +26 -0
- package/dist/cjs/exceptions/NatsForbiddenException.d.ts +11 -0
- package/dist/cjs/exceptions/NatsForbiddenException.js +18 -0
- package/dist/cjs/exceptions/NatsInternalServerException.d.ts +12 -0
- package/dist/cjs/exceptions/NatsInternalServerException.js +19 -0
- package/dist/cjs/exceptions/NatsNoRespondersAvailableException.d.ts +12 -0
- package/dist/cjs/exceptions/NatsNoRespondersAvailableException.js +19 -0
- package/dist/cjs/exceptions/NatsNotFoundException.d.ts +11 -0
- package/dist/cjs/exceptions/NatsNotFoundException.js +18 -0
- package/dist/cjs/exceptions/NatsRequestTimeoutException.d.ts +11 -0
- package/dist/cjs/exceptions/NatsRequestTimeoutException.js +18 -0
- package/dist/cjs/exports/Nats.d.ts +18 -0
- package/dist/cjs/exports/Nats.js +39 -0
- package/dist/cjs/interfaces/NatsClientOptions.d.ts +106 -0
- package/dist/{lib → cjs/lib}/ServiceEventCodec.d.ts +0 -1
- package/dist/{lib → cjs/lib}/ServiceEventCodec.js +19 -9
- package/dist/cjs/package.json +1 -0
- package/dist/cjs/providers/ServiceProxy.d.ts +210 -0
- package/dist/cjs/providers/ServiceProxy.js +274 -0
- package/dist/cjs/types/SubscribeOptions.d.ts +33 -0
- package/dist/esm/codecs/JSONCodec.js +41 -0
- package/dist/esm/codecs/MessagePackCodec.js +32 -0
- package/dist/esm/components/NATS.js +767 -0
- package/dist/esm/entrypoints/NatsServiceEntrypoint.js +123 -0
- package/dist/esm/exceptions/NatsBadRequestException.js +14 -0
- package/dist/esm/exceptions/NatsBulkException.js +22 -0
- package/dist/esm/exceptions/NatsForbiddenException.js +14 -0
- package/dist/esm/exceptions/NatsInternalServerException.js +15 -0
- package/dist/esm/exceptions/NatsNoRespondersAvailableException.js +15 -0
- package/dist/esm/exceptions/NatsNotFoundException.js +14 -0
- package/dist/esm/exceptions/NatsRequestTimeoutException.js +14 -0
- package/dist/esm/exports/Nats.js +15 -0
- package/dist/esm/interfaces/NatsClientOptions.js +1 -0
- package/dist/esm/lib/ServiceEventCodec.js +21 -0
- package/dist/esm/providers/ServiceProxy.js +270 -0
- package/dist/esm/types/SubscribeOptions.js +1 -0
- package/dist/types/codecs/JSONCodec.d.ts +32 -0
- package/dist/types/codecs/MessagePackCodec.d.ts +22 -0
- package/dist/types/components/NATS.d.ts +376 -0
- package/dist/types/entrypoints/NatsServiceEntrypoint.d.ts +102 -0
- package/dist/types/exceptions/NatsBadRequestException.d.ts +11 -0
- package/dist/types/exceptions/NatsBulkException.d.ts +19 -0
- package/dist/types/exceptions/NatsForbiddenException.d.ts +11 -0
- package/dist/types/exceptions/NatsInternalServerException.d.ts +12 -0
- package/dist/types/exceptions/NatsNoRespondersAvailableException.d.ts +12 -0
- package/dist/types/exceptions/NatsNotFoundException.d.ts +11 -0
- package/dist/types/exceptions/NatsRequestTimeoutException.d.ts +11 -0
- package/dist/types/exports/Nats.d.ts +18 -0
- package/dist/types/interfaces/NatsClientOptions.d.ts +106 -0
- package/dist/types/lib/ServiceEventCodec.d.ts +9 -0
- package/dist/types/providers/ServiceProxy.d.ts +210 -0
- package/dist/types/types/SubscribeOptions.d.ts +33 -0
- package/package.json +42 -33
- package/CHANGELOG.md +0 -288
- package/dist/CommonExports.d.ts +0 -19
- package/dist/CommonExports.d.ts.map +0 -1
- package/dist/CommonExports.js +0 -35
- package/dist/codecs/JSONCodec.d.ts +0 -3
- package/dist/codecs/JSONCodec.d.ts.map +0 -1
- package/dist/codecs/JSONCodec.js +0 -15
- package/dist/codecs/MessagePackCodec.d.ts +0 -3
- package/dist/codecs/MessagePackCodec.d.ts.map +0 -1
- package/dist/codecs/MessagePackCodec.js +0 -16
- package/dist/components/NATS.d.ts +0 -252
- package/dist/components/NATS.d.ts.map +0 -1
- package/dist/components/NATS.js +0 -564
- package/dist/entrypoints/SetupNatsServiceEntrypoint.d.ts +0 -8
- package/dist/entrypoints/SetupNatsServiceEntrypoint.d.ts.map +0 -1
- package/dist/entrypoints/SetupNatsServiceEntrypoint.js +0 -41
- package/dist/exceptions/NatsBadRequestException.d.ts +0 -7
- package/dist/exceptions/NatsBadRequestException.d.ts.map +0 -1
- package/dist/exceptions/NatsBadRequestException.js +0 -13
- package/dist/exceptions/NatsBulkException.d.ts +0 -11
- package/dist/exceptions/NatsBulkException.d.ts.map +0 -1
- package/dist/exceptions/NatsBulkException.js +0 -17
- package/dist/exceptions/NatsForbiddenException.d.ts +0 -7
- package/dist/exceptions/NatsForbiddenException.d.ts.map +0 -1
- package/dist/exceptions/NatsForbiddenException.js +0 -13
- package/dist/exceptions/NatsInternalServerException.d.ts +0 -7
- package/dist/exceptions/NatsInternalServerException.d.ts.map +0 -1
- package/dist/exceptions/NatsInternalServerException.js +0 -13
- package/dist/exceptions/NatsNoRespondersAvailableException.d.ts +0 -7
- package/dist/exceptions/NatsNoRespondersAvailableException.d.ts.map +0 -1
- package/dist/exceptions/NatsNoRespondersAvailableException.js +0 -13
- package/dist/exceptions/NatsNotFoundException.d.ts +0 -7
- package/dist/exceptions/NatsNotFoundException.d.ts.map +0 -1
- package/dist/exceptions/NatsNotFoundException.js +0 -13
- package/dist/exceptions/NatsRequestTimeoutException.d.ts +0 -7
- package/dist/exceptions/NatsRequestTimeoutException.d.ts.map +0 -1
- package/dist/exceptions/NatsRequestTimeoutException.js +0 -13
- package/dist/exceptions/ServiceInvokeException.d.ts +0 -6
- package/dist/exceptions/ServiceInvokeException.d.ts.map +0 -1
- package/dist/exceptions/ServiceInvokeException.js +0 -11
- package/dist/interfaces/NatsClientOptions.d.ts +0 -26
- package/dist/interfaces/NatsClientOptions.d.ts.map +0 -1
- package/dist/lib/ServiceEventCodec.d.ts.map +0 -1
- package/dist/lib/ServiceResponseCodec.d.ts +0 -22
- package/dist/lib/ServiceResponseCodec.d.ts.map +0 -1
- package/dist/lib/ServiceResponseCodec.js +0 -50
- package/dist/providers/ServiceProxy.d.ts +0 -85
- package/dist/providers/ServiceProxy.d.ts.map +0 -1
- package/dist/providers/ServiceProxy.js +0 -124
- package/dist/types/SubscribeOptions.d.ts +0 -12
- package/dist/types/SubscribeOptions.d.ts.map +0 -1
- package/docs/large-payload-design.md +0 -199
- package/tsconfig.json +0 -8
- /package/dist/{interfaces → cjs/interfaces}/NatsClientOptions.js +0 -0
- /package/dist/{types → cjs/types}/SubscribeOptions.js +0 -0
|
@@ -0,0 +1,376 @@
|
|
|
1
|
+
import { Application, Component, ComponentOptionsBuilder } from '@lakutata/core';
|
|
2
|
+
import { type Codec, Subscription, type ObjectStoreStatus } from 'nats';
|
|
3
|
+
import { SubscribeOptions } from '../types/SubscribeOptions.js';
|
|
4
|
+
import { NatsClientOptions } from '../interfaces/NatsClientOptions.js';
|
|
5
|
+
/**
|
|
6
|
+
* Build the component options of a {@link NATS} component, to register it in the `components` of an application (or a
|
|
7
|
+
* module) under the name of your choice. The options are validated when the component is created, not here.
|
|
8
|
+
* @param options The connection options: the servers, the codec, the authentication, the reconnection and the bulk
|
|
9
|
+
* channel of the large payloads.
|
|
10
|
+
* @returns The component options (`{class: NATS, ...options}`).
|
|
11
|
+
* @example
|
|
12
|
+
* ```typescript
|
|
13
|
+
* import {Application} from 'lakutata'
|
|
14
|
+
* import {buildNatsClientOptions, type NATS} from '@lakutata/nats'
|
|
15
|
+
*
|
|
16
|
+
* Application
|
|
17
|
+
* .run({
|
|
18
|
+
* id: 'notifier.app',
|
|
19
|
+
* name: 'Notifier',
|
|
20
|
+
* components: {
|
|
21
|
+
* nats: buildNatsClientOptions({
|
|
22
|
+
* servers: ['nats://10.0.0.1:4222', 'nats://10.0.0.2:4222'],
|
|
23
|
+
* user: 'notifier',
|
|
24
|
+
* pass: 'secret',
|
|
25
|
+
* name: 'notifier',
|
|
26
|
+
* //Never give up reconnecting
|
|
27
|
+
* maxReconnectAttempts: -1
|
|
28
|
+
* })
|
|
29
|
+
* }
|
|
30
|
+
* })
|
|
31
|
+
* .onLaunched(async (app: Application): Promise<void> => {
|
|
32
|
+
* const nats: NATS = await app.getObject('nats')
|
|
33
|
+
* nats.publish('notification.sent', {to: 'ada@example.com'})
|
|
34
|
+
* })
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
export declare const buildNatsClientOptions: ComponentOptionsBuilder<NatsClientOptions>;
|
|
38
|
+
/**
|
|
39
|
+
* The NATS component: a connection to a NATS server (or cluster) to publish messages, subscribe to subjects, send
|
|
40
|
+
* requests and answer them, and emit and receive the service events. Register it in the `components` of an application
|
|
41
|
+
* with {@link buildNatsClientOptions} (or `{class: NATS, ...options}`) and get it with `getObject()` or `@Inject`; it is
|
|
42
|
+
* a singleton. The service entrypoint ({@link natsServiceEntrypoint}) and the service proxies ({@link ServiceProxy})
|
|
43
|
+
* use it by its component name.
|
|
44
|
+
*
|
|
45
|
+
* It connects when it is created: a server which cannot be reached within the `timeout` option fails its creation, and
|
|
46
|
+
* so the application's start. A lost connection is reestablished in the background (see the `reconnect` and
|
|
47
|
+
* `maxReconnectAttempts` options); once the reconnection is given up, an `'error'` event is emitted and the calls fail
|
|
48
|
+
* with the NATS client error `CONNECTION_CLOSED`. When it is destroyed, it drains its connections: the subscriptions stop receiving, the messages
|
|
49
|
+
* in progress are handled and the outgoing ones flushed before the connections close.
|
|
50
|
+
*
|
|
51
|
+
* Every payload is encoded with the codec ({@link messagePackCodec} by default). A payload larger than the server's
|
|
52
|
+
* `max_payload` (1 MiB by default) cannot be sent as a message: a request or a response of 90% of it or more is relayed
|
|
53
|
+
* through a JetStream object store when both sides enabled the bulk channel (the `bulk` option, on by default, which
|
|
54
|
+
* needs JetStream on the server), as a reference the receiving side reads transparently. The published messages and the
|
|
55
|
+
* events are never relayed: over `max_payload`, publishing them throws.
|
|
56
|
+
*
|
|
57
|
+
* It emits an `'error'` event, only when it has listeners, for the failures nobody else can report: a subscription
|
|
58
|
+
* callback or an event listener which threw, a message which could not be decoded, a subscription error (a permissions
|
|
59
|
+
* violation).
|
|
60
|
+
* @example
|
|
61
|
+
* ```typescript
|
|
62
|
+
* import {Application} from 'lakutata'
|
|
63
|
+
* import {buildNatsClientOptions, type NATS} from '@lakutata/nats'
|
|
64
|
+
*
|
|
65
|
+
* Application
|
|
66
|
+
* .run({
|
|
67
|
+
* id: 'pricing.app',
|
|
68
|
+
* name: 'Pricing',
|
|
69
|
+
* components: {
|
|
70
|
+
* nats: buildNatsClientOptions({servers: 'nats://127.0.0.1:4222', name: 'pricing'})
|
|
71
|
+
* }
|
|
72
|
+
* })
|
|
73
|
+
* .onLaunched(async (app: Application): Promise<void> => {
|
|
74
|
+
* const nats: NATS = await app.getObject('nats')
|
|
75
|
+
* nats.on('error', (error: Error): void => console.error('NATS message handling failed', error))
|
|
76
|
+
* //Answer the requests, shared between the instances of the application: the value returned is the response
|
|
77
|
+
* nats.subscribe('price.get', async (input: {sku: string}): Promise<number> => input.sku.length * 10, {queue: 'pricing'})
|
|
78
|
+
* //The messages of every region: the subject tells which one
|
|
79
|
+
* nats.subscribe('price.changed.*', (price: number, subject: string): void => console.log(subject, price))
|
|
80
|
+
* nats.publish('price.changed.eu', 42)
|
|
81
|
+
* console.log(await nats.request('price.get', {sku: 'ABC'}, 5000)) //30
|
|
82
|
+
* //The service events of this application, received by the applications listening to them
|
|
83
|
+
* nats.emitServiceEvent('priceChanged', 'ABC', 30)
|
|
84
|
+
* nats.onServiceEvent('stock.service', 'stockChanged', (sku: string, quantity: number): void => console.log(sku, quantity))
|
|
85
|
+
* })
|
|
86
|
+
* ```
|
|
87
|
+
*/
|
|
88
|
+
export declare class NATS extends Component {
|
|
89
|
+
#private;
|
|
90
|
+
/**
|
|
91
|
+
* The application the component belongs to; its id names the service events it emits.
|
|
92
|
+
*/
|
|
93
|
+
protected readonly app: Application;
|
|
94
|
+
/**
|
|
95
|
+
* The NATS server, or the servers of a cluster: `host:port` or a URL (`nats://user:pass@host:4222`).
|
|
96
|
+
*/
|
|
97
|
+
protected readonly servers: string | string[];
|
|
98
|
+
/**
|
|
99
|
+
* The codec encoding and decoding every payload.
|
|
100
|
+
* @default messagePackCodec()
|
|
101
|
+
*/
|
|
102
|
+
protected readonly codec: Codec<unknown>;
|
|
103
|
+
/**
|
|
104
|
+
* The time to wait for the connection to a server to be established, in milliseconds.
|
|
105
|
+
* @default 20000
|
|
106
|
+
*/
|
|
107
|
+
protected readonly timeout?: number;
|
|
108
|
+
/**
|
|
109
|
+
* The token of the server's token authentication.
|
|
110
|
+
*/
|
|
111
|
+
protected readonly token?: string;
|
|
112
|
+
/**
|
|
113
|
+
* The user name of the server's user/password authentication.
|
|
114
|
+
*/
|
|
115
|
+
protected readonly user?: string;
|
|
116
|
+
/**
|
|
117
|
+
* The password of the server's user/password authentication.
|
|
118
|
+
*/
|
|
119
|
+
protected readonly pass?: string;
|
|
120
|
+
/**
|
|
121
|
+
* Whether the client prints the protocol messages it sends and receives.
|
|
122
|
+
* @default false
|
|
123
|
+
*/
|
|
124
|
+
protected readonly debug?: boolean;
|
|
125
|
+
/**
|
|
126
|
+
* The number of pings left unanswered after which the connection is considered stale and the client reconnects.
|
|
127
|
+
* @default 2
|
|
128
|
+
*/
|
|
129
|
+
protected readonly maxPingOut?: number;
|
|
130
|
+
/**
|
|
131
|
+
* The number of reconnection attempts to each server before giving up, `-1` never giving up.
|
|
132
|
+
* @default 10
|
|
133
|
+
*/
|
|
134
|
+
protected readonly maxReconnectAttempts?: number;
|
|
135
|
+
/**
|
|
136
|
+
* The client name shown by the server's monitoring; it also names the default bucket of the bulk channel.
|
|
137
|
+
*/
|
|
138
|
+
protected readonly name?: string;
|
|
139
|
+
/**
|
|
140
|
+
* Whether the messages this client publishes are never delivered to its own subscriptions.
|
|
141
|
+
* @default false
|
|
142
|
+
*/
|
|
143
|
+
protected readonly noEcho?: boolean;
|
|
144
|
+
/**
|
|
145
|
+
* Whether the servers are tried in the order given, instead of a random order.
|
|
146
|
+
* @default false
|
|
147
|
+
*/
|
|
148
|
+
protected readonly noRandomize?: boolean;
|
|
149
|
+
/**
|
|
150
|
+
* The interval between the pings the client sends to check the connection, in milliseconds.
|
|
151
|
+
* @default 120000
|
|
152
|
+
*/
|
|
153
|
+
protected readonly pingInterval?: number;
|
|
154
|
+
/**
|
|
155
|
+
* Whether the client reconnects after losing its connection.
|
|
156
|
+
* @default true
|
|
157
|
+
*/
|
|
158
|
+
protected readonly reconnect?: boolean;
|
|
159
|
+
/**
|
|
160
|
+
* Whether the bulk channel, relaying the large payloads through a JetStream object store over a second connection,
|
|
161
|
+
* is prepared when the component starts.
|
|
162
|
+
* @default true
|
|
163
|
+
*/
|
|
164
|
+
protected readonly bulk?: boolean;
|
|
165
|
+
/**
|
|
166
|
+
* The object store bucket of the bulk channel.
|
|
167
|
+
* @default `lkt-bulk-{name}`, `lkt-bulk-default` without `name`
|
|
168
|
+
*/
|
|
169
|
+
protected readonly bulkBucket?: string;
|
|
170
|
+
/**
|
|
171
|
+
* The time to live of the objects of the bulk channel, in milliseconds.
|
|
172
|
+
* @default 300000 (5 minutes)
|
|
173
|
+
*/
|
|
174
|
+
protected readonly bulkTTL?: number;
|
|
175
|
+
/**
|
|
176
|
+
* The number of replicas of the bulk bucket, sent to the server only when set.
|
|
177
|
+
* @default none: the server's default (one replica)
|
|
178
|
+
*/
|
|
179
|
+
protected readonly bulkReplicas?: number;
|
|
180
|
+
/**
|
|
181
|
+
* The subscriptions of the service event listeners, by event subject, then by listener.
|
|
182
|
+
*/
|
|
183
|
+
protected readonly serviceEventSubscriptionMap: Map<string, Map<(...args: any[]) => void, Subscription>>;
|
|
184
|
+
/**
|
|
185
|
+
* Connect to the server, then prepare the bulk channel when it is enabled (a failure of the bulk channel only
|
|
186
|
+
* disables it, with a warning).
|
|
187
|
+
* @throws {Error} The NATS client error when no server can be reached.
|
|
188
|
+
*/
|
|
189
|
+
protected init(): Promise<void>;
|
|
190
|
+
/**
|
|
191
|
+
* Drain the connections: stop receiving, finish the messages in progress and flush the outgoing ones, then close.
|
|
192
|
+
*/
|
|
193
|
+
protected destroy(): Promise<void>;
|
|
194
|
+
/**
|
|
195
|
+
* Graceful shutdown: drain stops receiving, finishes the messages in progress and flushes the outgoing ones before closing,
|
|
196
|
+
* so the requests in progress survive a rolling update; a failed drain closes the connection
|
|
197
|
+
* @param conn
|
|
198
|
+
* @private
|
|
199
|
+
*/
|
|
200
|
+
private drainConnection;
|
|
201
|
+
/**
|
|
202
|
+
* Publish a message: every subscription to the subject receives it (one per queue group). It is not answered, and is
|
|
203
|
+
* lost when nobody listens.
|
|
204
|
+
* @param subject The subject, without wildcards (`order.created`).
|
|
205
|
+
* @param payload The data, encoded with the codec.
|
|
206
|
+
* @throws {Error} The NATS client error `MAX_PAYLOAD_EXCEEDED` when the encoded payload is larger than the server's
|
|
207
|
+
* `max_payload` (the published messages are never relayed through the bulk channel), `CONNECTION_CLOSED` once the
|
|
208
|
+
* connection is closed, `BAD_SUBJECT` for an empty subject; the codec's error when the payload cannot be encoded.
|
|
209
|
+
*/
|
|
210
|
+
publish(subject: string, payload: any): void;
|
|
211
|
+
/**
|
|
212
|
+
* Send a request and wait for its first response. A subscription answers it with its callback's return value (see
|
|
213
|
+
* {@link NATS.subscribe}); when nobody listens on the subject, it fails at once.
|
|
214
|
+
*
|
|
215
|
+
* A payload of 90% of the server's `max_payload` or more is relayed through the bulk channel when the subject's
|
|
216
|
+
* responders support it: learned from a previous response on the subject, else asked once by a probe of the subject
|
|
217
|
+
* (answered by the responders of this version with the bulk channel on; the older ones do not answer it). Otherwise it
|
|
218
|
+
* is sent as a message, and fails over `max_payload`. A large response is relayed the same way and read
|
|
219
|
+
* transparently.
|
|
220
|
+
* @param subject The subject of the responders.
|
|
221
|
+
* @param payload The data, encoded with the codec.
|
|
222
|
+
* @param timeout The time to wait for the response, in milliseconds; `0` or no value waits 600000 (10 minutes).
|
|
223
|
+
* @returns The response, decoded.
|
|
224
|
+
* @throws {NatsNoRespondersAvailableException} When nobody listens on the subject.
|
|
225
|
+
* @throws {NatsRequestTimeoutException} When no response arrives in time (the request may have been processed).
|
|
226
|
+
* @throws {NatsBulkException} When a large request cannot be stored, or a large response cannot be read.
|
|
227
|
+
* @throws {Error} The NATS client error `MAX_PAYLOAD_EXCEEDED` when a payload too large is not relayed,
|
|
228
|
+
* `CONNECTION_CLOSED` once the connection is closed; the codec's error when the payload or the response cannot be
|
|
229
|
+
* encoded or decoded.
|
|
230
|
+
*/
|
|
231
|
+
request(subject: string, payload?: any, timeout?: number): Promise<any>;
|
|
232
|
+
/**
|
|
233
|
+
* Subscribe to a subject and handle its messages with a callback. The payloads are decoded (and read from the bulk
|
|
234
|
+
* channel when they are references) before the callback runs. A request (a message with a reply subject, sent by
|
|
235
|
+
* {@link NATS.request}) is answered with the callback's return value, awaited and encoded, relayed through the bulk
|
|
236
|
+
* channel when it is large and the requester supports it; the return value of a published message is ignored.
|
|
237
|
+
*
|
|
238
|
+
* When the callback throws (or a payload cannot be decoded, or a response cannot be sent), the error is emitted as an
|
|
239
|
+
* `'error'` event, and a request is answered with `subscribeOptions.errorResponse`, or not answered at all (the
|
|
240
|
+
* requester waits for its timeout).
|
|
241
|
+
* @param subject The subject, possibly with wildcards: `*` matches one token (`order.*`), `>` the remaining tokens
|
|
242
|
+
* (`order.>`).
|
|
243
|
+
* @param callback The handler: receives the decoded payload and the subject the message arrived on (useful with the
|
|
244
|
+
* wildcards), and returns the response to a request.
|
|
245
|
+
* @param subscribeOptions The queue group, the number of messages, the sequential handling and the error response.
|
|
246
|
+
* @returns The NATS subscription: `unsubscribe()` stops it at once, `drain()` once the messages received are handled.
|
|
247
|
+
* @throws {Error} The NATS client error `CONNECTION_CLOSED` once the connection is closed, `BAD_SUBJECT` for an invalid
|
|
248
|
+
* subject.
|
|
249
|
+
*/
|
|
250
|
+
subscribe(subject: string, callback: (data: any, subject: string) => any | Promise<any>, subscribeOptions?: SubscribeOptions): Subscription;
|
|
251
|
+
/**
|
|
252
|
+
* Subscribe to a subject, as {@link NATS.subscribe}; the subscriptions of the events do not answer the capability
|
|
253
|
+
* probes of the requesters (nobody requests them).
|
|
254
|
+
* @param subject The subject, wildcards allowed.
|
|
255
|
+
* @param callback Called with each message's data and subject; its result answers a request.
|
|
256
|
+
* @param subscribeOptions The queue group, the number of messages, the iteration and the error responses.
|
|
257
|
+
* @param answerProbes Whether the subscription answers the capability probes of the large requests to its subject.
|
|
258
|
+
* @returns The NATS subscription.
|
|
259
|
+
* @protected
|
|
260
|
+
*/
|
|
261
|
+
protected subscribeTo(subject: string, callback: (data: any, subject: string) => any | Promise<any>, subscribeOptions: SubscribeOptions | undefined, answerProbes: boolean): Subscription;
|
|
262
|
+
/**
|
|
263
|
+
* Emit an `'error'` event when the component has listeners, and do nothing otherwise (an `'error'` event
|
|
264
|
+
* without listener would throw).
|
|
265
|
+
* @param error The error to report.
|
|
266
|
+
*/
|
|
267
|
+
protected emitError(error: any): void;
|
|
268
|
+
/**
|
|
269
|
+
* Whether the bulk channel is ready: enabled by the `bulk` option and started (its connection and object store
|
|
270
|
+
* prepared).
|
|
271
|
+
*/
|
|
272
|
+
get bulkEnabled(): boolean;
|
|
273
|
+
/**
|
|
274
|
+
* The encoded size from which a payload is relayed through the bulk channel, in bytes: 90% of the current server's
|
|
275
|
+
* `max_payload` (1 MiB when unknown).
|
|
276
|
+
*/
|
|
277
|
+
get bulkThreshold(): number;
|
|
278
|
+
/**
|
|
279
|
+
* Whether the current server supports the message headers, which the bulk channel needs to mark its references.
|
|
280
|
+
*/
|
|
281
|
+
get headersSupported(): boolean;
|
|
282
|
+
/**
|
|
283
|
+
* Store bytes in the bulk channel's object store, for its time to live (`bulkTTL`).
|
|
284
|
+
* @param bytes The bytes to store.
|
|
285
|
+
* @returns The id of the object (a random UUID), to read it with {@link NATS.getBulk}.
|
|
286
|
+
* @throws {NatsBulkException} When the bulk channel is not enabled, or the object store rejects the write.
|
|
287
|
+
*/
|
|
288
|
+
putBulk(bytes: Uint8Array): Promise<string>;
|
|
289
|
+
/**
|
|
290
|
+
* Read an object from the bulk channel's object store. The object is not deleted.
|
|
291
|
+
* @param objId The id returned by {@link NATS.putBulk}.
|
|
292
|
+
* @returns The bytes stored.
|
|
293
|
+
* @throws {NatsBulkException} When the bulk channel is not enabled, the object store rejects the read, or the object
|
|
294
|
+
* does not exist (never stored, expired, or deleted).
|
|
295
|
+
*/
|
|
296
|
+
getBulk(objId: string): Promise<Uint8Array>;
|
|
297
|
+
/**
|
|
298
|
+
* Delete an object from the bulk channel's object store; nothing happens when the bulk channel is not enabled.
|
|
299
|
+
* @param objId The id returned by {@link NATS.putBulk}.
|
|
300
|
+
* @throws {Error} The object store's error when the deletion fails.
|
|
301
|
+
*/
|
|
302
|
+
deleteBulk(objId: string): Promise<void>;
|
|
303
|
+
/**
|
|
304
|
+
* Read the status of the bulk channel's object store: its bucket, time to live, replicas, storage and size.
|
|
305
|
+
* @returns The status, or `undefined` when the bulk channel is not enabled.
|
|
306
|
+
*/
|
|
307
|
+
bulkStatus(): Promise<ObjectStoreStatus | undefined>;
|
|
308
|
+
/**
|
|
309
|
+
* Ask the responders of a subject whether they support the bulk references, before the first large request to it:
|
|
310
|
+
* the responders supporting them answer on the probe subject, the others (an older version, the bulk channel off)
|
|
311
|
+
* have no subscription there (no responders, or no answer in time). The answer is kept for the subject.
|
|
312
|
+
* @param subject The subject of the request.
|
|
313
|
+
* @returns Whether its responders support the bulk references.
|
|
314
|
+
* @private
|
|
315
|
+
*/
|
|
316
|
+
private probeBulk;
|
|
317
|
+
/**
|
|
318
|
+
* Pack a payload to send: encoded, then stored in the object store and sent as a small reference when it is large and the peer supports it
|
|
319
|
+
* @param payload
|
|
320
|
+
* @param peerSupportsBulk whether the peer supports the references (the payload itself is sent otherwise)
|
|
321
|
+
* @private
|
|
322
|
+
*/
|
|
323
|
+
private packPayload;
|
|
324
|
+
/**
|
|
325
|
+
* Unpack received bytes: a reference is read from the object store then decoded (deleted once read, its time to live covers a failure)
|
|
326
|
+
* @param bytes
|
|
327
|
+
* @param isRef
|
|
328
|
+
* @private
|
|
329
|
+
*/
|
|
330
|
+
private unpackPayload;
|
|
331
|
+
/**
|
|
332
|
+
* Emit a service event of this application: the listeners registered for it with the application's id (with
|
|
333
|
+
* {@link NATS.onServiceEvent} or `ServiceProxy.on()`) receive the arguments. The event is published at most once: the
|
|
334
|
+
* applications not listening, or disconnected, miss it.
|
|
335
|
+
* @param eventName The event name.
|
|
336
|
+
* @param args The arguments given to the listeners, encoded with the codec (as one array).
|
|
337
|
+
* @returns The component, for chaining.
|
|
338
|
+
* @throws {Error} The NATS client error `MAX_PAYLOAD_EXCEEDED` when the encoded arguments are larger than the server's
|
|
339
|
+
* `max_payload` (the events are never relayed through the bulk channel), `CONNECTION_CLOSED` once the connection is
|
|
340
|
+
* closed; the codec's error when the arguments cannot be encoded.
|
|
341
|
+
*/
|
|
342
|
+
emitServiceEvent(eventName: string, ...args: any[]): this;
|
|
343
|
+
/**
|
|
344
|
+
* Listen to a service event of an application. A listener registered again for the same event (by this method or
|
|
345
|
+
* {@link NATS.onceServiceEvent}) is ignored. A listener which throws is reported as an `'error'` event; the rejection of
|
|
346
|
+
* an asynchronous listener is not caught.
|
|
347
|
+
* @param serviceId The id of the application emitting the event (its `id` option).
|
|
348
|
+
* @param eventName The event name.
|
|
349
|
+
* @param listener The listener, receiving the event's arguments.
|
|
350
|
+
* @param onlySingleClientReceived Whether each event goes to one of the listeners registered with `true` for it, across
|
|
351
|
+
* all the applications (a queue group), instead of to each of them; the listeners registered with `false` still receive
|
|
352
|
+
* every event.
|
|
353
|
+
* @returns The component, for chaining.
|
|
354
|
+
* @throws {Error} The NATS client error `CONNECTION_CLOSED` once the connection is closed.
|
|
355
|
+
*/
|
|
356
|
+
onServiceEvent(serviceId: string, eventName: string, listener: (...args: any[]) => void, onlySingleClientReceived?: boolean): this;
|
|
357
|
+
/**
|
|
358
|
+
* Listen to the next occurrence of a service event of an application only: the listener is removed once called. A
|
|
359
|
+
* listener already registered for the event is ignored.
|
|
360
|
+
* @param serviceId The id of the application emitting the event (its `id` option).
|
|
361
|
+
* @param eventName The event name.
|
|
362
|
+
* @param listener The listener, receiving the event's arguments.
|
|
363
|
+
* @returns The component, for chaining.
|
|
364
|
+
* @throws {Error} The NATS client error `CONNECTION_CLOSED` once the connection is closed.
|
|
365
|
+
*/
|
|
366
|
+
onceServiceEvent(serviceId: string, eventName: string, listener: (...args: any[]) => void): this;
|
|
367
|
+
/**
|
|
368
|
+
* Stop listening to a service event of an application.
|
|
369
|
+
* @param serviceId The id of the application emitting the event.
|
|
370
|
+
* @param eventName The event name.
|
|
371
|
+
* @param listener The listener to remove; without it, every listener registered on this component for the event is
|
|
372
|
+
* removed (those of the service proxies using the component included).
|
|
373
|
+
* @returns The component, for chaining.
|
|
374
|
+
*/
|
|
375
|
+
offServiceEvent(serviceId: string, eventName: string, listener?: (...args: any[]) => void): this;
|
|
376
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { ServiceContext, type EntrypointAdapter, type MiddlewareDefinition } from '@lakutata/entrypoint';
|
|
2
|
+
/**
|
|
3
|
+
* The options of {@link natsServiceEntrypoint}.
|
|
4
|
+
*/
|
|
5
|
+
export type NatsServiceEntrypointOptions = {
|
|
6
|
+
/**
|
|
7
|
+
* The adapter name, to tell apart several service adapters of one entrypoint.
|
|
8
|
+
*/
|
|
9
|
+
name?: string;
|
|
10
|
+
/**
|
|
11
|
+
* The subject the requests are received on: the `serviceId` the service proxies use. The events of
|
|
12
|
+
* `Entrypoint.broadcast()` are published under it; the ones of `NATS.emitServiceEvent()` under the application id.
|
|
13
|
+
* @default the application id (its `id` option)
|
|
14
|
+
*/
|
|
15
|
+
subject?: string;
|
|
16
|
+
/**
|
|
17
|
+
* The queue group sharing the requests between the instances of the service: each request is handled by one of
|
|
18
|
+
* them.
|
|
19
|
+
* @default `{subject}.serviceQueue`
|
|
20
|
+
*/
|
|
21
|
+
queue?: string;
|
|
22
|
+
/**
|
|
23
|
+
* The middlewares of this adapter's actions, run after the entrypoint's global middlewares.
|
|
24
|
+
*/
|
|
25
|
+
middlewares?: MiddlewareDefinition[];
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Create a service adapter of an entrypoint served over NATS: the requests sent to the application's id (by the
|
|
29
|
+
* {@link ServiceProxy} components of the other applications, or any NATS client) are dispatched to the controllers'
|
|
30
|
+
* service actions, through the {@link NATS} component registered under `natsComponentName`.
|
|
31
|
+
*
|
|
32
|
+
* A request's payload is the message matched against the `@ServiceAction` patterns: the action's pattern and its input
|
|
33
|
+
* in one object. It is answered with a service response `{success, error, payload}` (see `ServiceResponseCodec`):
|
|
34
|
+
* `payload` is the action's result, or `error` the properties of the error when the action failed (no matching action,
|
|
35
|
+
* validation, access denied…). A request whose payload cannot be decoded, or whose response cannot be sent, is answered
|
|
36
|
+
* with such an error too, so the requester does not wait for its timeout. A published message (without reply subject)
|
|
37
|
+
* runs the action without answer.
|
|
38
|
+
*
|
|
39
|
+
* The instances of the service share the requests through a queue group: each request is handled by one of them. Large
|
|
40
|
+
* requests and responses go through the NATS component's bulk channel. `Entrypoint.broadcast()` publishes its events
|
|
41
|
+
* under the entrypoint's subject, to the proxies of the service (it counts them 0: NATS does not tell how many receive
|
|
42
|
+
* them); `Entrypoint.notify()` does not reach it (NATS has no client ids). When the entrypoint stops, the subscription is drained: no request is received any more
|
|
43
|
+
* (the callers get no responder and retry), the requests in progress are answered.
|
|
44
|
+
* @param natsComponentName The name of the NATS component, as registered in the components; the entrypoint fails to
|
|
45
|
+
* start when it is not registered.
|
|
46
|
+
* @param options The subject, the queue group, the adapter name and its middlewares.
|
|
47
|
+
* @returns The adapter, to give to the `service` option of `buildEntrypoints`.
|
|
48
|
+
* @example
|
|
49
|
+
* ```typescript
|
|
50
|
+
* import {Application, DTO} from 'lakutata'
|
|
51
|
+
* import {buildEntrypoints, Controller} from 'lakutata/com/entrypoint'
|
|
52
|
+
* import {ServiceAction} from 'lakutata/decorator/ctrl'
|
|
53
|
+
* import {Expect} from 'lakutata/decorator/dto'
|
|
54
|
+
* import {buildNatsClientOptions, natsServiceEntrypoint} from '@lakutata/nats'
|
|
55
|
+
*
|
|
56
|
+
* class GetOrderDTO extends DTO {
|
|
57
|
+
* @Expect(DTO.Number().integer().required())
|
|
58
|
+
* public id!: number
|
|
59
|
+
* }
|
|
60
|
+
*
|
|
61
|
+
* class OrderController extends Controller {
|
|
62
|
+
* //Invoked by orderService.invoke({cmd: 'order.get', id: 1}) in the other applications
|
|
63
|
+
* @ServiceAction({cmd: 'order.get'}, GetOrderDTO)
|
|
64
|
+
* public async get(input: GetOrderDTO): Promise<{ id: number, total: number }> {
|
|
65
|
+
* return {id: input.id, total: 42}
|
|
66
|
+
* }
|
|
67
|
+
* }
|
|
68
|
+
*
|
|
69
|
+
* Application.run({
|
|
70
|
+
* //The subject of the requests: the serviceId of the proxies
|
|
71
|
+
* id: 'order.service',
|
|
72
|
+
* name: 'OrderService',
|
|
73
|
+
* components: {
|
|
74
|
+
* nats: buildNatsClientOptions({servers: 'nats://127.0.0.1:4222'}),
|
|
75
|
+
* entrypoint: buildEntrypoints({
|
|
76
|
+
* controllers: [OrderController],
|
|
77
|
+
* service: natsServiceEntrypoint('nats')
|
|
78
|
+
* })
|
|
79
|
+
* },
|
|
80
|
+
* bootstrap: ['entrypoint']
|
|
81
|
+
* })
|
|
82
|
+
* ```
|
|
83
|
+
*/
|
|
84
|
+
export declare function natsServiceEntrypoint(natsComponentName: string, options?: NatsServiceEntrypointOptions): EntrypointAdapter<ServiceContext>;
|
|
85
|
+
/**
|
|
86
|
+
* The former name of {@link natsServiceEntrypoint}, kept for the applications written for 2.x; it behaves the same.
|
|
87
|
+
* @param natsComponentName The name of the NATS component, as registered in the components.
|
|
88
|
+
* @param options The subject, the queue group, the adapter name and its middlewares.
|
|
89
|
+
* @returns The adapter, to give to the `service` option of `buildEntrypoints`.
|
|
90
|
+
* @example
|
|
91
|
+
* ```typescript
|
|
92
|
+
* import {buildEntrypoints, Controller} from 'lakutata/com/entrypoint'
|
|
93
|
+
* import {setupNatsServiceEntrypoint} from '@lakutata/nats'
|
|
94
|
+
*
|
|
95
|
+
* class OrderController extends Controller {
|
|
96
|
+
* }
|
|
97
|
+
*
|
|
98
|
+
* //The same as natsServiceEntrypoint('nats')
|
|
99
|
+
* export const entrypoint = buildEntrypoints({controllers: [OrderController], service: setupNatsServiceEntrypoint('nats')})
|
|
100
|
+
* ```
|
|
101
|
+
*/
|
|
102
|
+
export declare const setupNatsServiceEntrypoint: (natsComponentName: string, options?: NatsServiceEntrypointOptions) => EntrypointAdapter<ServiceContext>;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Exception } from '@lakutata/core';
|
|
2
|
+
/**
|
|
3
|
+
* Thrown by `NATS.request()` (and so `ServiceProxy.invoke()`) when the request fails with an error of the NATS client
|
|
4
|
+
* whose code is `400` (a bad request). The client reports such codes for some JetStream operations, not for the core
|
|
5
|
+
* requests the component sends, so it is rarely seen. Its `errno` is `E_NATS_BAD_REQUEST`, its `statusCode` 400.
|
|
6
|
+
*/
|
|
7
|
+
export declare class NatsBadRequestException extends Exception {
|
|
8
|
+
errno: string | number;
|
|
9
|
+
message: string;
|
|
10
|
+
statusCode: number;
|
|
11
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Exception } from '@lakutata/core';
|
|
2
|
+
/**
|
|
3
|
+
* A failure of the bulk channel, which relays the large payloads through a JetStream object store; its message tells
|
|
4
|
+
* the cause:
|
|
5
|
+
* - `bulk channel is not enabled`: `putBulk()` or `getBulk()` called, or a reference received, while the channel is
|
|
6
|
+
* disabled (the `bulk` option is `false`, or the channel failed to start);
|
|
7
|
+
* - `bulk put failed: …` / `bulk get failed: …`: the object store rejected the write or the read;
|
|
8
|
+
* - `bulk object not found: <id>`: the referenced object is gone (its time to live passed) or is in another bucket
|
|
9
|
+
* (the peers do not share their `bulkBucket`).
|
|
10
|
+
*
|
|
11
|
+
* `NATS.request()` and `ServiceProxy.invoke()` throw it when the large request cannot be stored or the large response
|
|
12
|
+
* cannot be read; `ServiceProxy.invoke()` never retries it, since the service may have processed the request. On the
|
|
13
|
+
* service side, the failure is answered to the requester, which receives a `ServiceInvokeException` whose `errno` is
|
|
14
|
+
* `E_NATS_BULK`. Its `errno` is `E_NATS_BULK`, its `statusCode` 502.
|
|
15
|
+
*/
|
|
16
|
+
export declare class NatsBulkException extends Exception {
|
|
17
|
+
errno: string | number;
|
|
18
|
+
statusCode: number;
|
|
19
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Exception } from '@lakutata/core';
|
|
2
|
+
/**
|
|
3
|
+
* Thrown by `NATS.request()` (and so `ServiceProxy.invoke()`) when the request fails with an error of the NATS client
|
|
4
|
+
* whose code is `403` (a forbidden request). The client reports such codes for some JetStream operations, not for the
|
|
5
|
+
* core requests the component sends, so it is rarely seen. Its `errno` is `E_NATS_FORBIDDEN`, its `statusCode` 403.
|
|
6
|
+
*/
|
|
7
|
+
export declare class NatsForbiddenException extends Exception {
|
|
8
|
+
errno: string | number;
|
|
9
|
+
message: string;
|
|
10
|
+
statusCode: number;
|
|
11
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Exception } from '@lakutata/core';
|
|
2
|
+
/**
|
|
3
|
+
* Thrown by `NATS.request()` (and so `ServiceProxy.invoke()`) when the request fails with an error of the NATS client
|
|
4
|
+
* whose code is `500` (an internal error of the server). The client reports such codes for some JetStream operations,
|
|
5
|
+
* not for the core requests the component sends, so it is rarely seen. Its `errno` is `E_NATS_INTERNAL_SERVER`, its
|
|
6
|
+
* `statusCode` 500.
|
|
7
|
+
*/
|
|
8
|
+
export declare class NatsInternalServerException extends Exception {
|
|
9
|
+
errno: string | number;
|
|
10
|
+
message: string;
|
|
11
|
+
statusCode: number;
|
|
12
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Exception } from '@lakutata/core';
|
|
2
|
+
/**
|
|
3
|
+
* Thrown by `NATS.request()` when no subscription receives the request: nobody listens on the subject (the service is
|
|
4
|
+
* not running, or is stopping). It is thrown at once, without waiting for the timeout, and the request was not
|
|
5
|
+
* processed: `ServiceProxy.invoke()` retries it (`maxRetries` times) before throwing it. Its `errno` is
|
|
6
|
+
* `E_NATS_NO_RESPONDERS_AVAILABLE`, its `statusCode` 503.
|
|
7
|
+
*/
|
|
8
|
+
export declare class NatsNoRespondersAvailableException extends Exception {
|
|
9
|
+
errno: string | number;
|
|
10
|
+
message: string;
|
|
11
|
+
statusCode: number;
|
|
12
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Exception } from '@lakutata/core';
|
|
2
|
+
/**
|
|
3
|
+
* Thrown by `NATS.request()` (and so `ServiceProxy.invoke()`) when the request fails with an error of the NATS client
|
|
4
|
+
* whose code is `404` (a subject not found). The client reports such codes for some JetStream operations, not for the
|
|
5
|
+
* core requests the component sends, so it is rarely seen. Its `errno` is `E_NATS_NOT_FOUND`, its `statusCode` 404.
|
|
6
|
+
*/
|
|
7
|
+
export declare class NatsNotFoundException extends Exception {
|
|
8
|
+
errno: string | number;
|
|
9
|
+
message: string;
|
|
10
|
+
statusCode: number;
|
|
11
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Exception } from '@lakutata/core';
|
|
2
|
+
/**
|
|
3
|
+
* Thrown by `NATS.request()` (and so `ServiceProxy.invoke()`) when no response arrives within the request's timeout.
|
|
4
|
+
* The request may have been received and processed, its response lost or late: it is never retried. Its `errno` is
|
|
5
|
+
* `E_NATS_REQUEST_TIMEOUT`, its `statusCode` 408.
|
|
6
|
+
*/
|
|
7
|
+
export declare class NatsRequestTimeoutException extends Exception {
|
|
8
|
+
errno: string | number;
|
|
9
|
+
message: string;
|
|
10
|
+
statusCode: number;
|
|
11
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export { natsServiceEntrypoint, setupNatsServiceEntrypoint, type NatsServiceEntrypointOptions } from '../entrypoints/NatsServiceEntrypoint.js';
|
|
2
|
+
export { ServiceProxy, buildServiceProxy, type BuildServiceProxyOptions } from '../providers/ServiceProxy.js';
|
|
3
|
+
export { RetentionPolicy } from 'nats';
|
|
4
|
+
export { NATS, buildNatsClientOptions } from '../components/NATS.js';
|
|
5
|
+
export { jsonCodec } from '../codecs/JSONCodec.js';
|
|
6
|
+
export { messagePackCodec } from '../codecs/MessagePackCodec.js';
|
|
7
|
+
export { StringCodec } from 'nats';
|
|
8
|
+
export type { SubscribeOptions } from '../types/SubscribeOptions.js';
|
|
9
|
+
export type { Subscription, Codec } from 'nats';
|
|
10
|
+
export type { NatsClientOptions } from '../interfaces/NatsClientOptions.js';
|
|
11
|
+
export { NatsBadRequestException } from '../exceptions/NatsBadRequestException.js';
|
|
12
|
+
export { NatsForbiddenException } from '../exceptions/NatsForbiddenException.js';
|
|
13
|
+
export { NatsInternalServerException } from '../exceptions/NatsInternalServerException.js';
|
|
14
|
+
export { NatsNoRespondersAvailableException } from '../exceptions/NatsNoRespondersAvailableException.js';
|
|
15
|
+
export { NatsNotFoundException } from '../exceptions/NatsNotFoundException.js';
|
|
16
|
+
export { NatsRequestTimeoutException } from '../exceptions/NatsRequestTimeoutException.js';
|
|
17
|
+
export { ServiceInvokeException } from '@lakutata/entrypoint';
|
|
18
|
+
export { NatsBulkException } from '../exceptions/NatsBulkException.js';
|