@palmetto/pubsub 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.
Files changed (42) hide show
  1. package/README.md +154 -0
  2. package/dist/bullmq/config.d.ts +21 -0
  3. package/dist/bullmq/config.js +2 -0
  4. package/dist/bullmq/connection.d.ts +2 -0
  5. package/dist/bullmq/connection.js +5 -0
  6. package/dist/bullmq/main.d.ts +6 -0
  7. package/dist/bullmq/main.js +21 -0
  8. package/dist/bullmq/publisher.d.ts +13 -0
  9. package/dist/bullmq/publisher.js +62 -0
  10. package/dist/bullmq/pubsub.d.ts +12 -0
  11. package/dist/bullmq/pubsub.js +35 -0
  12. package/dist/bullmq/subscriber.d.ts +27 -0
  13. package/dist/bullmq/subscriber.js +118 -0
  14. package/dist/errors.d.ts +17 -0
  15. package/dist/errors.js +37 -0
  16. package/dist/interfaces.d.ts +120 -0
  17. package/dist/interfaces.js +28 -0
  18. package/dist/lazy-load.d.ts +11 -0
  19. package/dist/lazy-load.js +79 -0
  20. package/dist/main.d.ts +6 -0
  21. package/dist/main.js +22 -0
  22. package/dist/publisher.d.ts +11 -0
  23. package/dist/publisher.js +87 -0
  24. package/dist/rabbitmq/config.d.ts +84 -0
  25. package/dist/rabbitmq/config.js +82 -0
  26. package/dist/rabbitmq/connection.d.ts +41 -0
  27. package/dist/rabbitmq/connection.js +140 -0
  28. package/dist/rabbitmq/main.d.ts +5 -0
  29. package/dist/rabbitmq/main.js +21 -0
  30. package/dist/rabbitmq/publisher.d.ts +29 -0
  31. package/dist/rabbitmq/publisher.js +98 -0
  32. package/dist/rabbitmq/pubsub.d.ts +15 -0
  33. package/dist/rabbitmq/pubsub.js +37 -0
  34. package/dist/rabbitmq/subscriber.d.ts +33 -0
  35. package/dist/rabbitmq/subscriber.js +197 -0
  36. package/dist/rabbitmq/utility.d.ts +6 -0
  37. package/dist/rabbitmq/utility.js +11 -0
  38. package/dist/subscriber.d.ts +28 -0
  39. package/dist/subscriber.js +140 -0
  40. package/package.json +54 -0
  41. package/src/bullmq/README.md +63 -0
  42. package/src/rabbitmq/README.md +184 -0
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MessageResult = exports.IdMetaSchema = exports.MetaSchema = void 0;
4
+ const v4_1 = require("zod/v4");
5
+ exports.MetaSchema = v4_1.z.object({
6
+ createdAt: v4_1.z.iso.datetime(),
7
+ schemaId: v4_1.z.string(),
8
+ publishedBy: v4_1.z.string(),
9
+ });
10
+ exports.IdMetaSchema = v4_1.z.object({
11
+ id: v4_1.z.string().optional(),
12
+ meta: exports.MetaSchema.optional(),
13
+ });
14
+ var MessageResult;
15
+ (function (MessageResult) {
16
+ /**
17
+ * the message was handled successfully or can otherwise be ignored
18
+ */
19
+ MessageResult["Ok"] = "ok";
20
+ /**
21
+ * The message should be retried
22
+ */
23
+ MessageResult["Retry"] = "retry";
24
+ /**
25
+ * The message failed and is either discarded or stored in a dead-letter queue
26
+ */
27
+ MessageResult["Fail"] = "fail";
28
+ })(MessageResult || (exports.MessageResult = MessageResult = {}));
@@ -0,0 +1,11 @@
1
+ /**
2
+ * This loads and returns a typed package.
3
+ * TPackage is a package type
4
+ * @returns The package
5
+ */
6
+ export declare function lazyLoad<TPackage>({ packageName, context, }: {
7
+ /** The name of the package to load (eg: "bullmq") */
8
+ packageName: string;
9
+ /** The name of the module trying to lazy-load the package (eg: "BullMqPublisher") */
10
+ context: string;
11
+ }): Promise<TPackage>;
@@ -0,0 +1,79 @@
1
+ "use strict";
2
+ /*
3
+ example usage:
4
+
5
+ // this imports the package as a type:
6
+ import type * as bullmq from "bullmq";
7
+
8
+ //then call lazyLoad with a function that is called at runtime, not a static startup call:
9
+ const BullMqPackage = await lazyLoad<
10
+ typeof bullmq,
11
+ >({
12
+ packageName: "bullmq",
13
+ context: "BullMqPublisher",
14
+ });
15
+
16
+ // then you can use the result of lazyLoad as if it was the original imported package type:
17
+ const queue = new BullMqPackage.Queue(new BullMqPackage.Queue(queueName, {
18
+ connection: this.connection,
19
+ });
20
+ */
21
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
22
+ if (k2 === undefined) k2 = k;
23
+ var desc = Object.getOwnPropertyDescriptor(m, k);
24
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
25
+ desc = { enumerable: true, get: function() { return m[k]; } };
26
+ }
27
+ Object.defineProperty(o, k2, desc);
28
+ }) : (function(o, m, k, k2) {
29
+ if (k2 === undefined) k2 = k;
30
+ o[k2] = m[k];
31
+ }));
32
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
33
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
34
+ }) : function(o, v) {
35
+ o["default"] = v;
36
+ });
37
+ var __importStar = (this && this.__importStar) || (function () {
38
+ var ownKeys = function(o) {
39
+ ownKeys = Object.getOwnPropertyNames || function (o) {
40
+ var ar = [];
41
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
42
+ return ar;
43
+ };
44
+ return ownKeys(o);
45
+ };
46
+ return function (mod) {
47
+ if (mod && mod.__esModule) return mod;
48
+ var result = {};
49
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
50
+ __setModuleDefault(result, mod);
51
+ return result;
52
+ };
53
+ })();
54
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
55
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
56
+ return new (P || (P = Promise))(function (resolve, reject) {
57
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
58
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
59
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
60
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
61
+ });
62
+ };
63
+ Object.defineProperty(exports, "__esModule", { value: true });
64
+ exports.lazyLoad = lazyLoad;
65
+ /**
66
+ * This loads and returns a typed package.
67
+ * TPackage is a package type
68
+ * @returns The package
69
+ */
70
+ function lazyLoad(_a) {
71
+ return __awaiter(this, arguments, void 0, function* ({ packageName, context, }) {
72
+ try {
73
+ return (yield Promise.resolve(`${packageName}`).then(s => __importStar(require(s))));
74
+ }
75
+ catch (err) {
76
+ throw new Error(`The "${packageName}" package is missing. Please, make sure to install it to take advantage of ${context}.`, { cause: err });
77
+ }
78
+ });
79
+ }
package/dist/main.d.ts ADDED
@@ -0,0 +1,6 @@
1
+ export * from "./errors.js";
2
+ export * from "./interfaces.js";
3
+ export * from "./publisher.js";
4
+ export * from "./subscriber.js";
5
+ export * from "./bullmq/main.js";
6
+ export * from "./rabbitmq/main.js";
package/dist/main.js ADDED
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./errors.js"), exports);
18
+ __exportStar(require("./interfaces.js"), exports);
19
+ __exportStar(require("./publisher.js"), exports);
20
+ __exportStar(require("./subscriber.js"), exports);
21
+ __exportStar(require("./bullmq/main.js"), exports);
22
+ __exportStar(require("./rabbitmq/main.js"), exports);
@@ -0,0 +1,11 @@
1
+ import { BaseMessage, Logger, PublisherProvider, PubSubConfiguration } from "./interfaces";
2
+ export declare class Publisher {
3
+ private readonly logger;
4
+ private readonly hashes;
5
+ private readonly publisherProviders;
6
+ constructor(logger: Logger, providers?: PublisherProvider[]);
7
+ addProvider(provider: PublisherProvider): void;
8
+ removeProvider(providerOrTransport: PublisherProvider | string): boolean;
9
+ publish(config: PubSubConfiguration, message: BaseMessage): Promise<void>;
10
+ close(): Promise<void>;
11
+ }
@@ -0,0 +1,87 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.Publisher = void 0;
13
+ const v4_1 = require("zod/v4");
14
+ const uuid_1 = require("uuid");
15
+ const crypto_hash_1 = require("crypto-hash");
16
+ const errors_1 = require("./errors");
17
+ class Publisher {
18
+ constructor(logger, providers) {
19
+ this.logger = logger;
20
+ this.hashes = new Map();
21
+ this.publisherProviders = new Map();
22
+ if (providers) {
23
+ providers.forEach((provider) => this.publisherProviders.set(provider.transport, provider));
24
+ }
25
+ }
26
+ addProvider(provider) {
27
+ var _a, _b;
28
+ this.publisherProviders.set(provider.transport, provider);
29
+ (_b = (_a = this.logger).debug) === null || _b === void 0 ? void 0 : _b.call(_a, `Publisher added provider for ${provider.transport}`);
30
+ }
31
+ removeProvider(providerOrTransport) {
32
+ var _a, _b;
33
+ let transport;
34
+ if (typeof providerOrTransport === "string") {
35
+ transport = providerOrTransport;
36
+ }
37
+ else {
38
+ transport = providerOrTransport.transport;
39
+ }
40
+ (_b = (_a = this.logger).debug) === null || _b === void 0 ? void 0 : _b.call(_a, `Publisher removing provider for ${transport}`);
41
+ return this.publisherProviders.delete(transport);
42
+ }
43
+ publish(config, message) {
44
+ return __awaiter(this, void 0, void 0, function* () {
45
+ var _a, _b;
46
+ const { transport, schema } = config;
47
+ const provider = this.publisherProviders.get(transport);
48
+ if (!provider) {
49
+ throw new errors_1.MissingPubSubProviderError(`No provider configured for ${transport}`);
50
+ }
51
+ if (!message.id) {
52
+ message.id = (0, uuid_1.v4)();
53
+ }
54
+ let hash = this.hashes.get(schema);
55
+ if (!hash) {
56
+ const jsonSchema = JSON.stringify(v4_1.z.toJSONSchema(schema), null, 3);
57
+ hash = yield (0, crypto_hash_1.sha256)(jsonSchema);
58
+ this.hashes.set(schema, hash);
59
+ }
60
+ if (!message.meta) {
61
+ message.meta = {
62
+ createdAt: new Date().toISOString(),
63
+ publishedBy: "",
64
+ schemaId: hash,
65
+ };
66
+ }
67
+ else {
68
+ message.meta.schemaId = hash;
69
+ }
70
+ const json = JSON.stringify(message);
71
+ const check = schema.safeParse(JSON.parse(json));
72
+ if (!check.success) {
73
+ throw new errors_1.SchemaValidationError(`Schema did not accept the published message: ${check.error.message}`);
74
+ }
75
+ (_b = (_a = this.logger).debug) === null || _b === void 0 ? void 0 : _b.call(_a, `Publisher publishing message for ${transport}`);
76
+ yield provider.publish(config, json);
77
+ });
78
+ }
79
+ close() {
80
+ return __awaiter(this, void 0, void 0, function* () {
81
+ for (const provider of this.publisherProviders.values()) {
82
+ yield provider.close();
83
+ }
84
+ });
85
+ }
86
+ }
87
+ exports.Publisher = Publisher;
@@ -0,0 +1,84 @@
1
+ import { MessageContext, PubSubConfiguration } from "../interfaces";
2
+ export interface RabbitMqConnectionConfig {
3
+ /**
4
+ * The URL to the RabbitMQ host
5
+ */
6
+ host: string;
7
+ /**
8
+ * Delay between publisher startup retries if the connection fails (default: 500ms)
9
+ */
10
+ startupRetryDelayMs?: number;
11
+ /**
12
+ * Timeout for publisher startup retries if the connection fails (default: 10 seconds)
13
+ */
14
+ startupRetryTimeoutMs?: number;
15
+ }
16
+ export type QueueType = "default" | "dead-letter" | "retry";
17
+ export type ExchangeType = "direct" | "topic";
18
+ /**
19
+ * Default binding key for all messages
20
+ */
21
+ export declare const DEFAULT_BINDING_KEY = "default";
22
+ export interface RabbitQueueExchangeConfiguration extends PubSubConfiguration {
23
+ /**
24
+ * The queue name prefix
25
+ */
26
+ name: string;
27
+ /**
28
+ * For topic exchanges, the name of the subscriber is used here
29
+ */
30
+ topicSubscriberName?: string;
31
+ /**
32
+ * Support direct exchange where each message is delivered once, or topic exchange where each message is delivered to multiple queues
33
+ */
34
+ exchangeType?: ExchangeType;
35
+ /**
36
+ * When true, the queue and exchange will be deleted after the consumers exit [note: dead-letter exchanges & queues main remain when there are no dead-letter messages or consumers]
37
+ */
38
+ temporary?: boolean;
39
+ /**
40
+ * The queue prefetch amount for subscribers. Defaults to 5 if not set.
41
+ */
42
+ prefetch?: number;
43
+ /**
44
+ * Pass a queueType when you want to publish or subscribe to the dead-letter or retry queues.
45
+ */
46
+ queueType?: QueueType;
47
+ /**
48
+ * Override default queue & exchange names
49
+ */
50
+ overrides?: RabbitQueueExchangeCustomConfiguration;
51
+ }
52
+ export interface RabbitQueueExchangeNames {
53
+ queueName?: string;
54
+ exchangeName?: string;
55
+ routingKey?: string;
56
+ }
57
+ /**
58
+ * A collection of properties to override default pub/sub configuration values
59
+ */
60
+ export interface RabbitQueueExchangeCustomConfiguration {
61
+ names: Partial<Record<QueueType, RabbitQueueExchangeNames>>;
62
+ retryQueueExchangeName?: string;
63
+ }
64
+ export interface RabbitMqMessageContext extends MessageContext {
65
+ exchangeName?: string;
66
+ routingKey?: string;
67
+ }
68
+ /**
69
+ * Returns the queue name based on the configuration
70
+ *
71
+ * @param config
72
+ * @returns The queue name
73
+ */
74
+ export declare function getQueueName(config: RabbitQueueExchangeConfiguration): string;
75
+ export declare const QueueNameExtensions: Record<QueueType, string | undefined>;
76
+ /**
77
+ * Returns the exchange name based on the configuration
78
+ * @param config
79
+ * @returns The exchange name
80
+ */
81
+ export declare function getExchangeName(config: RabbitQueueExchangeConfiguration): string;
82
+ export declare function getQueueType(config: RabbitQueueExchangeConfiguration): QueueType;
83
+ export declare function getRoutingKey(config: RabbitQueueExchangeConfiguration): string;
84
+ export declare function getExchangeType(config: RabbitQueueExchangeConfiguration): ExchangeType;
@@ -0,0 +1,82 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.QueueNameExtensions = exports.DEFAULT_BINDING_KEY = void 0;
4
+ exports.getQueueName = getQueueName;
5
+ exports.getExchangeName = getExchangeName;
6
+ exports.getQueueType = getQueueType;
7
+ exports.getRoutingKey = getRoutingKey;
8
+ exports.getExchangeType = getExchangeType;
9
+ const errors_1 = require("../errors");
10
+ /**
11
+ * Default binding key for all messages
12
+ */
13
+ exports.DEFAULT_BINDING_KEY = "default";
14
+ /**
15
+ * Returns the queue name based on the configuration
16
+ *
17
+ * @param config
18
+ * @returns The queue name
19
+ */
20
+ function getQueueName(config) {
21
+ var _a, _b;
22
+ const queueType = getQueueType(config);
23
+ if ((_b = (_a = config.overrides) === null || _a === void 0 ? void 0 : _a.names[queueType]) === null || _b === void 0 ? void 0 : _b.queueName) {
24
+ return config.overrides.names[queueType].queueName;
25
+ }
26
+ let queueName = config.name;
27
+ if (config.exchangeType === "topic") {
28
+ if (!config.topicSubscriberName) {
29
+ throw new errors_1.ConfigurationError("Topic queues must have a subscriber name");
30
+ }
31
+ queueName += "." + config.topicSubscriberName;
32
+ }
33
+ if (queueType === "dead-letter") {
34
+ queueName += ".dlq";
35
+ }
36
+ else if (queueType === "retry") {
37
+ queueName += ".rtq";
38
+ }
39
+ return queueName;
40
+ }
41
+ exports.QueueNameExtensions = {
42
+ "dead-letter": ".dlx",
43
+ retry: ".rtx",
44
+ default: undefined,
45
+ };
46
+ /**
47
+ * Returns the exchange name based on the configuration
48
+ * @param config
49
+ * @returns The exchange name
50
+ */
51
+ function getExchangeName(config) {
52
+ var _a, _b;
53
+ const queueType = getQueueType(config);
54
+ if ((_b = (_a = config.overrides) === null || _a === void 0 ? void 0 : _a.names[queueType]) === null || _b === void 0 ? void 0 : _b.exchangeName) {
55
+ return config.overrides.names[queueType].exchangeName;
56
+ }
57
+ let exchangeName = config.name;
58
+ if (["dead-letter", "retry"].includes(queueType)) {
59
+ if (config.exchangeType === "topic") {
60
+ if (!config.topicSubscriberName) {
61
+ throw new errors_1.ConfigurationError(`Topic ${queueType} exchanges must have a subscriber name`);
62
+ }
63
+ exchangeName += "." + config.topicSubscriberName;
64
+ }
65
+ }
66
+ const ext = exports.QueueNameExtensions[queueType];
67
+ if (ext) {
68
+ exchangeName += ext;
69
+ }
70
+ return exchangeName;
71
+ }
72
+ function getQueueType(config) {
73
+ return config.queueType || "default";
74
+ }
75
+ function getRoutingKey(config) {
76
+ var _a, _b;
77
+ return (((_b = (_a = config.overrides) === null || _a === void 0 ? void 0 : _a.names[getQueueType(config)]) === null || _b === void 0 ? void 0 : _b.routingKey) ||
78
+ exports.DEFAULT_BINDING_KEY);
79
+ }
80
+ function getExchangeType(config) {
81
+ return config.exchangeType || "direct";
82
+ }
@@ -0,0 +1,41 @@
1
+ import type * as amqpmgr from "amqp-connection-manager";
2
+ import type { Channel } from "amqplib";
3
+ import { RabbitQueueExchangeConfiguration, RabbitMqConnectionConfig } from "./config";
4
+ import { Logger } from "../interfaces";
5
+ export declare class SocketError extends Error {
6
+ readonly code: string;
7
+ readonly error: unknown;
8
+ constructor(code: string, error: unknown);
9
+ }
10
+ export declare const RABBITMQ_TRANSPORT = "rabbitmq";
11
+ /**
12
+ * Manages access to the AMQP connection itself
13
+ */
14
+ export declare class RabbitMqConnection {
15
+ readonly connection: amqpmgr.AmqpConnectionManager;
16
+ private readonly logger;
17
+ readonly config: RabbitMqConnectionConfig;
18
+ static create(config: RabbitMqConnectionConfig, logger: Logger): Promise<RabbitMqConnection>;
19
+ private constructor();
20
+ close(): Promise<void>;
21
+ /**
22
+ * Creates the exchanges necessary for the given config
23
+ * @param channel
24
+ * @param config Must be isDlq === false | undefined
25
+ * @param dlConfig Must be isDlq
26
+ * @returns
27
+ */
28
+ assertExchange(channel: Channel, config: RabbitQueueExchangeConfiguration): Promise<string>;
29
+ assertQueueAndBindings(channel: Channel, config: RabbitQueueExchangeConfiguration): Promise<{
30
+ exchangeName: string;
31
+ dlExchangeName: string;
32
+ retryExchangeName: string;
33
+ queueName: string;
34
+ dlQueueName: string;
35
+ retryQueueName: string;
36
+ retryDlExchangeName: string;
37
+ }>;
38
+ private assertQueue;
39
+ private bindQueue;
40
+ private static getConfigs;
41
+ }
@@ -0,0 +1,140 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.RabbitMqConnection = exports.RABBITMQ_TRANSPORT = exports.SocketError = void 0;
13
+ const config_1 = require("./config");
14
+ const lazy_load_1 = require("../lazy-load");
15
+ class SocketError extends Error {
16
+ constructor(code, error) {
17
+ super(`Socket error: ${code}`);
18
+ this.code = code;
19
+ this.error = error;
20
+ }
21
+ }
22
+ exports.SocketError = SocketError;
23
+ exports.RABBITMQ_TRANSPORT = "rabbitmq";
24
+ /**
25
+ * Manages access to the AMQP connection itself
26
+ */
27
+ class RabbitMqConnection {
28
+ static create(config, logger) {
29
+ return __awaiter(this, void 0, void 0, function* () {
30
+ const AmqpMgrPackage = yield (0, lazy_load_1.lazyLoad)({
31
+ packageName: "amqp-connection-manager",
32
+ context: "RabbitMqConnection",
33
+ });
34
+ return new RabbitMqConnection(config, AmqpMgrPackage.connect(config.host), logger);
35
+ });
36
+ }
37
+ constructor(config, connection, logger) {
38
+ this.connection = connection;
39
+ this.logger = logger;
40
+ this.config = Object.assign({}, config);
41
+ }
42
+ close() {
43
+ return __awaiter(this, void 0, void 0, function* () {
44
+ var _a, _b;
45
+ (_b = (_a = this.logger).debug) === null || _b === void 0 ? void 0 : _b.call(_a, "RabbitMQ closing connection");
46
+ yield this.connection.close();
47
+ });
48
+ }
49
+ /**
50
+ * Creates the exchanges necessary for the given config
51
+ * @param channel
52
+ * @param config Must be isDlq === false | undefined
53
+ * @param dlConfig Must be isDlq
54
+ * @returns
55
+ */
56
+ assertExchange(channel, config) {
57
+ return __awaiter(this, void 0, void 0, function* () {
58
+ var _a, _b;
59
+ const { exchange } = yield channel.assertExchange((0, config_1.getExchangeName)(config), (0, config_1.getExchangeType)(config), {
60
+ autoDelete: !!config.temporary,
61
+ });
62
+ (_b = (_a = this.logger).debug) === null || _b === void 0 ? void 0 : _b.call(_a, `Asserted exchange ${exchange}`);
63
+ return exchange;
64
+ });
65
+ }
66
+ assertQueueAndBindings(channel, config) {
67
+ return __awaiter(this, void 0, void 0, function* () {
68
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
69
+ let dlConfig, retryConfig;
70
+ ({ config, dlConfig, retryConfig } = RabbitMqConnection.getConfigs(config));
71
+ const exchangeName = yield this.assertExchange(channel, config);
72
+ const dlExchangeName = yield this.assertExchange(channel, dlConfig);
73
+ const retryExchangeName = yield this.assertExchange(channel, retryConfig);
74
+ const queueName = (0, config_1.getQueueName)(config);
75
+ const dlQueueName = (0, config_1.getQueueName)(dlConfig);
76
+ const retryQueueName = (0, config_1.getQueueName)(retryConfig);
77
+ const autoDelete = !!config.temporary;
78
+ // special case to ensure the retry dead-letter only reverts to the original queue,
79
+ // regardless of original exchange type [that is, not re-using the original queue exchange here]
80
+ const retryDlExchangeName = ((_a = config.overrides) === null || _a === void 0 ? void 0 : _a.retryQueueExchangeName) ||
81
+ `${queueName}${config_1.QueueNameExtensions["dead-letter"]}${config_1.QueueNameExtensions["retry"]}`;
82
+ yield channel.assertExchange(retryDlExchangeName, "direct", {
83
+ autoDelete: !!config.temporary,
84
+ });
85
+ (_c = (_b = this.logger).debug) === null || _c === void 0 ? void 0 : _c.call(_b, `Asserted exchange ${retryDlExchangeName}`);
86
+ // create the dead-letter queue without any DLX
87
+ yield this.assertQueue(channel, dlQueueName, autoDelete);
88
+ // create the retry queue using retry dead-letter exchange as the DLX
89
+ yield this.assertQueue(channel, retryQueueName, autoDelete, retryDlExchangeName);
90
+ // create the default queue using the dead-letter exchange as the DLX
91
+ yield this.assertQueue(channel, queueName, autoDelete, dlExchangeName);
92
+ // bind the default queue using the default exchange and default routing key
93
+ yield this.bindQueue(channel, queueName, exchangeName, ((_e = (_d = config.overrides) === null || _d === void 0 ? void 0 : _d.names.default) === null || _e === void 0 ? void 0 : _e.routingKey) || config_1.DEFAULT_BINDING_KEY);
94
+ // bind the dead-letter queue to the dead-letter exchange and dead-letter routing key
95
+ yield this.bindQueue(channel, dlQueueName, dlExchangeName, ((_g = (_f = config.overrides) === null || _f === void 0 ? void 0 : _f.names["dead-letter"]) === null || _g === void 0 ? void 0 : _g.routingKey) || config_1.DEFAULT_BINDING_KEY);
96
+ // bind the retry queue to the retry exchange and retry routing key
97
+ yield this.bindQueue(channel, retryQueueName, retryExchangeName, ((_j = (_h = config.overrides) === null || _h === void 0 ? void 0 : _h.names.retry) === null || _j === void 0 ? void 0 : _j.routingKey) || config_1.DEFAULT_BINDING_KEY);
98
+ // bind the queue to the retry dead-letter exchange and default routing key
99
+ yield this.bindQueue(channel, queueName, retryDlExchangeName, ((_l = (_k = config.overrides) === null || _k === void 0 ? void 0 : _k.names.default) === null || _l === void 0 ? void 0 : _l.routingKey) || config_1.DEFAULT_BINDING_KEY);
100
+ return {
101
+ exchangeName,
102
+ dlExchangeName,
103
+ retryExchangeName,
104
+ queueName,
105
+ dlQueueName,
106
+ retryQueueName,
107
+ retryDlExchangeName,
108
+ };
109
+ });
110
+ }
111
+ assertQueue(channel, queueName, autoDelete, deadLetterExchange) {
112
+ return __awaiter(this, void 0, void 0, function* () {
113
+ var _a, _b;
114
+ yield channel.assertQueue(queueName, {
115
+ autoDelete,
116
+ deadLetterExchange,
117
+ });
118
+ (_b = (_a = this.logger).debug) === null || _b === void 0 ? void 0 : _b.call(_a, `Asserted queue ${queueName}`);
119
+ });
120
+ }
121
+ bindQueue(channel, queueName, exchangeName, bindingKey) {
122
+ return __awaiter(this, void 0, void 0, function* () {
123
+ var _a, _b;
124
+ yield channel.bindQueue(queueName, exchangeName, bindingKey);
125
+ (_b = (_a = this.logger).debug) === null || _b === void 0 ? void 0 : _b.call(_a, `Bound queue ${queueName} to ${exchangeName}:${bindingKey}`);
126
+ });
127
+ }
128
+ static getConfigs(config) {
129
+ const dlConfig = config.queueType === "dead-letter"
130
+ ? config
131
+ : Object.assign(Object.assign({}, config), { queueType: "dead-letter" });
132
+ const retryConfig = config.queueType === "retry" ? config : Object.assign(Object.assign({}, config), { queueType: "retry" });
133
+ config =
134
+ !config.queueType || config.queueType === "default"
135
+ ? config
136
+ : Object.assign(Object.assign({}, config), { queueType: "default" });
137
+ return { config, dlConfig, retryConfig };
138
+ }
139
+ }
140
+ exports.RabbitMqConnection = RabbitMqConnection;
@@ -0,0 +1,5 @@
1
+ export * from "./config.js";
2
+ export * from "./connection.js";
3
+ export * from "./publisher.js";
4
+ export * from "./subscriber.js";
5
+ export * from "./pubsub.js";
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./config.js"), exports);
18
+ __exportStar(require("./connection.js"), exports);
19
+ __exportStar(require("./publisher.js"), exports);
20
+ __exportStar(require("./subscriber.js"), exports);
21
+ __exportStar(require("./pubsub.js"), exports);
@@ -0,0 +1,29 @@
1
+ import type { ChannelWrapper } from "amqp-connection-manager";
2
+ import { Logger, PublisherProvider } from "../interfaces";
3
+ import { RabbitMqConnection } from "./connection";
4
+ import { RabbitQueueExchangeConfiguration } from "./config";
5
+ export declare class RabbitMqPublisher implements PublisherProvider {
6
+ private readonly connection;
7
+ private readonly logger;
8
+ private inited;
9
+ private channel?;
10
+ private connected;
11
+ constructor(connection: RabbitMqConnection, logger: Logger);
12
+ readonly transport: string;
13
+ /**
14
+ * Initializes the rabbit connection and asserts the exchange for the configuration.
15
+ *
16
+ * @param config
17
+ * @returns a Promise containing the ChannelWrapper to publish messages with
18
+ */
19
+ init(config: RabbitQueueExchangeConfiguration): Promise<ChannelWrapper>;
20
+ /**
21
+ * Publishes a message to Rabbit based on the configuration
22
+ *
23
+ * @param config The rabbit queue configuration
24
+ * @param message The JSON message to send
25
+ * @returns A promise that is completed when the message is published
26
+ */
27
+ publish(config: RabbitQueueExchangeConfiguration, message: string): Promise<void>;
28
+ close(): Promise<void> | undefined;
29
+ }