@samuelaj1/eazisend-service-kit 1.0.6 → 1.0.7

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/dist/index.cjs CHANGED
@@ -33,6 +33,7 @@ __export(index_exports, {
33
33
  LogLevelTypes: () => LogLevelTypes,
34
34
  elasticSearchRepo: () => elasticSearchRepo,
35
35
  loggerRepo: () => loggerRepo,
36
+ rabbitmqRepo: () => rabbitmqRepo,
36
37
  registerErrorMiddleware: () => registerErrorMiddleware,
37
38
  registerSecurityMiddleware: () => registerSecurityMiddleware,
38
39
  registerStandardMiddleware: () => registerStandardMiddleware,
@@ -66,10 +67,13 @@ var Config = class {
66
67
  API_GATEWAY_URL;
67
68
  GATEWAY_TOKEN;
68
69
  ELASTIC_SEARCH_NODE_URL;
70
+ RABBITMQ_URL;
69
71
  PORT;
70
72
  constructor() {
71
73
  this.API_GATEWAY_URL = process.env.API_GATEWAY_URL || "";
72
74
  this.GATEWAY_TOKEN = process.env.GATEWAY_TOKEN || "";
75
+ this.ELASTIC_SEARCH_NODE_URL = process.env.ELASTIC_SEARCH_NODE_URL || "";
76
+ this.RABBITMQ_URL = process.env.RABBITMQ_URL || "";
73
77
  this.ELASTIC_SEARCH_NODE_URL = process.env.ELASTIC_SEARCH_NODE_URL?.trim() || "";
74
78
  this.PORT = process.env.PORT || "";
75
79
  }
@@ -197,6 +201,202 @@ var ElasticsearchRepo = class {
197
201
  };
198
202
  var elasticSearchRepo = new ElasticsearchRepo();
199
203
 
204
+ // src/repositories/rabbitmq.repo.ts
205
+ var import_amqplib = __toESM(require("amqplib"), 1);
206
+ var RabbitmqRepo = class {
207
+ queueChannel;
208
+ pendingConnection;
209
+ /**
210
+ * Returns the shared channel, creating a connection when necessary.
211
+ *
212
+ * @example
213
+ * ```ts
214
+ * const channel = await rabbitmqRepo.getQueueConnection();
215
+ * ```
216
+ */
217
+ async getQueueConnection() {
218
+ if (this.queueChannel) {
219
+ return this.queueChannel;
220
+ }
221
+ if (this.pendingConnection) {
222
+ return this.pendingConnection;
223
+ }
224
+ this.pendingConnection = this.createQueueConnection();
225
+ try {
226
+ return await this.pendingConnection;
227
+ } finally {
228
+ this.pendingConnection = void 0;
229
+ }
230
+ }
231
+ async createQueueConnection() {
232
+ let connection;
233
+ try {
234
+ connection = await import_amqplib.default.connect(libConfig.RABBITMQ_URL);
235
+ const channel = await connection.createChannel();
236
+ const clearChannel = () => {
237
+ if (this.queueChannel === channel) {
238
+ this.queueChannel = void 0;
239
+ }
240
+ };
241
+ channel.on("error", (error) => {
242
+ clearChannel();
243
+ console.error("RabbitmqRepo channel error:", error);
244
+ });
245
+ channel.once("close", clearChannel);
246
+ connection.on("error", (error) => {
247
+ clearChannel();
248
+ console.error("RabbitmqRepo connection error:", error);
249
+ });
250
+ connection.once("close", clearChannel);
251
+ console.log("RabbitmqRepo connected to queue successfully...");
252
+ this.closeConnection(channel, connection);
253
+ this.queueChannel = channel;
254
+ return channel;
255
+ } catch (error) {
256
+ if (connection) {
257
+ await connection.close().catch((closeError) => {
258
+ console.error("RabbitmqRepo error closing failed connection:", closeError);
259
+ });
260
+ }
261
+ console.error("RabbitmqRepo error creating connection:", error);
262
+ return void 0;
263
+ }
264
+ }
265
+ /**
266
+ * Closes the channel and connection when the application shuts down.
267
+ */
268
+ closeConnection(channel, connection) {
269
+ let isClosing = false;
270
+ const close = async (signal) => {
271
+ if (isClosing) {
272
+ return;
273
+ }
274
+ isClosing = true;
275
+ try {
276
+ try {
277
+ await channel.close();
278
+ } finally {
279
+ await connection.close();
280
+ }
281
+ console.log(`RabbitmqRepo queue connection closed after ${signal}`);
282
+ } catch (error) {
283
+ console.error("RabbitmqRepo error closing connection:", error);
284
+ }
285
+ };
286
+ process.once("SIGINT", close);
287
+ process.once("SIGTERM", close);
288
+ connection.once("close", () => {
289
+ process.removeListener("SIGINT", close);
290
+ process.removeListener("SIGTERM", close);
291
+ });
292
+ }
293
+ /**
294
+ * Establishes the shared RabbitMQ connection during application startup.
295
+ *
296
+ * @example
297
+ * ```ts
298
+ * await rabbitmqRepo.establishQueueConnection();
299
+ * ```
300
+ */
301
+ async establishQueueConnection() {
302
+ const channel = await this.getQueueConnection();
303
+ if (!channel) {
304
+ throw new Error("No channel found.");
305
+ }
306
+ }
307
+ async connectQueueToExchange(channel, exchange, queueName, routingKey, exchangeType) {
308
+ await channel.assertExchange(exchange, exchangeType);
309
+ const q = await channel.assertQueue(queueName, { durable: true, autoDelete: false });
310
+ await channel.bindQueue(q.queue, exchange, routingKey);
311
+ return q;
312
+ }
313
+ /**
314
+ * Publishes a typed payload as JSON using the supplied exchange and routing key.
315
+ *
316
+ * @example
317
+ * ```ts
318
+ * await rabbitmqRepo.publishMessageToQueue<EmailPayload>({
319
+ * exchange: 'notifications',
320
+ * routingKey: 'email',
321
+ * message: { receiverEmail, username, verifyLink, resetLink },
322
+ * logMessage: 'Email notification published',
323
+ * });
324
+ * ```
325
+ */
326
+ async publishMessageToQueue(args) {
327
+ const serializedMessage = JSON.stringify(args.message);
328
+ if (serializedMessage === void 0) {
329
+ throw new Error("Message must be JSON serializable.");
330
+ }
331
+ const channel = await this.getQueueConnection();
332
+ const { exchange, routingKey, logMessage, exchangeType } = args;
333
+ if (!channel) {
334
+ throw new Error("No channel found.");
335
+ }
336
+ await channel.assertExchange(exchange, exchangeType || "direct");
337
+ channel.publish(exchange, routingKey, Buffer.from(serializedMessage));
338
+ if (logMessage) {
339
+ console.log(logMessage);
340
+ }
341
+ }
342
+ /**
343
+ * Consumes JSON messages and acknowledges them after the callback succeeds.
344
+ * Prefetch defaults to 10 when omitted.
345
+ *
346
+ * @example
347
+ * ```ts
348
+ * await rabbitmqRepo.consumeMessagesFromQueue<EmailPayload>({
349
+ * exchange: 'notifications',
350
+ * queueName: 'email-queue',
351
+ * routingKey: 'email',
352
+ * prefetch: 5,
353
+ * callback: async ({ receiverEmail, username, verifyLink, resetLink }) => {
354
+ * // Process the email.
355
+ * },
356
+ * });
357
+ * ```
358
+ */
359
+ async consumeMessagesFromQueue(args) {
360
+ const { exchange, queueName, routingKey, callback } = args;
361
+ const prefetch = args.prefetch ?? 10;
362
+ if (!Number.isInteger(prefetch) || prefetch < 1 || prefetch > 65535) {
363
+ throw new Error("Prefetch must be an integer between 1 and 65535.");
364
+ }
365
+ const channel = args.channel ?? await this.getQueueConnection();
366
+ if (!channel) {
367
+ throw new Error("No channel found.");
368
+ }
369
+ const q = await this.connectQueueToExchange(channel, exchange, queueName, routingKey, args.exchangeType ?? "direct");
370
+ await channel.prefetch(prefetch, false);
371
+ await channel.consume(q.queue, async (message) => {
372
+ if (!message) {
373
+ return;
374
+ }
375
+ try {
376
+ let payload;
377
+ try {
378
+ payload = JSON.parse(message.content.toString());
379
+ } catch (error) {
380
+ console.error("RabbitmqRepo invalid JSON message:", error);
381
+ channel.nack(message, false, false);
382
+ return;
383
+ }
384
+ try {
385
+ await callback(payload);
386
+ } catch (error) {
387
+ console.error("RabbitmqRepo message callback failed:", error);
388
+ channel.nack(message, false, true);
389
+ return;
390
+ }
391
+ channel.ack(message);
392
+ } catch (error) {
393
+ console.error("RabbitmqRepo error settling message:", error);
394
+ }
395
+ });
396
+ }
397
+ };
398
+ var rabbitmqRepo = new RabbitmqRepo();
399
+
200
400
  // src/middlewares/gateway.middleware.ts
201
401
  var import_jsonwebtoken = __toESM(require("jsonwebtoken"), 1);
202
402
  function verifyGatewayRequest(serviceId) {
@@ -233,6 +433,7 @@ function registerErrorMiddleware(app) {
233
433
  LogLevelTypes,
234
434
  elasticSearchRepo,
235
435
  loggerRepo,
436
+ rabbitmqRepo,
236
437
  registerErrorMiddleware,
237
438
  registerSecurityMiddleware,
238
439
  registerStandardMiddleware,
package/dist/index.d.cts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { Express, Request, Response, NextFunction, Application } from 'express';
2
2
  import { LogEntry } from 'winston';
3
+ import { Channel } from 'amqplib';
3
4
 
4
5
  declare function registerStandardMiddleware(app: Express): void;
5
6
 
@@ -27,7 +28,7 @@ declare function runServer(app: Express): void;
27
28
 
28
29
  /** Configured Elasticsearch cluster */
29
30
  declare class ElasticsearchRepo {
30
- private elasticSearchClient?;
31
+ private readonly elasticSearchClient?;
31
32
  /** Creates an Elasticsearch client using the configured cluster URL. */
32
33
  constructor();
33
34
  /** Elasticsearch connection is established. */
@@ -37,8 +38,84 @@ declare class ElasticsearchRepo {
37
38
  }
38
39
  declare const elasticSearchRepo: ElasticsearchRepo;
39
40
 
41
+ declare class RabbitmqRepo {
42
+ private queueChannel;
43
+ private pendingConnection;
44
+ /**
45
+ * Returns the shared channel, creating a connection when necessary.
46
+ *
47
+ * @example
48
+ * ```ts
49
+ * const channel = await rabbitmqRepo.getQueueConnection();
50
+ * ```
51
+ */
52
+ getQueueConnection(): Promise<Channel | undefined>;
53
+ private createQueueConnection;
54
+ /**
55
+ * Closes the channel and connection when the application shuts down.
56
+ */
57
+ private closeConnection;
58
+ /**
59
+ * Establishes the shared RabbitMQ connection during application startup.
60
+ *
61
+ * @example
62
+ * ```ts
63
+ * await rabbitmqRepo.establishQueueConnection();
64
+ * ```
65
+ */
66
+ establishQueueConnection(): Promise<void>;
67
+ private connectQueueToExchange;
68
+ /**
69
+ * Publishes a typed payload as JSON using the supplied exchange and routing key.
70
+ *
71
+ * @example
72
+ * ```ts
73
+ * await rabbitmqRepo.publishMessageToQueue<EmailPayload>({
74
+ * exchange: 'notifications',
75
+ * routingKey: 'email',
76
+ * message: { receiverEmail, username, verifyLink, resetLink },
77
+ * logMessage: 'Email notification published',
78
+ * });
79
+ * ```
80
+ */
81
+ publishMessageToQueue<T>(args: {
82
+ exchange: string;
83
+ routingKey: string;
84
+ message: T;
85
+ logMessage?: string;
86
+ exchangeType?: 'direct' | 'fanout';
87
+ }): Promise<void>;
88
+ /**
89
+ * Consumes JSON messages and acknowledges them after the callback succeeds.
90
+ * Prefetch defaults to 10 when omitted.
91
+ *
92
+ * @example
93
+ * ```ts
94
+ * await rabbitmqRepo.consumeMessagesFromQueue<EmailPayload>({
95
+ * exchange: 'notifications',
96
+ * queueName: 'email-queue',
97
+ * routingKey: 'email',
98
+ * prefetch: 5,
99
+ * callback: async ({ receiverEmail, username, verifyLink, resetLink }) => {
100
+ * // Process the email.
101
+ * },
102
+ * });
103
+ * ```
104
+ */
105
+ consumeMessagesFromQueue<T = unknown>(args: {
106
+ exchange: string;
107
+ queueName: string;
108
+ routingKey: string;
109
+ callback: (payload: T) => void | Promise<void>;
110
+ channel?: Channel;
111
+ exchangeType?: 'direct' | 'fanout';
112
+ prefetch?: number;
113
+ }): Promise<void>;
114
+ }
115
+ declare const rabbitmqRepo: RabbitmqRepo;
116
+
40
117
  declare function verifyGatewayRequest(serviceId: string): (req: Request, _res: Response, next: NextFunction) => void;
41
118
 
42
119
  declare function registerErrorMiddleware(app: Application): (err: Error, _req: Request, res: Response, _next: NextFunction) => void;
43
120
 
44
- export { LogLevelTypes, elasticSearchRepo, loggerRepo, registerErrorMiddleware, registerSecurityMiddleware, registerStandardMiddleware, runServer, verifyGatewayRequest };
121
+ export { LogLevelTypes, elasticSearchRepo, loggerRepo, rabbitmqRepo, registerErrorMiddleware, registerSecurityMiddleware, registerStandardMiddleware, runServer, verifyGatewayRequest };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { Express, Request, Response, NextFunction, Application } from 'express';
2
2
  import { LogEntry } from 'winston';
3
+ import { Channel } from 'amqplib';
3
4
 
4
5
  declare function registerStandardMiddleware(app: Express): void;
5
6
 
@@ -27,7 +28,7 @@ declare function runServer(app: Express): void;
27
28
 
28
29
  /** Configured Elasticsearch cluster */
29
30
  declare class ElasticsearchRepo {
30
- private elasticSearchClient?;
31
+ private readonly elasticSearchClient?;
31
32
  /** Creates an Elasticsearch client using the configured cluster URL. */
32
33
  constructor();
33
34
  /** Elasticsearch connection is established. */
@@ -37,8 +38,84 @@ declare class ElasticsearchRepo {
37
38
  }
38
39
  declare const elasticSearchRepo: ElasticsearchRepo;
39
40
 
41
+ declare class RabbitmqRepo {
42
+ private queueChannel;
43
+ private pendingConnection;
44
+ /**
45
+ * Returns the shared channel, creating a connection when necessary.
46
+ *
47
+ * @example
48
+ * ```ts
49
+ * const channel = await rabbitmqRepo.getQueueConnection();
50
+ * ```
51
+ */
52
+ getQueueConnection(): Promise<Channel | undefined>;
53
+ private createQueueConnection;
54
+ /**
55
+ * Closes the channel and connection when the application shuts down.
56
+ */
57
+ private closeConnection;
58
+ /**
59
+ * Establishes the shared RabbitMQ connection during application startup.
60
+ *
61
+ * @example
62
+ * ```ts
63
+ * await rabbitmqRepo.establishQueueConnection();
64
+ * ```
65
+ */
66
+ establishQueueConnection(): Promise<void>;
67
+ private connectQueueToExchange;
68
+ /**
69
+ * Publishes a typed payload as JSON using the supplied exchange and routing key.
70
+ *
71
+ * @example
72
+ * ```ts
73
+ * await rabbitmqRepo.publishMessageToQueue<EmailPayload>({
74
+ * exchange: 'notifications',
75
+ * routingKey: 'email',
76
+ * message: { receiverEmail, username, verifyLink, resetLink },
77
+ * logMessage: 'Email notification published',
78
+ * });
79
+ * ```
80
+ */
81
+ publishMessageToQueue<T>(args: {
82
+ exchange: string;
83
+ routingKey: string;
84
+ message: T;
85
+ logMessage?: string;
86
+ exchangeType?: 'direct' | 'fanout';
87
+ }): Promise<void>;
88
+ /**
89
+ * Consumes JSON messages and acknowledges them after the callback succeeds.
90
+ * Prefetch defaults to 10 when omitted.
91
+ *
92
+ * @example
93
+ * ```ts
94
+ * await rabbitmqRepo.consumeMessagesFromQueue<EmailPayload>({
95
+ * exchange: 'notifications',
96
+ * queueName: 'email-queue',
97
+ * routingKey: 'email',
98
+ * prefetch: 5,
99
+ * callback: async ({ receiverEmail, username, verifyLink, resetLink }) => {
100
+ * // Process the email.
101
+ * },
102
+ * });
103
+ * ```
104
+ */
105
+ consumeMessagesFromQueue<T = unknown>(args: {
106
+ exchange: string;
107
+ queueName: string;
108
+ routingKey: string;
109
+ callback: (payload: T) => void | Promise<void>;
110
+ channel?: Channel;
111
+ exchangeType?: 'direct' | 'fanout';
112
+ prefetch?: number;
113
+ }): Promise<void>;
114
+ }
115
+ declare const rabbitmqRepo: RabbitmqRepo;
116
+
40
117
  declare function verifyGatewayRequest(serviceId: string): (req: Request, _res: Response, next: NextFunction) => void;
41
118
 
42
119
  declare function registerErrorMiddleware(app: Application): (err: Error, _req: Request, res: Response, _next: NextFunction) => void;
43
120
 
44
- export { LogLevelTypes, elasticSearchRepo, loggerRepo, registerErrorMiddleware, registerSecurityMiddleware, registerStandardMiddleware, runServer, verifyGatewayRequest };
121
+ export { LogLevelTypes, elasticSearchRepo, loggerRepo, rabbitmqRepo, registerErrorMiddleware, registerSecurityMiddleware, registerStandardMiddleware, runServer, verifyGatewayRequest };
package/dist/index.js CHANGED
@@ -19,10 +19,13 @@ var Config = class {
19
19
  API_GATEWAY_URL;
20
20
  GATEWAY_TOKEN;
21
21
  ELASTIC_SEARCH_NODE_URL;
22
+ RABBITMQ_URL;
22
23
  PORT;
23
24
  constructor() {
24
25
  this.API_GATEWAY_URL = process.env.API_GATEWAY_URL || "";
25
26
  this.GATEWAY_TOKEN = process.env.GATEWAY_TOKEN || "";
27
+ this.ELASTIC_SEARCH_NODE_URL = process.env.ELASTIC_SEARCH_NODE_URL || "";
28
+ this.RABBITMQ_URL = process.env.RABBITMQ_URL || "";
26
29
  this.ELASTIC_SEARCH_NODE_URL = process.env.ELASTIC_SEARCH_NODE_URL?.trim() || "";
27
30
  this.PORT = process.env.PORT || "";
28
31
  }
@@ -150,6 +153,202 @@ var ElasticsearchRepo = class {
150
153
  };
151
154
  var elasticSearchRepo = new ElasticsearchRepo();
152
155
 
156
+ // src/repositories/rabbitmq.repo.ts
157
+ import amqp from "amqplib";
158
+ var RabbitmqRepo = class {
159
+ queueChannel;
160
+ pendingConnection;
161
+ /**
162
+ * Returns the shared channel, creating a connection when necessary.
163
+ *
164
+ * @example
165
+ * ```ts
166
+ * const channel = await rabbitmqRepo.getQueueConnection();
167
+ * ```
168
+ */
169
+ async getQueueConnection() {
170
+ if (this.queueChannel) {
171
+ return this.queueChannel;
172
+ }
173
+ if (this.pendingConnection) {
174
+ return this.pendingConnection;
175
+ }
176
+ this.pendingConnection = this.createQueueConnection();
177
+ try {
178
+ return await this.pendingConnection;
179
+ } finally {
180
+ this.pendingConnection = void 0;
181
+ }
182
+ }
183
+ async createQueueConnection() {
184
+ let connection;
185
+ try {
186
+ connection = await amqp.connect(libConfig.RABBITMQ_URL);
187
+ const channel = await connection.createChannel();
188
+ const clearChannel = () => {
189
+ if (this.queueChannel === channel) {
190
+ this.queueChannel = void 0;
191
+ }
192
+ };
193
+ channel.on("error", (error) => {
194
+ clearChannel();
195
+ console.error("RabbitmqRepo channel error:", error);
196
+ });
197
+ channel.once("close", clearChannel);
198
+ connection.on("error", (error) => {
199
+ clearChannel();
200
+ console.error("RabbitmqRepo connection error:", error);
201
+ });
202
+ connection.once("close", clearChannel);
203
+ console.log("RabbitmqRepo connected to queue successfully...");
204
+ this.closeConnection(channel, connection);
205
+ this.queueChannel = channel;
206
+ return channel;
207
+ } catch (error) {
208
+ if (connection) {
209
+ await connection.close().catch((closeError) => {
210
+ console.error("RabbitmqRepo error closing failed connection:", closeError);
211
+ });
212
+ }
213
+ console.error("RabbitmqRepo error creating connection:", error);
214
+ return void 0;
215
+ }
216
+ }
217
+ /**
218
+ * Closes the channel and connection when the application shuts down.
219
+ */
220
+ closeConnection(channel, connection) {
221
+ let isClosing = false;
222
+ const close = async (signal) => {
223
+ if (isClosing) {
224
+ return;
225
+ }
226
+ isClosing = true;
227
+ try {
228
+ try {
229
+ await channel.close();
230
+ } finally {
231
+ await connection.close();
232
+ }
233
+ console.log(`RabbitmqRepo queue connection closed after ${signal}`);
234
+ } catch (error) {
235
+ console.error("RabbitmqRepo error closing connection:", error);
236
+ }
237
+ };
238
+ process.once("SIGINT", close);
239
+ process.once("SIGTERM", close);
240
+ connection.once("close", () => {
241
+ process.removeListener("SIGINT", close);
242
+ process.removeListener("SIGTERM", close);
243
+ });
244
+ }
245
+ /**
246
+ * Establishes the shared RabbitMQ connection during application startup.
247
+ *
248
+ * @example
249
+ * ```ts
250
+ * await rabbitmqRepo.establishQueueConnection();
251
+ * ```
252
+ */
253
+ async establishQueueConnection() {
254
+ const channel = await this.getQueueConnection();
255
+ if (!channel) {
256
+ throw new Error("No channel found.");
257
+ }
258
+ }
259
+ async connectQueueToExchange(channel, exchange, queueName, routingKey, exchangeType) {
260
+ await channel.assertExchange(exchange, exchangeType);
261
+ const q = await channel.assertQueue(queueName, { durable: true, autoDelete: false });
262
+ await channel.bindQueue(q.queue, exchange, routingKey);
263
+ return q;
264
+ }
265
+ /**
266
+ * Publishes a typed payload as JSON using the supplied exchange and routing key.
267
+ *
268
+ * @example
269
+ * ```ts
270
+ * await rabbitmqRepo.publishMessageToQueue<EmailPayload>({
271
+ * exchange: 'notifications',
272
+ * routingKey: 'email',
273
+ * message: { receiverEmail, username, verifyLink, resetLink },
274
+ * logMessage: 'Email notification published',
275
+ * });
276
+ * ```
277
+ */
278
+ async publishMessageToQueue(args) {
279
+ const serializedMessage = JSON.stringify(args.message);
280
+ if (serializedMessage === void 0) {
281
+ throw new Error("Message must be JSON serializable.");
282
+ }
283
+ const channel = await this.getQueueConnection();
284
+ const { exchange, routingKey, logMessage, exchangeType } = args;
285
+ if (!channel) {
286
+ throw new Error("No channel found.");
287
+ }
288
+ await channel.assertExchange(exchange, exchangeType || "direct");
289
+ channel.publish(exchange, routingKey, Buffer.from(serializedMessage));
290
+ if (logMessage) {
291
+ console.log(logMessage);
292
+ }
293
+ }
294
+ /**
295
+ * Consumes JSON messages and acknowledges them after the callback succeeds.
296
+ * Prefetch defaults to 10 when omitted.
297
+ *
298
+ * @example
299
+ * ```ts
300
+ * await rabbitmqRepo.consumeMessagesFromQueue<EmailPayload>({
301
+ * exchange: 'notifications',
302
+ * queueName: 'email-queue',
303
+ * routingKey: 'email',
304
+ * prefetch: 5,
305
+ * callback: async ({ receiverEmail, username, verifyLink, resetLink }) => {
306
+ * // Process the email.
307
+ * },
308
+ * });
309
+ * ```
310
+ */
311
+ async consumeMessagesFromQueue(args) {
312
+ const { exchange, queueName, routingKey, callback } = args;
313
+ const prefetch = args.prefetch ?? 10;
314
+ if (!Number.isInteger(prefetch) || prefetch < 1 || prefetch > 65535) {
315
+ throw new Error("Prefetch must be an integer between 1 and 65535.");
316
+ }
317
+ const channel = args.channel ?? await this.getQueueConnection();
318
+ if (!channel) {
319
+ throw new Error("No channel found.");
320
+ }
321
+ const q = await this.connectQueueToExchange(channel, exchange, queueName, routingKey, args.exchangeType ?? "direct");
322
+ await channel.prefetch(prefetch, false);
323
+ await channel.consume(q.queue, async (message) => {
324
+ if (!message) {
325
+ return;
326
+ }
327
+ try {
328
+ let payload;
329
+ try {
330
+ payload = JSON.parse(message.content.toString());
331
+ } catch (error) {
332
+ console.error("RabbitmqRepo invalid JSON message:", error);
333
+ channel.nack(message, false, false);
334
+ return;
335
+ }
336
+ try {
337
+ await callback(payload);
338
+ } catch (error) {
339
+ console.error("RabbitmqRepo message callback failed:", error);
340
+ channel.nack(message, false, true);
341
+ return;
342
+ }
343
+ channel.ack(message);
344
+ } catch (error) {
345
+ console.error("RabbitmqRepo error settling message:", error);
346
+ }
347
+ });
348
+ }
349
+ };
350
+ var rabbitmqRepo = new RabbitmqRepo();
351
+
153
352
  // src/middlewares/gateway.middleware.ts
154
353
  import jwt from "jsonwebtoken";
155
354
  function verifyGatewayRequest(serviceId) {
@@ -185,6 +384,7 @@ export {
185
384
  LogLevelTypes,
186
385
  elasticSearchRepo,
187
386
  loggerRepo,
387
+ rabbitmqRepo,
188
388
  registerErrorMiddleware,
189
389
  registerSecurityMiddleware,
190
390
  registerStandardMiddleware,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@samuelaj1/eazisend-service-kit",
3
- "version": "1.0.6",
3
+ "version": "1.0.7",
4
4
  "scripts": {
5
5
  "build": "tsup"
6
6
  },
@@ -29,25 +29,27 @@
29
29
  "license": "MIT",
30
30
  "type": "module",
31
31
  "devDependencies": {
32
+ "@types/amqplib": "^0.10.8",
33
+ "@types/compression": "^1.8.1",
34
+ "@types/cors": "^2.8.19",
32
35
  "@types/express": "^5.0.6",
36
+ "@types/hpp": "^0.2.7",
33
37
  "@types/jsonwebtoken": "^9.0.10",
34
38
  "tsup": "^8.5.1",
35
- "typescript": "^6.0.3",
36
- "@types/cors": "^2.8.19",
37
- "@types/hpp": "^0.2.7",
38
- "@types/compression": "^1.8.1"
39
+ "typescript": "^6.0.3"
39
40
  },
40
41
  "dependencies": {
41
42
  "@elastic/elasticsearch": "^9.4.2",
43
+ "amqplib": "^2.2.0",
44
+ "compression": "^1.8.1",
45
+ "cors": "^2.8.6",
42
46
  "dotenv": "^17.4.2",
43
47
  "express": "^5.2.1",
48
+ "helmet": "^8.3.0",
49
+ "hpp": "^0.2.3",
44
50
  "http-status-codes": "^2.3.0",
45
51
  "jsonwebtoken": "^9.0.3",
46
52
  "winston": "^3.19.0",
47
- "winston-elasticsearch": "^0.19.0",
48
- "helmet": "^8.3.0",
49
- "hpp": "^0.2.3",
50
- "cors": "^2.8.6",
51
- "compression": "^1.8.1"
53
+ "winston-elasticsearch": "^0.19.0"
52
54
  }
53
55
  }