@autonomaai/event-bus 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,11 @@
1
+ import { DomainEvent, DomainEventName, EventBus } from './types';
2
+ export declare class RedisEventBus implements EventBus {
3
+ private publisher;
4
+ private subscribers;
5
+ private isClosing;
6
+ constructor(redisUrl: string);
7
+ publish<E extends DomainEvent>(topic: DomainEventName, event: E): Promise<void>;
8
+ subscribe<E extends DomainEvent>(topic: DomainEventName, group: string, consumer: string, handler: (event: E) => Promise<void>): Promise<() => Promise<void>>;
9
+ close(): Promise<void>;
10
+ }
11
+ //# sourceMappingURL=RedisEventBus.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RedisEventBus.d.ts","sourceRoot":"","sources":["../src/RedisEventBus.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEjE,qBAAa,aAAc,YAAW,QAAQ;IAC5C,OAAO,CAAC,SAAS,CAAQ;IACzB,OAAO,CAAC,WAAW,CAAiC;IACpD,OAAO,CAAC,SAAS,CAAS;gBAEd,QAAQ,EAAE,MAAM;IAItB,OAAO,CAAC,CAAC,SAAS,WAAW,EAAE,KAAK,EAAE,eAAe,EAAE,KAAK,EAAE,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAK/E,SAAS,CAAC,CAAC,SAAS,WAAW,EACnC,KAAK,EAAE,eAAe,EACtB,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,GACnC,OAAO,CAAC,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IA2EzB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAQ7B"}
@@ -0,0 +1,92 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.RedisEventBus = void 0;
7
+ const ioredis_1 = __importDefault(require("ioredis"));
8
+ class RedisEventBus {
9
+ publisher;
10
+ subscribers = new Map();
11
+ isClosing = false;
12
+ constructor(redisUrl) {
13
+ this.publisher = new ioredis_1.default(redisUrl);
14
+ }
15
+ async publish(topic, event) {
16
+ const message = JSON.stringify(event);
17
+ await this.publisher.xadd(topic, '*', 'event', message);
18
+ }
19
+ async subscribe(topic, group, consumer, handler) {
20
+ // Create a dedicated connection for this subscription to avoid blocking
21
+ // In a real app, we might pool these or use a single connection with a loop,
22
+ // but for simplicity and robustness in Stage 1, we'll use a loop on a dedicated connection per consumer type if needed,
23
+ // or just reuse a connection if we are careful.
24
+ // Actually, for XREADGROUP, we can share a connection if we are careful, but blocking calls (BLOCK) block the connection.
25
+ // So we need a dedicated connection for the blocking loop.
26
+ const redis = this.publisher.duplicate();
27
+ this.subscribers.set(`${topic}-${group}-${consumer}`, redis);
28
+ // Ensure group exists
29
+ try {
30
+ await redis.xgroup('CREATE', topic, group, '$', 'MKSTREAM');
31
+ }
32
+ catch (err) {
33
+ if (!err.message.includes('BUSYGROUP')) {
34
+ throw err;
35
+ }
36
+ }
37
+ let isRunning = true;
38
+ const loop = async () => {
39
+ while (isRunning && !this.isClosing) {
40
+ try {
41
+ // Read new messages
42
+ const results = await redis.xreadgroup('GROUP', group, consumer, 'BLOCK', 2000, // 2 seconds block
43
+ 'STREAMS', topic, '>');
44
+ if (results) {
45
+ for (const [_stream, messages] of results) {
46
+ for (const [id, fields] of messages) {
47
+ // fields is ['event', '{"json":...}']
48
+ const eventData = fields[1];
49
+ if (eventData) {
50
+ try {
51
+ const event = JSON.parse(eventData);
52
+ await handler(event);
53
+ await redis.xack(topic, group, id);
54
+ }
55
+ catch (error) {
56
+ console.error(`Error processing event ${id} from ${topic}:`, error);
57
+ // In a real system, we might move to a DLQ here
58
+ }
59
+ }
60
+ }
61
+ }
62
+ }
63
+ }
64
+ catch (error) {
65
+ if (this.isClosing)
66
+ break;
67
+ console.error(`Error in subscription loop for ${topic}:`, error);
68
+ // Wait a bit before retrying to avoid tight loops on error
69
+ await new Promise((resolve) => setTimeout(resolve, 1000));
70
+ }
71
+ }
72
+ };
73
+ // Start the loop
74
+ loop();
75
+ // Return unsubscribe function
76
+ return async () => {
77
+ isRunning = false;
78
+ this.subscribers.delete(`${topic}-${group}-${consumer}`);
79
+ await redis.quit();
80
+ };
81
+ }
82
+ async close() {
83
+ this.isClosing = true;
84
+ await this.publisher.quit();
85
+ for (const redis of this.subscribers.values()) {
86
+ await redis.quit();
87
+ }
88
+ this.subscribers.clear();
89
+ }
90
+ }
91
+ exports.RedisEventBus = RedisEventBus;
92
+ //# sourceMappingURL=RedisEventBus.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RedisEventBus.js","sourceRoot":"","sources":["../src/RedisEventBus.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export * from './types';
2
+ export * from './RedisEventBus';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,cAAc,iBAAiB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,19 @@
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("./types"), exports);
18
+ __exportStar(require("./RedisEventBus"), exports);
19
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,0CAAwB;AACxB,kDAAgC"}
@@ -0,0 +1,15 @@
1
+ export type DomainEventName = 'trade.executed' | 'strategy.updated' | 'risk.alert' | 'portfolio.snapshot.created' | 'market.tick' | 'signal.created' | 'agent.message.created';
2
+ export interface DomainEvent<TPayload = any> {
3
+ id: string;
4
+ name: DomainEventName;
5
+ version: number;
6
+ timestamp: string;
7
+ source: string;
8
+ payload: TPayload;
9
+ }
10
+ export interface EventBus {
11
+ publish<E extends DomainEvent>(topic: DomainEventName, event: E): Promise<void>;
12
+ subscribe<E extends DomainEvent>(topic: DomainEventName, group: string, consumer: string, handler: (event: E) => Promise<void>): Promise<() => Promise<void>>;
13
+ close(): Promise<void>;
14
+ }
15
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,eAAe,GACvB,gBAAgB,GAChB,kBAAkB,GAClB,YAAY,GACZ,4BAA4B,GAC5B,aAAa,GACb,gBAAgB,GAChB,uBAAuB,CAAC;AAE5B,MAAM,WAAW,WAAW,CAAC,QAAQ,GAAG,GAAG;IACzC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,eAAe,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,QAAQ,CAAC;CACnB;AAED,MAAM,WAAW,QAAQ;IACvB,OAAO,CAAC,CAAC,SAAS,WAAW,EAC3B,KAAK,EAAE,eAAe,EACtB,KAAK,EAAE,CAAC,GACP,OAAO,CAAC,IAAI,CAAC,CAAC;IAEjB,SAAS,CAAC,CAAC,SAAS,WAAW,EAC7B,KAAK,EAAE,eAAe,EACtB,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,GACnC,OAAO,CAAC,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;IAEhC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB"}
package/dist/types.js ADDED
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
package/package.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "@autonomaai/event-bus",
3
+ "version": "1.0.0",
4
+ "description": "Shared event bus abstraction and implementations for autonoma microservices",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "scripts": {
8
+ "build": "tsc",
9
+ "dev": "tsc --watch",
10
+ "test": "jest",
11
+ "lint": "eslint src/**/*.ts"
12
+ },
13
+ "keywords": [
14
+ "event-bus",
15
+ "redis",
16
+ "microservices",
17
+ "messaging"
18
+ ],
19
+ "author": "autonoma Team",
20
+ "license": "MIT",
21
+ "files": [
22
+ "dist/**/*",
23
+ "README.md"
24
+ ],
25
+ "repository": {
26
+ "type": "git",
27
+ "url": "https://github.com/Stack3Labs/autonoma-typescript-packages"
28
+ },
29
+ "publishConfig": {
30
+ "access": "public"
31
+ },
32
+ "dependencies": {
33
+ "ioredis": "^5.3.2",
34
+ "uuid": "^9.0.1"
35
+ },
36
+ "devDependencies": {
37
+ "@types/node": "^20.11.0",
38
+ "@types/uuid": "^9.0.8",
39
+ "typescript": "^5.3.3"
40
+ }
41
+ }