@bgaldino/nestjs-rabbitmq 1.0.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.
@@ -0,0 +1,144 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RabbitMQConsumer = void 0;
4
+ const amqp_connection_manager_1 = require("./amqp-connection-manager");
5
+ class RabbitMQConsumer {
6
+ constructor(connection, options, publishChannelWrapper) {
7
+ var _a, _b;
8
+ this.connection = connection;
9
+ this.options = options;
10
+ this.delayExchange = `${this.options.delayExchangeName}.delay.exchange`;
11
+ this.publishChannel = publishChannelWrapper;
12
+ this.logType =
13
+ (_b = (_a = process.env.RABBITMQ_TRAFFIC_TYPE) !== null && _a !== void 0 ? _a : this.options.trafficInspection) !== null && _b !== void 0 ? _b : "none";
14
+ }
15
+ async createConsumers() {
16
+ var _a, _b, _c, _d, _e, _f;
17
+ for (const consumerEntry of (_b = (_a = this.options) === null || _a === void 0 ? void 0 : _a.consumerChannels) !== null && _b !== void 0 ? _b : []) {
18
+ const consumer = consumerEntry.options;
19
+ const exchangeBindName = consumer.exchangeName.endsWith((_d = (_c = consumer.suffixOptions) === null || _c === void 0 ? void 0 : _c.exchangeSuffix) !== null && _d !== void 0 ? _d : ".exchange")
20
+ ? consumer.exchangeName
21
+ : `${consumer.exchangeName}${(_f = (_e = consumer.suffixOptions) === null || _e === void 0 ? void 0 : _e.exchangeSuffix) !== null && _f !== void 0 ? _f : ".exchange"}`;
22
+ this.connection.createChannel({
23
+ confirm: true,
24
+ name: consumer.queue,
25
+ setup: (channel) => {
26
+ var _a, _b, _c, _d, _e;
27
+ return Promise.all([
28
+ channel.prefetch((_a = consumer.prefetch) !== null && _a !== void 0 ? _a : 10),
29
+ channel.assertQueue(consumer.queue, {
30
+ durable: (_b = consumer.durable) !== null && _b !== void 0 ? _b : true,
31
+ autoDelete: (_c = consumer.autoDelete) !== null && _c !== void 0 ? _c : false,
32
+ deadLetterRoutingKey: `${consumer.queue}${(_e = (_d = consumer.suffixOptions) === null || _d === void 0 ? void 0 : _d.dlqSuffix) !== null && _e !== void 0 ? _e : ".dlq"}`,
33
+ deadLetterExchange: "",
34
+ }),
35
+ channel.bindQueue(consumer.queue, exchangeBindName, consumer.routingKey),
36
+ this.attachRetryAndDLQ(channel, consumer),
37
+ channel.consume(consumer.queue, async (message) => {
38
+ await this.processConsumerMessage(message, channel, consumer, consumerEntry.messageHandler);
39
+ }),
40
+ ]);
41
+ },
42
+ });
43
+ }
44
+ amqp_connection_manager_1.AMQPConnectionManager.isConsumersLoaded = true;
45
+ }
46
+ async processConsumerMessage(message, channel, consumer, callback) {
47
+ var _a;
48
+ let hasErrors = null;
49
+ try {
50
+ await callback(JSON.parse(message.content.toString("utf8")), {
51
+ message,
52
+ channel,
53
+ queue: consumer.queue,
54
+ });
55
+ if (consumer.autoAck === undefined || consumer.autoAck) {
56
+ channel.ack(message);
57
+ }
58
+ }
59
+ catch (e) {
60
+ hasErrors = e;
61
+ await this.processRetry(consumer, message, channel);
62
+ }
63
+ finally {
64
+ this.inspectConsumer({
65
+ binding: {
66
+ queue: consumer.queue,
67
+ routingKey: (_a = message.fields.routingKey) !== null && _a !== void 0 ? _a : consumer.routingKey,
68
+ exchange: consumer.exchangeName,
69
+ },
70
+ consumeMessage: message,
71
+ error: hasErrors,
72
+ });
73
+ }
74
+ }
75
+ async attachRetryAndDLQ(channel, consumer) {
76
+ var _a, _b, _c;
77
+ const deadletterQueue = `${consumer.queue}${(_b = (_a = consumer.suffixOptions) === null || _a === void 0 ? void 0 : _a.dlqSuffix) !== null && _b !== void 0 ? _b : ".dlq"}`;
78
+ await channel.assertQueue(deadletterQueue, { durable: true });
79
+ if (((_c = consumer === null || consumer === void 0 ? void 0 : consumer.retryStrategy) === null || _c === void 0 ? void 0 : _c.enabled) == false) {
80
+ await channel.unbindQueue(consumer.queue, this.delayExchange, consumer.queue);
81
+ }
82
+ else {
83
+ await channel.assertExchange(this.delayExchange, "x-delayed-message", {
84
+ durable: true,
85
+ arguments: { "x-delayed-type": "direct" },
86
+ });
87
+ await channel.bindQueue(consumer.queue, this.delayExchange, consumer.queue);
88
+ }
89
+ }
90
+ async processRetry(consumer, message, channel) {
91
+ var _a, _b, _c, _d, _e, _f, _g, _h;
92
+ if (consumer.retryStrategy === undefined ||
93
+ consumer.retryStrategy.enabled === undefined ||
94
+ (consumer === null || consumer === void 0 ? void 0 : consumer.retryStrategy.enabled)) {
95
+ const retryCount = (_c = (_b = (_a = message.properties) === null || _a === void 0 ? void 0 : _a.headers) === null || _b === void 0 ? void 0 : _b["retriesCount"]) !== null && _c !== void 0 ? _c : 1;
96
+ const maxRetry = (_e = (_d = consumer === null || consumer === void 0 ? void 0 : consumer.retryStrategy) === null || _d === void 0 ? void 0 : _d.maxAttempts) !== null && _e !== void 0 ? _e : 5;
97
+ if (retryCount <= maxRetry) {
98
+ const retryDelay = (_h = (_g = (_f = consumer === null || consumer === void 0 ? void 0 : consumer.retryStrategy) === null || _f === void 0 ? void 0 : _f.delay) === null || _g === void 0 ? void 0 : _g.call(_f, retryCount)) !== null && _h !== void 0 ? _h : 5000;
99
+ try {
100
+ const isPublished = await this.publishChannel.publish(this.delayExchange, consumer.queue, JSON.stringify(JSON.parse(message.content.toString("utf8"))), {
101
+ headers: Object.assign(Object.assign({}, message.properties.headers), { retriesCount: retryCount + 1, "x-delay": retryDelay }),
102
+ });
103
+ if (isPublished) {
104
+ channel.ack(message);
105
+ return;
106
+ }
107
+ }
108
+ catch (e) {
109
+ console.log(JSON.stringify({ message: "could_not_retry", error: e }));
110
+ channel.nack(message);
111
+ }
112
+ }
113
+ }
114
+ channel.nack(message, false, false);
115
+ }
116
+ inspectConsumer(args) {
117
+ var _a, _b, _c;
118
+ if (!["consumer", "all"].includes(this.logType) && (args === null || args === void 0 ? void 0 : args.error) == undefined)
119
+ return;
120
+ const { binding, consumeMessage, data, error } = args;
121
+ const { exchange, routingKey, queue } = binding;
122
+ const { content, fields, properties } = consumeMessage;
123
+ const message = `[AMQP] [CONSUMER] [${exchange}] [${routingKey}] [${queue}]`;
124
+ const logLevel = error ? "error" : "info";
125
+ const logData = {
126
+ logLevel,
127
+ correlationId: (_b = (_a = args === null || args === void 0 ? void 0 : args.consumeMessage) === null || _a === void 0 ? void 0 : _a.properties) === null || _b === void 0 ? void 0 : _b.correlationId,
128
+ binding,
129
+ title: message,
130
+ message: {
131
+ fields,
132
+ properties,
133
+ content: data !== null && data !== void 0 ? data : content.toString("utf8"),
134
+ },
135
+ error,
136
+ };
137
+ if (error)
138
+ Object.assign(logData, { error: (_c = error.message) !== null && _c !== void 0 ? _c : error.toString() });
139
+ console[logLevel](JSON.stringify(logData));
140
+ // this.logger[logLevel]({ message, amqp: logData });
141
+ }
142
+ }
143
+ exports.RabbitMQConsumer = RabbitMQConsumer;
144
+ //# sourceMappingURL=rabbitmq-consumers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rabbitmq-consumers.js","sourceRoot":"","sources":["../src/rabbitmq-consumers.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ import { OnApplicationBootstrap } from "@nestjs/common";
2
+ import { PublishOptions } from "./rabbitmq.types";
3
+ export declare class RabbitMQService implements OnApplicationBootstrap {
4
+ private logger;
5
+ private connectionBlocked;
6
+ onApplicationBootstrap(): Promise<void>;
7
+ /**
8
+ * Check status of the main conenection to the broker.
9
+ * @returns {number} 1 - Online | 0 - Offline
10
+ */
11
+ checkHealth(): number;
12
+ /**
13
+ * Publishes a message to the broker. Every published message needs its exchange and routingKey to be properly routed
14
+ * @param {string} exchangeName - Name of the exchange
15
+ * @param {string} routingKey - Publish routing key
16
+ * @param {T} the message that will be published to RabbitMQ. All messages will be transformed to JSON.
17
+ * @param {PublishOptions} options - Any custom options that you want to send with the message such as headers or properties
18
+ * @returns {Promise<boolean>} Returns a promise of confirmation.
19
+ * If **TRUE** it means that the message arrived and was successfully delivered to an exchange or queue.
20
+ * If **FALSE** or an error is thrown, the message was not published !
21
+ */
22
+ publish<T = any>(exchangeName: string, routingKey: string, message: T, options?: PublishOptions): Promise<boolean>;
23
+ createConsumers(): Promise<void>;
24
+ private waitForBlockedConnection;
25
+ private inspectPublisher;
26
+ }
@@ -0,0 +1,115 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RabbitMQService = void 0;
4
+ const common_1 = require("@nestjs/common");
5
+ const node_crypto_1 = require("node:crypto");
6
+ const amqp_connection_manager_1 = require("./amqp-connection-manager");
7
+ const rabbitmq_consumers_1 = require("./rabbitmq-consumers");
8
+ class RabbitMQService {
9
+ constructor() {
10
+ this.logger = new common_1.Logger(RabbitMQService.name);
11
+ this.connectionBlocked = {
12
+ isBlocked: false,
13
+ reason: "",
14
+ };
15
+ }
16
+ async onApplicationBootstrap() {
17
+ amqp_connection_manager_1.AMQPConnectionManager.connection.on("blocked", ({ reason }) => {
18
+ console.error(`RabbitMQ broker is blocked with reason: ${reason}`);
19
+ this.connectionBlocked = { isBlocked: true, reason };
20
+ });
21
+ amqp_connection_manager_1.AMQPConnectionManager.connection.on("unblocked", () => {
22
+ var _a;
23
+ console.error(`RabbitMQ broker connection is unblocked, last reason was: ${(_a = this.connectionBlocked) === null || _a === void 0 ? void 0 : _a.reason}`);
24
+ this.connectionBlocked = { isBlocked: false, reason: "" };
25
+ });
26
+ }
27
+ /**
28
+ * Check status of the main conenection to the broker.
29
+ * @returns {number} 1 - Online | 0 - Offline
30
+ */
31
+ checkHealth() {
32
+ return amqp_connection_manager_1.AMQPConnectionManager.connection.isConnected() ? 1 : 0;
33
+ }
34
+ /**
35
+ * Publishes a message to the broker. Every published message needs its exchange and routingKey to be properly routed
36
+ * @param {string} exchangeName - Name of the exchange
37
+ * @param {string} routingKey - Publish routing key
38
+ * @param {T} the message that will be published to RabbitMQ. All messages will be transformed to JSON.
39
+ * @param {PublishOptions} options - Any custom options that you want to send with the message such as headers or properties
40
+ * @returns {Promise<boolean>} Returns a promise of confirmation.
41
+ * If **TRUE** it means that the message arrived and was successfully delivered to an exchange or queue.
42
+ * If **FALSE** or an error is thrown, the message was not published !
43
+ */
44
+ async publish(exchangeName, routingKey, message, options) {
45
+ let hasErrors = null;
46
+ try {
47
+ if (amqp_connection_manager_1.AMQPConnectionManager.connection) {
48
+ await this.waitForBlockedConnection();
49
+ return amqp_connection_manager_1.AMQPConnectionManager.publishChannelWrapper.publish(exchangeName, routingKey, JSON.stringify(message), Object.assign(Object.assign({ correlationId: (0, node_crypto_1.randomUUID)() }, options), { headers: Object.assign({ "x-delay": 0 }, options === null || options === void 0 ? void 0 : options.headers) }));
50
+ }
51
+ else {
52
+ throw new Error("Connection with RabbitMQ is closed. Cannot publish");
53
+ }
54
+ }
55
+ catch (e) {
56
+ hasErrors = e;
57
+ }
58
+ finally {
59
+ this.inspectPublisher(exchangeName, routingKey, message, options, hasErrors);
60
+ }
61
+ return !hasErrors;
62
+ }
63
+ async createConsumers() {
64
+ if (amqp_connection_manager_1.AMQPConnectionManager.isConsumersLoaded) {
65
+ throw new Error("Consumers already initialized. If you want to initiate the consumers manually please set consumerManualLoad: true");
66
+ }
67
+ const consumerInstance = new rabbitmq_consumers_1.RabbitMQConsumer(amqp_connection_manager_1.AMQPConnectionManager.connection, amqp_connection_manager_1.AMQPConnectionManager.rabbitModuleOptions, amqp_connection_manager_1.AMQPConnectionManager.publishChannelWrapper);
68
+ await consumerInstance.createConsumers();
69
+ this.logger.debug("Initiating RabbitMQ consumers manually");
70
+ }
71
+ async waitForBlockedConnection() {
72
+ var _a;
73
+ let retry = 0;
74
+ while (this.connectionBlocked.isBlocked && retry <= 60) {
75
+ console.warn("RabbitMQ connection is blocked, waiting 1s before trying again");
76
+ retry++;
77
+ await new Promise((resolve) => setTimeout(() => {
78
+ resolve();
79
+ }, 1000));
80
+ }
81
+ if (retry >= 60) {
82
+ throw new Error(`RabbitMQ connection is still blocked, cannot publish message. Reason: ${(_a = this.connectionBlocked) === null || _a === void 0 ? void 0 : _a.reason}`);
83
+ }
84
+ }
85
+ inspectPublisher(exchange, routingKey, content, properties, error) {
86
+ // if (
87
+ // !["publisher", "all"].includes(
88
+ // this.rabbitModuleOptions.trafficInspection,
89
+ // ) &&
90
+ // !error
91
+ // )
92
+ // return;
93
+ var _a;
94
+ const logLevel = error ? "error" : "info";
95
+ const message = `[AMQP] [PUBLISH] [${exchange}] [${routingKey}]`;
96
+ const logData = {
97
+ logLevel,
98
+ correlationId: properties === null || properties === void 0 ? void 0 : properties.correlationId,
99
+ title: message,
100
+ binding: { exchange, routingKey },
101
+ message: { content, properties },
102
+ };
103
+ if (error)
104
+ Object.assign(logData, { error: (_a = error.message) !== null && _a !== void 0 ? _a : error.toString() });
105
+ console[logLevel](JSON.stringify(logData));
106
+ // this.logger[logLevel]({
107
+ // log
108
+ // message,
109
+ // amqp: logData,
110
+ // error,
111
+ // });
112
+ }
113
+ }
114
+ exports.RabbitMQService = RabbitMQService;
115
+ //# sourceMappingURL=rabbitmq-service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rabbitmq-service.js","sourceRoot":"","sources":["../src/rabbitmq-service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ import { ChannelWrapper } from "amqp-connection-manager";
2
+ import { ConfirmChannel, ConsumeMessage } from "amqplib";
3
+ import { RabbitMQModuleOptions } from "./rabbitmq.types";
4
+ export type RabbitConsumerParameters = {
5
+ message: ConsumeMessage;
6
+ channel: ConfirmChannel;
7
+ queue: string;
8
+ };
9
+ export interface IRabbitHandler<T = any> {
10
+ (content: T, parameters?: RabbitConsumerParameters): Promise<void>;
11
+ }
12
+ export interface IDelayProgression {
13
+ (attempt: number): number;
14
+ }
15
+ export interface RabbitOptionsFactory {
16
+ createRabbitOptions(): RabbitMQModuleOptions;
17
+ }
18
+ export interface RabbitChannel {
19
+ exchangeType: string;
20
+ wrapper: ChannelWrapper;
21
+ }
22
+ export interface IRabbitConsumer<T = any> {
23
+ messageHandler(content: T, parameters?: RabbitConsumerParameters): Promise<void>;
24
+ }
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=rabbitmq.interfaces.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rabbitmq.interfaces.js","sourceRoot":"","sources":["../src/rabbitmq.interfaces.ts"],"names":[],"mappings":""}
@@ -0,0 +1,9 @@
1
+ import { DynamicModule, Type } from "@nestjs/common";
2
+ import { RabbitOptionsFactory } from "./rabbitmq.interfaces";
3
+ export type RabbitOptions = {
4
+ useClass: Type<RabbitOptionsFactory>;
5
+ injects?: any[];
6
+ };
7
+ export declare class RabbitMQModule {
8
+ static register(options: RabbitOptions): DynamicModule;
9
+ }
@@ -0,0 +1,37 @@
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 RabbitMQModule_1;
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.RabbitMQModule = void 0;
11
+ const common_1 = require("@nestjs/common");
12
+ const amqp_connection_manager_1 = require("./amqp-connection-manager");
13
+ const rabbitmq_service_1 = require("./rabbitmq-service");
14
+ let RabbitMQModule = RabbitMQModule_1 = class RabbitMQModule {
15
+ static register(options) {
16
+ var _a;
17
+ return {
18
+ module: RabbitMQModule_1,
19
+ imports: [...((_a = options === null || options === void 0 ? void 0 : options.injects) !== null && _a !== void 0 ? _a : [])],
20
+ global: true,
21
+ providers: [
22
+ amqp_connection_manager_1.AMQPConnectionManager,
23
+ {
24
+ provide: "RABBIT_OPTIONS",
25
+ useClass: options.useClass,
26
+ },
27
+ rabbitmq_service_1.RabbitMQService,
28
+ ],
29
+ exports: [rabbitmq_service_1.RabbitMQService],
30
+ };
31
+ }
32
+ };
33
+ exports.RabbitMQModule = RabbitMQModule;
34
+ exports.RabbitMQModule = RabbitMQModule = RabbitMQModule_1 = __decorate([
35
+ (0, common_1.Module)({})
36
+ ], RabbitMQModule);
37
+ //# sourceMappingURL=rabbitmq.module.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rabbitmq.module.js","sourceRoot":"","sources":["../src/rabbitmq.module.ts"],"names":[],"mappings":";;;;;;;;;;AAAA,2CAA6D;AAC7D,uEAAkE;AAClE,yDAAqD;AAS9C,IAAM,cAAc,sBAApB,MAAM,cAAc;IACzB,MAAM,CAAC,QAAQ,CAAC,OAAsB;;QACpC,OAAO;YACL,MAAM,EAAE,gBAAc;YACtB,OAAO,EAAE,CAAC,GAAG,CAAC,MAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,OAAO,mCAAI,EAAE,CAAC,CAAC;YACtC,MAAM,EAAE,IAAI;YACZ,SAAS,EAAE;gBACT,+CAAqB;gBACrB;oBACE,OAAO,EAAE,gBAAgB;oBACzB,QAAQ,EAAE,OAAO,CAAC,QAAQ;iBAC3B;gBACD,kCAAe;aAChB;YACD,OAAO,EAAE,CAAC,kCAAe,CAAC;SAC3B,CAAC;IACJ,CAAC;CACF,CAAA;AAjBY,wCAAc;yBAAd,cAAc;IAD1B,IAAA,eAAM,EAAC,EAAE,CAAC;GACE,cAAc,CAiB1B"}
@@ -0,0 +1,133 @@
1
+ import { IDelayProgression, IRabbitHandler } from "./rabbitmq.interfaces";
2
+ export type RabbitMQExchangeTypes = "direct" | "topic" | "fanout" | "headers";
3
+ export type LogType = "all" | "consumer" | "publisher" | "none";
4
+ export type RabbitMQConsumerOptions = {
5
+ /** Declare the queue parameters and operation */
6
+ /** Name of the Queue */
7
+ queue: string;
8
+ /** The SDK will send an ACK at the end of the consumer function
9
+ * If *disabled* your consumer will need to call channel.ack() manually !
10
+ * Default: true*/
11
+ autoAck?: boolean;
12
+ /** Amount of messages that will be delivered to the consumer at once
13
+ * Default: 10 */
14
+ prefetch?: number;
15
+ /** If messages enqueued on the queue will be stored on a persistent disk
16
+ * **WARNING**: If this option is disabled, Rabbit will store the messages in-memory. If RabbitMQ goes offline while messages are enqueued, they will be lost!
17
+ * Default: true */
18
+ durable?: boolean;
19
+ /** If the queue needs to be automatically deleted when there are no consumers attached.
20
+ * **WARNING**: RabbitMQ will delete the queue no matter the amount of messages enqueued.
21
+ * Default: false */
22
+ autoDelete?: boolean;
23
+ /** By definition, every queue needs to be attached to an Exchange. Here you can declare the exchange */
24
+ /** Name of the Exchange */
25
+ exchangeName: string;
26
+ /** Routing key between the Queue and the exchange. This acts as a filter so only this routing key will be received by the queue.
27
+ * For exchanges of the type `fanout` this parameter will be ignored
28
+ * This parameter accepts patterns
29
+ * E.g: webhook.`#` - Routes all messages that contains at least `webhook` in the routing key. (webhooks, webhooks.test)
30
+ * webhook.\*.test - Routes all messages that contains the described patter (webhook.ABC.test, webhook.123.test) */
31
+ routingKey: string;
32
+ /** When the consumer throwns an error. The message will be automatically enqueued to a retry queue. Here you declare the strategies for retrying */
33
+ retryStrategy?: {
34
+ /** If the retry strategy will be executed.
35
+ * Default: true */
36
+ enabled?: boolean;
37
+ /** Maximum amount of attempts before sending the message do the DLQ
38
+ * Default: 5 */
39
+ maxAttempts?: number;
40
+ /** The delay amount in MS before the retry sends the message to the original queue
41
+ * Default: 5000*/
42
+ delay?: IDelayProgression;
43
+ };
44
+ /** Override default suffix that are defined in this library */
45
+ suffixOptions?: {
46
+ exchangeSuffix?: string;
47
+ dlqSuffix?: string;
48
+ };
49
+ };
50
+ export type RabbitConnectionOptions = {
51
+ urls: string | string[];
52
+ };
53
+ export type RabbitMQAssertExchange = {
54
+ /** Name of the exchange to be asserted.
55
+ * An automatic `.exchange` will be appended to the name in case the exchange name does not have it */
56
+ name: string;
57
+ /** Assert the type of the exchange.
58
+ * For more information about exchange types: https://www.rabbitmq.com/tutorials/amqp-concepts
59
+ * */
60
+ type: RabbitMQExchangeTypes;
61
+ options?: {
62
+ /** If messages that passes through this exchange should be stored on a persistent disk
63
+ * **WARNING**: If this option is disabled, Rabbit will store the messages in-memory. If RabbitMQ goes offline while messages are enqueued, they will be lost!
64
+ * Default: true */
65
+ durable?: boolean;
66
+ /** If the queue needs to be automatically deleted when there are no consumers attached.
67
+ * **WARNING**: RabbitMQ will delete the queue no matter the amount of messages enqueued.
68
+ * Default: false */
69
+ autoDelete?: boolean;
70
+ /** Override default suffix that are defined in this library.
71
+ * Default: '.exchange'*/
72
+ exchangeSufix?: string;
73
+ /** Declare the exchange as a delayed one, in this scenario the exchange will be declated as a `x-delayed-message` with an argument `x-delayed-type: ${type}`
74
+ * Default: false */
75
+ isDelayed?: boolean;
76
+ };
77
+ };
78
+ export type RabbitMQConsumerChannel = {
79
+ options: RabbitMQConsumerOptions;
80
+ /** Callback bind that will be declared as consumer
81
+ * This handler will follow the `IRabbitHandler` interface
82
+ * E.g: messageHandler: this.yourService.messageHandler.bind(this.yourService)
83
+ */
84
+ messageHandler: IRabbitHandler;
85
+ };
86
+ export type RabbitMQModuleOptions = {
87
+ /** Connection URI for the RabbitMQ server
88
+ * E.g: amqp://{user}:{password}@{url}/{vhost} */
89
+ connectionString: string | string[];
90
+ /** The name of the squad you belong */
91
+ delayExchangeName: string;
92
+ /** When **TRUE** the SDK will not initiate the consumers automatically during the _OnModuleInit_
93
+ * To initiate the consumer, you can call it at the end of the `bootstrap()` on your `main.ts` file
94
+ * ```javascript
95
+ * const rabbitService: RabbitMQService = app.get(RabbitMQService);
96
+ * await rabbitService.beginConsumers();
97
+ * ```
98
+ * Default: false */
99
+ consumerManualLoad?: boolean;
100
+ /** When **TRUE**, the connection will be made synchronously during the `OnModuleInit` lifecycle
101
+ * and will only return after the connection is sucessfully made
102
+ * When **FALSE**, the connection is made asynchronously and will release the lifecycle event as fast as possible.
103
+ * Default: true */
104
+ waitConnection?: boolean;
105
+ /** All exchanges declared here will be validated before attaching the consumers
106
+ * If any of the exchanegs declared can not be asserted an error will be thrown */
107
+ assertExchanges?: Array<RabbitMQAssertExchange>;
108
+ /** Enables the message inspection of different parts of the RabbitMQ
109
+ * this option can be overriden by using the env RABBITMQ_TRAFFIC_TYPE */
110
+ trafficInspection?: LogType;
111
+ /** Array of consumers that will be attached to the application*/
112
+ consumerChannels?: Array<RabbitMQConsumerChannel>;
113
+ };
114
+ export type PublishOptions = {
115
+ expiration?: string | number | undefined;
116
+ userId?: string | undefined;
117
+ CC?: string | string[] | undefined;
118
+ mandatory?: boolean | undefined;
119
+ persistent?: boolean | undefined;
120
+ deliveryMode?: boolean | number | undefined;
121
+ BCC?: string | string[] | undefined;
122
+ contentType?: string | undefined;
123
+ contentEncoding?: string | undefined;
124
+ headers?: any;
125
+ priority?: number | undefined;
126
+ correlationId?: string | undefined;
127
+ replyTo?: string | undefined;
128
+ messageId?: string | undefined;
129
+ timestamp?: number | undefined;
130
+ type?: string | undefined;
131
+ appId?: string | undefined;
132
+ timeout?: number;
133
+ };
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=rabbitmq.types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rabbitmq.types.js","sourceRoot":"","sources":["../src/rabbitmq.types.ts"],"names":[],"mappings":""}