@meridianjs/event-bus-redis 0.1.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,43 @@
1
+ import { IEventBus, EventMessage, SubscriberFn, ModuleDefinition } from '@meridianjs/types';
2
+
3
+ interface RedisEventBusOptions {
4
+ url: string;
5
+ /** BullMQ queue name — defaults to "meridian:events" */
6
+ queueName?: string;
7
+ /** Worker concurrency — defaults to 5 */
8
+ concurrency?: number;
9
+ }
10
+ /**
11
+ * Production event bus backed by BullMQ + Redis.
12
+ *
13
+ * All events go into a single persistent BullMQ queue.
14
+ * A Worker processes jobs and fans out to all registered handlers for
15
+ * the event name — providing durable, async, at-least-once delivery.
16
+ *
17
+ * For local development use @meridianjs/event-bus-local instead.
18
+ */
19
+ declare class RedisEventBus implements IEventBus {
20
+ private queue;
21
+ private worker;
22
+ private connection;
23
+ /** event name → set of registered handlers */
24
+ private handlers;
25
+ constructor(options: RedisEventBusOptions);
26
+ emit<T>(event: EventMessage<T> | EventMessage<T>[]): Promise<void>;
27
+ subscribe(eventName: string, handler: SubscriberFn): void;
28
+ unsubscribe(eventName: string, handler: SubscriberFn): void;
29
+ close(): Promise<void>;
30
+ }
31
+ declare const EVENT_BUS_MODULE = "eventBus";
32
+ /**
33
+ * Meridian module definition for the Redis event bus.
34
+ *
35
+ * Register in meridian.config.ts:
36
+ * @example
37
+ * modules: [
38
+ * { resolve: "@meridianjs/event-bus-redis", options: { url: process.env.REDIS_URL } }
39
+ * ]
40
+ */
41
+ declare const RedisEventBusModule: ModuleDefinition;
42
+
43
+ export { EVENT_BUS_MODULE, RedisEventBus, type RedisEventBusOptions, RedisEventBusModule as default };
@@ -0,0 +1,43 @@
1
+ import { IEventBus, EventMessage, SubscriberFn, ModuleDefinition } from '@meridianjs/types';
2
+
3
+ interface RedisEventBusOptions {
4
+ url: string;
5
+ /** BullMQ queue name — defaults to "meridian:events" */
6
+ queueName?: string;
7
+ /** Worker concurrency — defaults to 5 */
8
+ concurrency?: number;
9
+ }
10
+ /**
11
+ * Production event bus backed by BullMQ + Redis.
12
+ *
13
+ * All events go into a single persistent BullMQ queue.
14
+ * A Worker processes jobs and fans out to all registered handlers for
15
+ * the event name — providing durable, async, at-least-once delivery.
16
+ *
17
+ * For local development use @meridianjs/event-bus-local instead.
18
+ */
19
+ declare class RedisEventBus implements IEventBus {
20
+ private queue;
21
+ private worker;
22
+ private connection;
23
+ /** event name → set of registered handlers */
24
+ private handlers;
25
+ constructor(options: RedisEventBusOptions);
26
+ emit<T>(event: EventMessage<T> | EventMessage<T>[]): Promise<void>;
27
+ subscribe(eventName: string, handler: SubscriberFn): void;
28
+ unsubscribe(eventName: string, handler: SubscriberFn): void;
29
+ close(): Promise<void>;
30
+ }
31
+ declare const EVENT_BUS_MODULE = "eventBus";
32
+ /**
33
+ * Meridian module definition for the Redis event bus.
34
+ *
35
+ * Register in meridian.config.ts:
36
+ * @example
37
+ * modules: [
38
+ * { resolve: "@meridianjs/event-bus-redis", options: { url: process.env.REDIS_URL } }
39
+ * ]
40
+ */
41
+ declare const RedisEventBusModule: ModuleDefinition;
42
+
43
+ export { EVENT_BUS_MODULE, RedisEventBus, type RedisEventBusOptions, RedisEventBusModule as default };
package/dist/index.js ADDED
@@ -0,0 +1,117 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
+ EVENT_BUS_MODULE: () => EVENT_BUS_MODULE,
34
+ RedisEventBus: () => RedisEventBus,
35
+ default: () => index_default
36
+ });
37
+ module.exports = __toCommonJS(index_exports);
38
+ var import_bullmq = require("bullmq");
39
+ var import_ioredis = __toESM(require("ioredis"));
40
+ var RedisEventBus = class {
41
+ queue;
42
+ worker;
43
+ connection;
44
+ /** event name → set of registered handlers */
45
+ handlers = /* @__PURE__ */ new Map();
46
+ constructor(options) {
47
+ const queueName = options.queueName ?? "meridian:events";
48
+ this.connection = new import_ioredis.default(options.url, {
49
+ maxRetriesPerRequest: null
50
+ });
51
+ this.queue = new import_bullmq.Queue(queueName, {
52
+ connection: this.connection,
53
+ defaultJobOptions: {
54
+ attempts: 3,
55
+ backoff: { type: "exponential", delay: 1e3 },
56
+ removeOnComplete: { count: 1e3 },
57
+ removeOnFail: { count: 500 }
58
+ }
59
+ });
60
+ this.worker = new import_bullmq.Worker(
61
+ queueName,
62
+ async (job) => {
63
+ const eventMsg = job.data;
64
+ const handlers = this.handlers.get(eventMsg.name);
65
+ if (!handlers || handlers.size === 0) return;
66
+ await Promise.all(
67
+ [...handlers].map(
68
+ (handler) => handler({ event: eventMsg, container: null }).catch((err) => {
69
+ console.error(
70
+ `[RedisEventBus] Unhandled error in subscriber for "${eventMsg.name}":`,
71
+ err
72
+ );
73
+ })
74
+ )
75
+ );
76
+ },
77
+ {
78
+ connection: this.connection,
79
+ concurrency: options.concurrency ?? 5
80
+ }
81
+ );
82
+ this.worker.on("error", (err) => {
83
+ console.error("[RedisEventBus] Worker error:", err);
84
+ });
85
+ }
86
+ async emit(event) {
87
+ const events = Array.isArray(event) ? event : [event];
88
+ await Promise.all(
89
+ events.map((e) => this.queue.add(e.name, e))
90
+ );
91
+ }
92
+ subscribe(eventName, handler) {
93
+ if (!this.handlers.has(eventName)) {
94
+ this.handlers.set(eventName, /* @__PURE__ */ new Set());
95
+ }
96
+ this.handlers.get(eventName).add(handler);
97
+ }
98
+ unsubscribe(eventName, handler) {
99
+ this.handlers.get(eventName)?.delete(handler);
100
+ }
101
+ async close() {
102
+ await this.worker.close();
103
+ await this.queue.close();
104
+ await this.connection.quit();
105
+ }
106
+ };
107
+ var EVENT_BUS_MODULE = "eventBus";
108
+ var RedisEventBusModule = {
109
+ key: EVENT_BUS_MODULE,
110
+ service: RedisEventBus
111
+ };
112
+ var index_default = RedisEventBusModule;
113
+ // Annotate the CommonJS export names for ESM import in node:
114
+ 0 && (module.exports = {
115
+ EVENT_BUS_MODULE,
116
+ RedisEventBus
117
+ });
package/dist/index.mjs ADDED
@@ -0,0 +1,81 @@
1
+ // src/index.ts
2
+ import { Queue, Worker } from "bullmq";
3
+ import IORedis from "ioredis";
4
+ var RedisEventBus = class {
5
+ queue;
6
+ worker;
7
+ connection;
8
+ /** event name → set of registered handlers */
9
+ handlers = /* @__PURE__ */ new Map();
10
+ constructor(options) {
11
+ const queueName = options.queueName ?? "meridian:events";
12
+ this.connection = new IORedis(options.url, {
13
+ maxRetriesPerRequest: null
14
+ });
15
+ this.queue = new Queue(queueName, {
16
+ connection: this.connection,
17
+ defaultJobOptions: {
18
+ attempts: 3,
19
+ backoff: { type: "exponential", delay: 1e3 },
20
+ removeOnComplete: { count: 1e3 },
21
+ removeOnFail: { count: 500 }
22
+ }
23
+ });
24
+ this.worker = new Worker(
25
+ queueName,
26
+ async (job) => {
27
+ const eventMsg = job.data;
28
+ const handlers = this.handlers.get(eventMsg.name);
29
+ if (!handlers || handlers.size === 0) return;
30
+ await Promise.all(
31
+ [...handlers].map(
32
+ (handler) => handler({ event: eventMsg, container: null }).catch((err) => {
33
+ console.error(
34
+ `[RedisEventBus] Unhandled error in subscriber for "${eventMsg.name}":`,
35
+ err
36
+ );
37
+ })
38
+ )
39
+ );
40
+ },
41
+ {
42
+ connection: this.connection,
43
+ concurrency: options.concurrency ?? 5
44
+ }
45
+ );
46
+ this.worker.on("error", (err) => {
47
+ console.error("[RedisEventBus] Worker error:", err);
48
+ });
49
+ }
50
+ async emit(event) {
51
+ const events = Array.isArray(event) ? event : [event];
52
+ await Promise.all(
53
+ events.map((e) => this.queue.add(e.name, e))
54
+ );
55
+ }
56
+ subscribe(eventName, handler) {
57
+ if (!this.handlers.has(eventName)) {
58
+ this.handlers.set(eventName, /* @__PURE__ */ new Set());
59
+ }
60
+ this.handlers.get(eventName).add(handler);
61
+ }
62
+ unsubscribe(eventName, handler) {
63
+ this.handlers.get(eventName)?.delete(handler);
64
+ }
65
+ async close() {
66
+ await this.worker.close();
67
+ await this.queue.close();
68
+ await this.connection.quit();
69
+ }
70
+ };
71
+ var EVENT_BUS_MODULE = "eventBus";
72
+ var RedisEventBusModule = {
73
+ key: EVENT_BUS_MODULE,
74
+ service: RedisEventBus
75
+ };
76
+ var index_default = RedisEventBusModule;
77
+ export {
78
+ EVENT_BUS_MODULE,
79
+ RedisEventBus,
80
+ index_default as default
81
+ };
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "@meridianjs/event-bus-redis",
3
+ "version": "0.1.0",
4
+ "description": "Meridian Redis event bus — BullMQ-backed IEventBus for production",
5
+ "main": "./dist/index.js",
6
+ "module": "./dist/index.mjs",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "import": {
11
+ "types": "./dist/index.d.mts",
12
+ "default": "./dist/index.mjs"
13
+ },
14
+ "require": {
15
+ "types": "./dist/index.d.ts",
16
+ "default": "./dist/index.js"
17
+ }
18
+ }
19
+ },
20
+ "scripts": {
21
+ "build": "tsup src/index.ts --format esm,cjs --dts --clean",
22
+ "dev": "tsup src/index.ts --format esm,cjs --dts --watch",
23
+ "typecheck": "tsc --noEmit",
24
+ "clean": "rm -rf dist",
25
+ "prepublishOnly": "npm run build"
26
+ },
27
+ "dependencies": {
28
+ "@meridianjs/types": "^0.1.0",
29
+ "bullmq": "^5.0.0",
30
+ "ioredis": "^5.3.2"
31
+ },
32
+ "devDependencies": {
33
+ "tsup": "^8.3.5",
34
+ "typescript": "*"
35
+ },
36
+ "files": [
37
+ "dist"
38
+ ],
39
+ "publishConfig": {
40
+ "access": "public"
41
+ }
42
+ }