@lad-tech/nsc-toolkit 1.21.0 → 1.22.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,6 +1,6 @@
1
- # [1.21.0](https://github.com/lad-tech/nsc-toolkit/compare/v1.20.1...v1.21.0) (2024-08-14)
1
+ ## [1.22.1](https://github.com/lad-tech/nsc-toolkit/compare/v1.22.0...v1.22.1) (2024-08-15)
2
2
 
3
3
 
4
- ### Features
4
+ ### Bug Fixes
5
5
 
6
- * Add new requestId field into baggage ([#113](https://github.com/lad-tech/nsc-toolkit/issues/113)) ([02c222d](https://github.com/lad-tech/nsc-toolkit/commit/02c222d13b7325211edc6049cad8301440b64b47))
6
+ * Add required version nats driver and update nats driver ([#115](https://github.com/lad-tech/nsc-toolkit/issues/115)) ([1815d3a](https://github.com/lad-tech/nsc-toolkit/commit/1815d3a77d354aa8c0b97fe33503365f638b9641))
package/dist/Client.js CHANGED
@@ -36,12 +36,29 @@ class Client extends Root_1.Root {
36
36
  message.ack = event.ack.bind(event);
37
37
  message.nak = event.nak.bind(event);
38
38
  }
39
- listener.emit(`${eventName}`, message);
39
+ listener.emit(eventName, message);
40
+ }
41
+ }
42
+ async startBatchWatch(fetcher, listener, eventName) {
43
+ while (true) {
44
+ const batch = [];
45
+ const events = fetcher.fetch();
46
+ for await (const event of events) {
47
+ let data;
48
+ try {
49
+ data = (0, nats_1.JSONCodec)().decode(event.data);
50
+ }
51
+ catch (error) {
52
+ data = (0, nats_1.StringCodec)().decode(event.data);
53
+ }
54
+ const message = { data };
55
+ message.ack = event.ack.bind(event);
56
+ message.nak = event.nak.bind(event);
57
+ batch.push(message);
58
+ }
59
+ listener.emit(eventName, batch);
40
60
  }
41
61
  }
42
- /**
43
- * Make listener for service events. Auto subscribe and unsubscribe to subject
44
- */
45
62
  getListener(serviceNameFrom, options) {
46
63
  if (!this.events) {
47
64
  throw new Error('The service does not generate events');
@@ -73,7 +90,12 @@ class Client extends Root_1.Root {
73
90
  subscription = this.broker.subscribe(`${this.serviceName}.${eventName}`, queue);
74
91
  }
75
92
  this.subscriptions.set(eventName, subscription);
76
- this.startWatch(subscription, listener, String(eventName));
93
+ if (StreamManager_1.StreamManager.isStreamFetcher(subscription) && StreamManager_1.StreamManager.isPullConsumerOptions(options)) {
94
+ this.startBatchWatch(subscription, listener, String(eventName));
95
+ }
96
+ else {
97
+ this.startWatch(subscription, listener, String(eventName));
98
+ }
77
99
  return method.call(target, eventName, handler);
78
100
  }
79
101
  catch (error) {
@@ -182,7 +204,8 @@ class Client extends Root_1.Root {
182
204
  return (0, nats_1.JSONCodec)().decode(result.data);
183
205
  }
184
206
  catch (error) {
185
- return this.buildErrorMessage(error);
207
+ const errorMessage = new Error(`${error === null || error === void 0 ? void 0 : error.message}. Subject: ${subject} `);
208
+ return this.buildErrorMessage(errorMessage);
186
209
  }
187
210
  }
188
211
  async makeHttpRequest(subject, message, options, timeout) {
@@ -219,11 +242,13 @@ class Client extends Root_1.Root {
219
242
  resolve(JSON.parse(responseDataString));
220
243
  }
221
244
  catch (error) {
222
- resolve(this.buildErrorMessage(error));
245
+ const errorMessage = new Error(`${error === null || error === void 0 ? void 0 : error.message}. Subject: ${subject} `);
246
+ resolve(this.buildErrorMessage(errorMessage));
223
247
  }
224
248
  });
225
249
  request.on('error', error => {
226
- resolve(this.buildErrorMessage(error));
250
+ const errorMessage = new Error(`${error === null || error === void 0 ? void 0 : error.message}. Subject: ${subject} `);
251
+ resolve(this.buildErrorMessage(errorMessage));
227
252
  });
228
253
  if (this.isStream(message.payload)) {
229
254
  message.payload.pipe(request);
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.StreamFetcher = void 0;
4
+ class StreamFetcher {
5
+ constructor(jsClient, streamName, consumerName, options) {
6
+ this.jsClient = jsClient;
7
+ this.streamName = streamName;
8
+ this.consumerName = consumerName;
9
+ this.options = options;
10
+ }
11
+ fetch(noWait, size, expires) {
12
+ return this.jsClient.fetch(this.streamName, this.consumerName, {
13
+ batch: size !== null && size !== void 0 ? size : this.options.batchSize,
14
+ expires: expires !== null && expires !== void 0 ? expires : this.options.batchTimeout,
15
+ no_wait: noWait !== null && noWait !== void 0 ? noWait : this.options.noWait,
16
+ });
17
+ }
18
+ }
19
+ exports.StreamFetcher = StreamFetcher;
20
+ //# sourceMappingURL=StreamFetcher.js.map
@@ -3,6 +3,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.StreamManager = void 0;
4
4
  const nats_1 = require("nats");
5
5
  const Root_1 = require("./Root");
6
+ const StreamFetcher_1 = require("./StreamFetcher");
7
+ const types_1 = require("nats/lib/jetstream/types");
6
8
  class StreamManager extends Root_1.Root {
7
9
  constructor(param) {
8
10
  super(param.broker, param.outputFormatter);
@@ -21,6 +23,12 @@ class StreamManager extends Root_1.Root {
21
23
  rollUps: true,
22
24
  };
23
25
  }
26
+ static isPullConsumerOptions(setting) {
27
+ return !!(setting === null || setting === void 0 ? void 0 : setting.batch);
28
+ }
29
+ static isStreamFetcher(consumer) {
30
+ return !!(consumer === null || consumer === void 0 ? void 0 : consumer.fetch);
31
+ }
24
32
  async createStreams() {
25
33
  if (!this.jsm) {
26
34
  this.jsm = await this.param.broker.jetstreamManager();
@@ -55,14 +63,29 @@ class StreamManager extends Root_1.Root {
55
63
  async createConsumer(serviceNameFrom, eventName, setting) {
56
64
  const consumerName = this.capitalizeFirstLetter(serviceNameFrom) + this.capitalizeFirstLetter(eventName);
57
65
  const prefix = this.param.options.prefix;
58
- const subjeсt = `${this.param.serviceName}.${prefix}.${eventName}`;
66
+ const subject = `${this.param.serviceName}.${prefix}.${eventName}`;
67
+ if (!this.jsm) {
68
+ this.jsm = await this.param.broker.jetstreamManager();
69
+ }
59
70
  const options = (0, nats_1.consumerOpts)();
71
+ const isPullConsumer = StreamManager.isPullConsumerOptions(setting);
60
72
  options
61
73
  .durable(consumerName)
62
74
  .manualAck()
63
75
  .ackExplicit()
64
- .maxAckPending((setting === null || setting === void 0 ? void 0 : setting.maxPending) || 10)
65
- .deliverTo((0, nats_1.createInbox)());
76
+ .filterSubject(subject)
77
+ .maxAckPending((setting === null || setting === void 0 ? void 0 : setting.maxPending) || 10);
78
+ if (!isPullConsumer) {
79
+ options.deliverTo((0, nats_1.createInbox)());
80
+ }
81
+ if (isPullConsumer) {
82
+ if (setting.maxPullRequestExpires) {
83
+ options.maxPullRequestExpires(setting.maxPullRequestExpires);
84
+ }
85
+ if (setting.maxPullRequestBatch) {
86
+ options.maxPullBatch(setting.maxPullRequestBatch);
87
+ }
88
+ }
66
89
  if (setting === null || setting === void 0 ? void 0 : setting.maxAckWaiting) {
67
90
  options.ackWait(setting.maxAckWaiting);
68
91
  }
@@ -77,7 +100,19 @@ class StreamManager extends Root_1.Root {
77
100
  options.deliverAll();
78
101
  }
79
102
  }
80
- return this.broker.jetstream().subscribe(subjeсt, options);
103
+ const streamName = await this.jsm.streams.find(subject);
104
+ if (!streamName) {
105
+ throw new Error(`Error creating consumer ${consumerName}. Stream for subject ${subject} not found`);
106
+ }
107
+ if ((0, types_1.isConsumerOptsBuilder)(options)) {
108
+ await this.jsm.consumers.add(streamName, options.config);
109
+ }
110
+ return isPullConsumer
111
+ ? new StreamFetcher_1.StreamFetcher(this.broker.jetstream(), streamName, consumerName, {
112
+ batchSize: setting.maxPullRequestBatch,
113
+ batchTimeout: setting.maxPullRequestExpires,
114
+ })
115
+ : this.broker.jetstream().subscribe(subject, options);
81
116
  }
82
117
  getStreamName(eventName) {
83
118
  const serviceName = this.capitalizeFirstLetter(this.param.serviceName);
@@ -13,6 +13,18 @@ class UnionBroker {
13
13
  this.DEFAULT_TIMEOUT = 60000; // 1 Minut
14
14
  this.emitter = new node_stream_1.EventEmitter();
15
15
  }
16
+ publishMessage(msg) {
17
+ throw new Error('Method not implemented.');
18
+ }
19
+ respondMessage(msg) {
20
+ throw new Error('Method not implemented.');
21
+ }
22
+ requestMany(subject, payload, opts) {
23
+ throw new Error('Method not implemented.');
24
+ }
25
+ reconnect() {
26
+ throw new Error('Method not implemented.');
27
+ }
16
28
  closed() {
17
29
  return Promise.resolve();
18
30
  }
@@ -6,6 +6,12 @@ class JetStreamClientBlank {
6
6
  constructor(emitter) {
7
7
  this.emitter = emitter;
8
8
  }
9
+ jetstreamManager(checkAPI) {
10
+ throw new Error('Method not implemented.');
11
+ }
12
+ getOptions() {
13
+ throw new Error('Method not implemented.');
14
+ }
9
15
  publish(subj, data, options) {
10
16
  throw new Error('Method publish not implemented.');
11
17
  }
@@ -6,6 +6,12 @@ class JetStreamManagerBlank {
6
6
  constructor() {
7
7
  this.streams = new StreamApi_1.StreamApiBlank();
8
8
  }
9
+ getOptions() {
10
+ throw new Error('Method not implemented.');
11
+ }
12
+ jetstream() {
13
+ throw new Error('Method not implemented.');
14
+ }
9
15
  getAccountInfo() {
10
16
  throw new Error('Method getAccountInfo not implemented.');
11
17
  }
@@ -2,6 +2,18 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.StreamApiBlank = void 0;
4
4
  class StreamApiBlank {
5
+ listKvs() {
6
+ throw new Error('Method not implemented.');
7
+ }
8
+ listObjectStores() {
9
+ throw new Error('Method not implemented.');
10
+ }
11
+ names(subject) {
12
+ throw new Error('Method not implemented.');
13
+ }
14
+ get(name) {
15
+ throw new Error('Method not implemented.');
16
+ }
5
17
  info(stream, opts) {
6
18
  return Promise.resolve({});
7
19
  }
@@ -1,6 +1,6 @@
1
1
  /// <reference types="node" />
2
2
  import { Readable } from 'node:stream';
3
- import { ClientParam, Emitter, GetListenerOptions, Listener, MethodSettings } from './interfaces';
3
+ import { ClientParam, Emitter, GetBatchListenerOptions, GetListenerOptions, Listener, ListenerBatch, MethodSettings } from './interfaces';
4
4
  import { Root } from './Root';
5
5
  type RequestData = Record<string, unknown> | Readable;
6
6
  export declare class Client<E extends Emitter = Emitter> extends Root {
@@ -13,10 +13,12 @@ export declare class Client<E extends Emitter = Emitter> extends Root {
13
13
  private REQUEST_HTTP_SETTINGS_TIMEOUT;
14
14
  constructor({ broker, events, loggerOutputFormatter, serviceName, baggage, cache, Ref }: ClientParam<E>);
15
15
  private startWatch;
16
+ private startBatchWatch;
16
17
  /**
17
18
  * Make listener for service events. Auto subscribe and unsubscribe to subject
18
19
  */
19
20
  getListener<A extends keyof E>(serviceNameFrom: string, options?: GetListenerOptions): Listener<E>;
21
+ getListener<A extends keyof E>(serviceNameFrom: string, options?: GetBatchListenerOptions): ListenerBatch<E>;
20
22
  private createCacheKey;
21
23
  private validate;
22
24
  protected request<R = any, P extends RequestData = RequestData>(subject: string, data: P, { options, request, response }: MethodSettings): Promise<R>;
@@ -0,0 +1,15 @@
1
+ import { JetStreamClient, JsMsg, QueuedIterator } from 'nats';
2
+ interface BatcherOptions {
3
+ batchSize?: number;
4
+ batchTimeout?: number;
5
+ noWait?: boolean;
6
+ }
7
+ export declare class StreamFetcher {
8
+ private jsClient;
9
+ private streamName;
10
+ private consumerName;
11
+ private options;
12
+ constructor(jsClient: JetStreamClient, streamName: string, consumerName: string, options: BatcherOptions);
13
+ fetch(noWait?: boolean, size?: number, expires?: number): QueuedIterator<JsMsg>;
14
+ }
15
+ export {};
@@ -1,6 +1,7 @@
1
- import { StreamManagerParam, GetListenerOptions } from '.';
2
- import { JetStreamSubscription } from 'nats';
1
+ import { StreamManagerParam, GetListenerOptions, GetBatchListenerOptions } from '.';
2
+ import { JetStreamSubscription, Subscription } from 'nats';
3
3
  import { Root } from './Root';
4
+ import { StreamFetcher } from './StreamFetcher';
4
5
  export declare class StreamManager extends Root {
5
6
  private param;
6
7
  private readonly STAR_WILDCARD;
@@ -10,8 +11,11 @@ export declare class StreamManager extends Root {
10
11
  private readonly defaultStreamOption;
11
12
  private jsm?;
12
13
  constructor(param: StreamManagerParam);
14
+ static isPullConsumerOptions(setting?: GetListenerOptions | GetBatchListenerOptions): setting is GetBatchListenerOptions;
15
+ static isStreamFetcher(consumer?: JetStreamSubscription | StreamFetcher | Subscription): consumer is StreamFetcher;
13
16
  createStreams(): Promise<void>;
14
17
  createConsumer(serviceNameFrom: string, eventName: string, setting?: GetListenerOptions): Promise<JetStreamSubscription>;
18
+ createConsumer(serviceNameFrom: string, eventName: string, setting?: GetBatchListenerOptions): Promise<StreamFetcher>;
15
19
  private getStreamName;
16
20
  private isNotFoundStreamError;
17
21
  private buildPrefixForStreamName;
@@ -1,9 +1,14 @@
1
- import { JetStreamClient, JetStreamManager, JetStreamOptions, Msg, NatsConnection, PublishOptions, RequestOptions, ServerInfo, Stats, Status, Subscription, SubscriptionOptions } from 'nats';
1
+ import { JetStreamClient, JetStreamManager, JetStreamOptions, Msg, NatsConnection, Payload, PublishOptions, RequestManyOptions, RequestOptions, ServerInfo, ServicesAPI, Stats, Status, Subscription, SubscriptionOptions } from 'nats';
2
2
  interface Union {
3
3
  isUnion?: boolean;
4
4
  }
5
5
  export type Broker = NatsConnection & Union;
6
6
  export declare class UnionBroker implements Broker {
7
+ publishMessage(msg: Msg): void;
8
+ respondMessage(msg: Msg): boolean;
9
+ requestMany(subject: string, payload?: Payload | undefined, opts?: Partial<RequestManyOptions> | undefined): Promise<AsyncIterable<Msg>>;
10
+ services: ServicesAPI;
11
+ reconnect(): Promise<void>;
7
12
  info?: ServerInfo;
8
13
  isUnion: boolean;
9
14
  private DEFAULT_TIMEOUT;
@@ -1,12 +1,15 @@
1
1
  /// <reference types="node" />
2
- import { ConsumerOpts, ConsumerOptsBuilder, JetStreamClient, JetStreamPublishOptions, JetStreamPullSubscription, JetStreamSubscription, JsMsg, PubAck, PullOptions } from 'nats';
3
- import { QueuedIterator } from 'nats/lib/nats-base-client/queued_iterator';
4
- import { Views } from 'nats/lib/nats-base-client/types';
2
+ import { ConsumerOpts, ConsumerOptsBuilder, Consumers, JetStreamClient, JetStreamManager, JetStreamOptions, JetStreamPublishOptions, JetStreamPullSubscription, JetStreamSubscription, JsMsg, PubAck, PullOptions, QueuedIterator, Streams, Views } from 'nats';
5
3
  import { EventEmitter } from 'stream';
6
4
  export declare class JetStreamClientBlank implements JetStreamClient {
7
5
  private emitter;
8
6
  views: Views;
9
7
  constructor(emitter: EventEmitter);
8
+ apiPrefix: string;
9
+ consumers: Consumers;
10
+ streams: Streams;
11
+ jetstreamManager(checkAPI?: boolean | undefined): Promise<JetStreamManager>;
12
+ getOptions(): JetStreamOptions;
10
13
  publish(subj: string, data?: Uint8Array, options?: Partial<JetStreamPublishOptions>): Promise<PubAck>;
11
14
  pull(stream: string, durable: string, expires?: number): Promise<JsMsg>;
12
15
  fetch(stream: string, durable: string, opts?: Partial<PullOptions>): QueuedIterator<JsMsg>;
@@ -1,7 +1,8 @@
1
- import { JetStreamAccountStats, JetStreamManager } from 'nats';
2
- import { ConsumerAPI, Advisory } from 'nats/lib/nats-base-client/types';
1
+ import { Advisory, ConsumerAPI, JetStreamAccountStats, JetStreamClient, JetStreamManager, JetStreamOptions } from 'nats';
3
2
  import { StreamApiBlank } from './StreamApi';
4
3
  export declare class JetStreamManagerBlank implements JetStreamManager {
4
+ getOptions(): JetStreamOptions;
5
+ jetstream(): JetStreamClient;
5
6
  consumers: ConsumerAPI;
6
7
  streams: StreamApiBlank;
7
8
  getAccountInfo(): Promise<JetStreamAccountStats>;
@@ -1,5 +1,9 @@
1
- import { Lister, MsgRequest, PurgeOpts, PurgeResponse, StoredMsg, StreamAPI, StreamConfig, StreamInfo, StreamInfoRequestOptions, StreamUpdateConfig } from 'nats/lib/nats-base-client/types';
1
+ import { StreamAPI, StreamInfoRequestOptions, StreamInfo, StreamConfig, StreamUpdateConfig, PurgeOpts, PurgeResponse, Lister, MsgRequest, StoredMsg, KvStatus, ObjectStoreStatus, Stream } from 'nats';
2
2
  export declare class StreamApiBlank implements StreamAPI {
3
+ listKvs(): Lister<KvStatus>;
4
+ listObjectStores(): Lister<ObjectStoreStatus>;
5
+ names(subject?: string | undefined): Lister<string>;
6
+ get(name: string): Promise<Stream>;
3
7
  info(stream: string, opts?: Partial<StreamInfoRequestOptions>): Promise<StreamInfo>;
4
8
  add(cfg: Partial<StreamConfig>): Promise<StreamInfo>;
5
9
  update(name: string, cfg: Partial<StreamUpdateConfig>): Promise<StreamInfo>;
@@ -1,6 +1,5 @@
1
1
  /// <reference types="node" />
2
- import { Msg, NatsError, Subscription } from 'nats';
3
- import { Closed, ConsumerInfoable, Destroyable } from 'nats/lib/nats-base-client/types';
2
+ import { Closed, ConsumerInfoable, Destroyable, Msg, NatsError, Subscription } from 'nats';
4
3
  import { PassThrough } from 'node:stream';
5
4
  export declare class UnionSubscription extends PassThrough implements Subscription, Destroyable, Closed, ConsumerInfoable {
6
5
  closed: Promise<void>;
@@ -71,6 +71,11 @@ export interface GetListenerOptions {
71
71
  maxPending?: number;
72
72
  maxAckWaiting?: number;
73
73
  }
74
+ export interface GetBatchListenerOptions extends GetListenerOptions {
75
+ batch: true;
76
+ maxPullRequestBatch?: number;
77
+ maxPullRequestExpires?: number;
78
+ }
74
79
  export interface StreamManagerParam {
75
80
  serviceName: string;
76
81
  options: StreamOptions;
@@ -129,6 +134,10 @@ export interface Listener<E extends Emitter> {
129
134
  on<A extends keyof E>(action: A, handler: E[A]): void;
130
135
  off<A extends keyof E>(action: A, handler: E[A]): void;
131
136
  }
137
+ export interface ListenerBatch<E extends Emitter> {
138
+ on<A extends keyof E>(action: A, handler: (params: Array<Parameters<E[A]>[0]>) => void): void;
139
+ off<A extends keyof E>(action: A, handler: (params: Array<Parameters<E[A]>[0]>) => void): void;
140
+ }
132
141
  export interface HttpSettings {
133
142
  ip?: string;
134
143
  port?: number;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lad-tech/nsc-toolkit",
3
- "version": "1.21.0",
3
+ "version": "1.22.1",
4
4
  "description": "Toolkit for create microservices around NATS",
5
5
  "main": "dist/index.js",
6
6
  "types": "./dist/types/index.d.ts",
@@ -41,9 +41,12 @@
41
41
  "@opentelemetry/sdk-trace-base": "^1.3.1",
42
42
  "@opentelemetry/semantic-conventions": "^1.3.1",
43
43
  "ajv": "^8.11.0",
44
- "nats": "^2.6.1",
44
+ "nats": "^2.28.2",
45
45
  "reflect-metadata": "^0.1.13"
46
46
  },
47
+ "peerDependencies": {
48
+ "nats": "^2.15.0"
49
+ },
47
50
  "jest": {
48
51
  "preset": "ts-jest",
49
52
  "testEnvironment": "node",