conduithub 0.1.0 → 1.0.1

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 (83) hide show
  1. package/dist/core/conduit-hub/index.cjs +188 -0
  2. package/dist/core/conduit-hub/index.d.cts +44 -0
  3. package/dist/core/conduit-hub/index.d.mts +44 -0
  4. package/dist/core/conduit-hub/index.d.ts +44 -0
  5. package/dist/core/conduit-hub/index.mjs +186 -0
  6. package/dist/core/config-manager/index.cjs +216 -0
  7. package/dist/core/config-manager/index.d.cts +7 -0
  8. package/dist/core/config-manager/index.d.mts +7 -0
  9. package/dist/core/config-manager/index.d.ts +7 -0
  10. package/dist/core/config-manager/index.mjs +214 -0
  11. package/dist/core/event-bus/index.cjs +154 -53
  12. package/dist/core/event-bus/index.d.cts +2 -42
  13. package/dist/core/event-bus/index.d.mts +2 -42
  14. package/dist/core/event-bus/index.d.ts +2 -42
  15. package/dist/core/event-bus/index.mjs +153 -52
  16. package/dist/core/hook/index.cjs +185 -148
  17. package/dist/core/hook/index.d.cts +28 -16
  18. package/dist/core/hook/index.d.mts +28 -16
  19. package/dist/core/hook/index.d.ts +28 -16
  20. package/dist/core/hook/index.mjs +183 -146
  21. package/dist/core/index.cjs +17 -1
  22. package/dist/core/index.d.cts +184 -3
  23. package/dist/core/index.d.mts +184 -3
  24. package/dist/core/index.d.ts +184 -3
  25. package/dist/core/index.mjs +12 -1
  26. package/dist/core/plugin/index.cjs +271 -0
  27. package/dist/core/plugin/index.d.cts +7 -0
  28. package/dist/core/plugin/index.d.mts +7 -0
  29. package/dist/core/plugin/index.d.ts +7 -0
  30. package/dist/core/plugin/index.mjs +268 -0
  31. package/dist/core/service-container/index.cjs +306 -0
  32. package/dist/core/service-container/index.d.cts +51 -0
  33. package/dist/core/service-container/index.d.mts +51 -0
  34. package/dist/core/service-container/index.d.ts +51 -0
  35. package/dist/core/service-container/index.mjs +304 -0
  36. package/dist/core/state-manager/index.cjs +195 -0
  37. package/dist/core/state-manager/index.d.cts +39 -0
  38. package/dist/core/state-manager/index.d.mts +39 -0
  39. package/dist/core/state-manager/index.d.ts +39 -0
  40. package/dist/core/state-manager/index.mjs +193 -0
  41. package/dist/error/index.cjs +71 -0
  42. package/dist/error/index.d.cts +47 -0
  43. package/dist/error/index.d.mts +47 -0
  44. package/dist/error/index.d.ts +47 -0
  45. package/dist/error/index.mjs +65 -0
  46. package/dist/index.cjs +38 -5
  47. package/dist/index.d.cts +8 -2
  48. package/dist/index.d.mts +8 -2
  49. package/dist/index.d.ts +8 -2
  50. package/dist/index.mjs +16 -1
  51. package/dist/plugins/index.cjs +12 -0
  52. package/dist/plugins/index.d.cts +8 -0
  53. package/dist/plugins/index.d.mts +8 -0
  54. package/dist/plugins/index.d.ts +8 -0
  55. package/dist/plugins/index.mjs +6 -0
  56. package/dist/plugins/redis/index.cjs +12 -0
  57. package/dist/plugins/redis/index.d.cts +109 -0
  58. package/dist/plugins/redis/index.d.mts +109 -0
  59. package/dist/plugins/redis/index.d.ts +109 -0
  60. package/dist/plugins/redis/index.mjs +6 -0
  61. package/dist/shared/conduithub.-bZD30_I.mjs +769 -0
  62. package/dist/shared/{conduithub.CvMLTa-R.cjs → conduithub.BNQsddJO.cjs} +2 -9
  63. package/dist/shared/{conduithub.74V0wiLi.mjs → conduithub.BNefRQsK.mjs} +3 -9
  64. package/dist/shared/conduithub.BZQmkQy7.d.cts +52 -0
  65. package/dist/shared/conduithub.Bq_7Xj0J.cjs +18 -0
  66. package/dist/shared/conduithub.BzLwccre.d.mts +52 -0
  67. package/dist/shared/conduithub.CkOQG3cD.mjs +14 -0
  68. package/dist/shared/conduithub.CmZo_Vuc.cjs +38 -0
  69. package/dist/shared/conduithub.DQO1dRnn.cjs +33 -0
  70. package/dist/shared/conduithub.DQOWQ-Bx.d.ts +52 -0
  71. package/dist/shared/conduithub.Dlvl2xGE.cjs +76 -0
  72. package/dist/shared/conduithub.DsOOeNwU.cjs +269 -0
  73. package/dist/shared/conduithub.DyQQrHW9.mjs +267 -0
  74. package/dist/shared/conduithub.G7ICpZIy.mjs +36 -0
  75. package/dist/shared/conduithub.Up0QYVao.mjs +59 -0
  76. package/dist/shared/conduithub.alPiaJax.mjs +29 -0
  77. package/dist/shared/conduithub.cvEjE62V.cjs +775 -0
  78. package/dist/utils/index.cjs +19 -5
  79. package/dist/utils/index.d.cts +33 -2
  80. package/dist/utils/index.d.mts +33 -2
  81. package/dist/utils/index.d.ts +33 -2
  82. package/dist/utils/index.mjs +8 -1
  83. package/package.json +55 -7
@@ -1,17 +1,62 @@
1
1
  'use strict';
2
2
 
3
- const uuid = require('../../shared/conduithub.CvMLTa-R.cjs');
3
+ const error_index = require('../../error/index.cjs');
4
+ const logger = require('../../shared/conduithub.BNQsddJO.cjs');
5
+ require('process');
6
+ require('readline');
7
+ const uuid = require('../../shared/conduithub.Bq_7Xj0J.cjs');
8
+ const code = require('../../shared/conduithub.CmZo_Vuc.cjs');
4
9
  require('uuid');
5
10
 
6
11
  class EventBus {
7
12
  handlers = {};
13
+ locks = /* @__PURE__ */ new Map();
8
14
  initialized = false;
9
15
  logger;
16
+ maxHandlersPerEvent;
17
+ handlerTimeoutMs;
18
+ onError;
10
19
  constructor(options) {
11
- this.logger = uuid.createLogger(options?.logger);
20
+ this.logger = logger.createLogger(options?.logger);
21
+ this.maxHandlersPerEvent = options?.maxHandlersPerEvent ?? 100;
22
+ this.handlerTimeoutMs = options?.handlerTimeoutMs ?? 5e3;
23
+ this.onError = options?.onError;
24
+ }
25
+ async withEventLock(type, operation) {
26
+ const currentLock = this.locks.get(type) ?? Promise.resolve();
27
+ let resolveLock;
28
+ const newLock = new Promise((resolve) => {
29
+ resolveLock = resolve;
30
+ });
31
+ this.locks.set(
32
+ type,
33
+ currentLock.then(() => newLock)
34
+ );
35
+ await currentLock;
36
+ try {
37
+ return await operation();
38
+ } finally {
39
+ resolveLock();
40
+ }
12
41
  }
13
42
  ensureInitialized() {
14
- if (!this.initialized) throw new Error("EventBus is not initialized");
43
+ if (!this.initialized) {
44
+ throw new error_index.ConduithubError(code.ERROR_CODE.EVENT_BUS_NOT_INITIALIZED);
45
+ }
46
+ }
47
+ sanitizeLog(data) {
48
+ if (typeof data === "string") {
49
+ return data.length > 100 ? `${data.substring(0, 100)}...` : data;
50
+ }
51
+ if (typeof data === "object" && data !== null) {
52
+ try {
53
+ const json = JSON.stringify(data);
54
+ return json.length > 100 ? `${json.substring(0, 100)}...` : json;
55
+ } catch {
56
+ return "[Unserializable Object]";
57
+ }
58
+ }
59
+ return String(data);
15
60
  }
16
61
  async initialize() {
17
62
  if (this.initialized) return;
@@ -20,73 +65,125 @@ class EventBus {
20
65
  }
21
66
  async shutdown() {
22
67
  this.ensureInitialized();
23
- this.handlers = {};
68
+ const totalHandlers = this.getTotalHandlerCount();
69
+ this.clearAllHandlers();
24
70
  this.initialized = false;
25
- this.logger.success("EventBus system shutdown completed");
71
+ this.logger.success(
72
+ `EventBus system shutdown completed - cleared ${totalHandlers} handlers`
73
+ );
74
+ }
75
+ getTotalHandlerCount() {
76
+ return Object.values(this.handlers).reduce(
77
+ (sum, list) => sum + (list?.length ?? 0),
78
+ 0
79
+ );
80
+ }
81
+ clearAllHandlers() {
82
+ for (const key in this.handlers) {
83
+ delete this.handlers[key];
84
+ }
26
85
  }
27
- on(type, handler) {
86
+ on(type, handler, priority = 0, customId) {
28
87
  this.ensureInitialized();
29
- const id = uuid.generateUuid();
30
- const record = {
31
- id,
32
- handler,
33
- once: false
34
- };
35
- (this.handlers[type] ??= []).push(record);
36
- this.logger.debug(`Event handler registered: '${String(type)}' \u2192 ${id}`);
37
- return id;
88
+ return this.registerHandler(type, handler, false, priority, customId);
38
89
  }
39
- once(type, handler) {
90
+ once(type, handler, priority = 0, customId) {
40
91
  this.ensureInitialized();
41
- const id = uuid.generateUuid();
92
+ return this.registerHandler(type, handler, true, priority, customId);
93
+ }
94
+ registerHandler(type, handler, once, priority, customId) {
95
+ const list = this.handlers[type] ??= [];
96
+ if (list.length >= this.maxHandlersPerEvent) {
97
+ throw new error_index.ConduithubError(
98
+ `${code.ERROR_CODE.EVENT_HANDLER_LIMIT_EXCEEDED} ${String(type)} (${this.maxHandlersPerEvent})`
99
+ );
100
+ }
101
+ const id = customId ?? uuid.generateUuid();
102
+ if (customId && list.some((h) => h.id === customId)) {
103
+ throw new error_index.ConduithubError(
104
+ `${code.ERROR_CODE.DUPLICATE_EVENT_HANDLER_ID} ${String(type)}: ${customId}`
105
+ );
106
+ }
42
107
  const record = {
43
108
  id,
44
109
  handler,
45
- once: true
110
+ once,
111
+ priority
46
112
  };
47
- (this.handlers[type] ??= []).push(record);
113
+ list.push(record);
114
+ const handlerType = once ? "One-time event handler" : "Event handler";
48
115
  this.logger.debug(
49
- `One-time event handler registered: '${String(type)}' \u2192 ${id}`
116
+ `${handlerType} registered: '${String(type)}' \u2192 ${id} (priority: ${priority})`
50
117
  );
51
118
  return id;
52
119
  }
53
120
  off(type, id) {
54
121
  this.ensureInitialized();
55
122
  const list = this.handlers[type];
56
- if (!list) return;
123
+ if (!list) {
124
+ this.logger.debug(`No handlers found for event: '${String(type)}'`);
125
+ return;
126
+ }
57
127
  if (!id) {
58
128
  delete this.handlers[type];
59
129
  this.logger.debug(`All event handlers removed for: '${String(type)}'`);
60
130
  return;
61
131
  }
62
132
  const index = list.findIndex((h) => h.id === id);
63
- if (index !== -1) {
64
- list.splice(index, 1);
65
- this.logger.debug(`Event handler removed: '${String(type)}' \u2192 ${id}`);
66
- if (list.length === 0) delete this.handlers[type];
133
+ if (index === -1) {
134
+ this.logger.warn(`Handler not found: '${String(type)}' \u2192 ${id}`);
135
+ return;
136
+ }
137
+ list.splice(index, 1);
138
+ this.logger.debug(`Event handler removed: '${String(type)}' \u2192 ${id}`);
139
+ if (list.length === 0) {
140
+ delete this.handlers[type];
67
141
  }
68
142
  }
69
- async emit(type, payload, source = "event-bus") {
70
- this.ensureInitialized();
71
- const list = this.handlers[type];
72
- if (!list?.length) return;
73
- const event = {
74
- type,
75
- payload,
76
- timestamp: Date.now(),
77
- source
78
- };
79
- for (const { id, handler, once } of [...list]) {
80
- try {
81
- await handler(event);
82
- if (once) this.off(type, id);
83
- } catch (err) {
84
- this.logger.error(
85
- `Event handler execution failed: '${String(type)}' \u2192 ${id}`,
86
- err
87
- );
143
+ async emit(type, payload, source = "event-bus", context) {
144
+ await this.withEventLock(type, async () => {
145
+ this.ensureInitialized();
146
+ const list = this.handlers[type];
147
+ if (!list?.length) {
148
+ this.logger.debug(`No handlers for event: '${String(type)}'`);
149
+ return;
88
150
  }
89
- }
151
+ const sortedList = [...list].sort((a, b) => b.priority - a.priority);
152
+ const event = {
153
+ type,
154
+ payload,
155
+ timestamp: Date.now(),
156
+ source,
157
+ context
158
+ };
159
+ let successCount = 0;
160
+ let errorCount = 0;
161
+ for (const { id, handler, once } of sortedList) {
162
+ try {
163
+ await Promise.race([
164
+ Promise.resolve(handler(event, context)),
165
+ new Promise(
166
+ (_, reject) => setTimeout(
167
+ () => reject(new Error("Handler timeout")),
168
+ this.handlerTimeoutMs
169
+ )
170
+ )
171
+ ]);
172
+ successCount++;
173
+ if (once) this.off(type, id);
174
+ } catch (err) {
175
+ errorCount++;
176
+ const errorMessage = err instanceof Error ? err.message : String(err);
177
+ this.logger.error(
178
+ `Event handler execution failed: '${String(type)}' \u2192 ${id} - ${this.sanitizeLog(errorMessage)}`
179
+ );
180
+ this.onError?.(err, type);
181
+ }
182
+ }
183
+ this.logger.debug(
184
+ `Event emitted: '${String(type)}' (${successCount} succeeded, ${errorCount} failed)`
185
+ );
186
+ });
90
187
  }
91
188
  removeAllListeners(type) {
92
189
  this.ensureInitialized();
@@ -96,7 +193,7 @@ class EventBus {
96
193
  `All listeners removed for event type: '${String(type)}'`
97
194
  );
98
195
  } else {
99
- this.handlers = {};
196
+ this.clearAllHandlers();
100
197
  this.logger.debug("All event listeners cleared from EventBus");
101
198
  }
102
199
  }
@@ -107,15 +204,19 @@ class EventBus {
107
204
  return Object.keys(this.handlers);
108
205
  }
109
206
  getStats() {
110
- const names = this.eventNames();
111
- const countMap = Object.fromEntries(
112
- names.map((name) => [name, this.listenerCount(name)])
207
+ const eventNames = this.eventNames();
208
+ const listenerCount = Object.fromEntries(
209
+ eventNames.map((name) => [name, this.listenerCount(name)])
210
+ );
211
+ const totalListeners = Object.values(listenerCount).reduce(
212
+ (sum, count) => sum + count,
213
+ 0
113
214
  );
114
215
  return {
115
- totalEvents: names.length,
116
- totalListeners: Object.values(countMap).reduce((a, b) => a + b, 0),
117
- eventNames: names,
118
- listenerCount: countMap
216
+ totalEvents: eventNames.length,
217
+ totalListeners,
218
+ eventNames,
219
+ listenerCount
119
220
  };
120
221
  }
121
222
  get isInitialized() {
@@ -1,42 +1,2 @@
1
- import { a as Logger } from '../../shared/conduithub.B7aryjPG.cjs';
2
-
3
- interface EventData<K extends string, P> {
4
- type: K;
5
- payload: P;
6
- timestamp: number;
7
- source: string;
8
- }
9
- interface EventHandlerRecord<K extends string, P> {
10
- id: string;
11
- once: boolean;
12
- handler: (event: EventData<K, P>) => Promise<void> | void;
13
- }
14
-
15
- declare class EventBus<EM extends Record<string, unknown>> {
16
- private handlers;
17
- private initialized;
18
- private logger;
19
- constructor(options?: {
20
- logger?: Logger;
21
- });
22
- private ensureInitialized;
23
- initialize(): Promise<void>;
24
- shutdown(): Promise<void>;
25
- on<K extends keyof EM>(type: K, handler: (event: EventData<K & string, EM[K]>) => Promise<void> | void): string;
26
- once<K extends keyof EM>(type: K, handler: (event: EventData<K & string, EM[K]>) => Promise<void> | void): string;
27
- off<K extends keyof EM>(type: K, id?: string): void;
28
- emit<K extends keyof EM>(type: K, payload: EM[K], source?: string): Promise<void>;
29
- removeAllListeners<K extends keyof EM>(type?: K): void;
30
- listenerCount<K extends keyof EM>(type: K): number;
31
- eventNames(): Array<keyof EM>;
32
- getStats(): {
33
- totalEvents: number;
34
- totalListeners: number;
35
- eventNames: (keyof EM)[];
36
- listenerCount: Record<keyof EM, number>;
37
- };
38
- get isInitialized(): boolean;
39
- }
40
-
41
- export { EventBus };
42
- export type { EventData, EventHandlerRecord };
1
+ import '../../shared/conduithub.B7aryjPG.cjs';
2
+ export { E as EventBus } from '../../shared/conduithub.BZQmkQy7.cjs';
@@ -1,42 +1,2 @@
1
- import { a as Logger } from '../../shared/conduithub.B7aryjPG.mjs';
2
-
3
- interface EventData<K extends string, P> {
4
- type: K;
5
- payload: P;
6
- timestamp: number;
7
- source: string;
8
- }
9
- interface EventHandlerRecord<K extends string, P> {
10
- id: string;
11
- once: boolean;
12
- handler: (event: EventData<K, P>) => Promise<void> | void;
13
- }
14
-
15
- declare class EventBus<EM extends Record<string, unknown>> {
16
- private handlers;
17
- private initialized;
18
- private logger;
19
- constructor(options?: {
20
- logger?: Logger;
21
- });
22
- private ensureInitialized;
23
- initialize(): Promise<void>;
24
- shutdown(): Promise<void>;
25
- on<K extends keyof EM>(type: K, handler: (event: EventData<K & string, EM[K]>) => Promise<void> | void): string;
26
- once<K extends keyof EM>(type: K, handler: (event: EventData<K & string, EM[K]>) => Promise<void> | void): string;
27
- off<K extends keyof EM>(type: K, id?: string): void;
28
- emit<K extends keyof EM>(type: K, payload: EM[K], source?: string): Promise<void>;
29
- removeAllListeners<K extends keyof EM>(type?: K): void;
30
- listenerCount<K extends keyof EM>(type: K): number;
31
- eventNames(): Array<keyof EM>;
32
- getStats(): {
33
- totalEvents: number;
34
- totalListeners: number;
35
- eventNames: (keyof EM)[];
36
- listenerCount: Record<keyof EM, number>;
37
- };
38
- get isInitialized(): boolean;
39
- }
40
-
41
- export { EventBus };
42
- export type { EventData, EventHandlerRecord };
1
+ import '../../shared/conduithub.B7aryjPG.mjs';
2
+ export { E as EventBus } from '../../shared/conduithub.BzLwccre.mjs';
@@ -1,42 +1,2 @@
1
- import { a as Logger } from '../../shared/conduithub.B7aryjPG.js';
2
-
3
- interface EventData<K extends string, P> {
4
- type: K;
5
- payload: P;
6
- timestamp: number;
7
- source: string;
8
- }
9
- interface EventHandlerRecord<K extends string, P> {
10
- id: string;
11
- once: boolean;
12
- handler: (event: EventData<K, P>) => Promise<void> | void;
13
- }
14
-
15
- declare class EventBus<EM extends Record<string, unknown>> {
16
- private handlers;
17
- private initialized;
18
- private logger;
19
- constructor(options?: {
20
- logger?: Logger;
21
- });
22
- private ensureInitialized;
23
- initialize(): Promise<void>;
24
- shutdown(): Promise<void>;
25
- on<K extends keyof EM>(type: K, handler: (event: EventData<K & string, EM[K]>) => Promise<void> | void): string;
26
- once<K extends keyof EM>(type: K, handler: (event: EventData<K & string, EM[K]>) => Promise<void> | void): string;
27
- off<K extends keyof EM>(type: K, id?: string): void;
28
- emit<K extends keyof EM>(type: K, payload: EM[K], source?: string): Promise<void>;
29
- removeAllListeners<K extends keyof EM>(type?: K): void;
30
- listenerCount<K extends keyof EM>(type: K): number;
31
- eventNames(): Array<keyof EM>;
32
- getStats(): {
33
- totalEvents: number;
34
- totalListeners: number;
35
- eventNames: (keyof EM)[];
36
- listenerCount: Record<keyof EM, number>;
37
- };
38
- get isInitialized(): boolean;
39
- }
40
-
41
- export { EventBus };
42
- export type { EventData, EventHandlerRecord };
1
+ import '../../shared/conduithub.B7aryjPG.js';
2
+ export { E as EventBus } from '../../shared/conduithub.DQOWQ-Bx.js';
@@ -1,15 +1,60 @@
1
- import { c as createLogger, g as generateUuid } from '../../shared/conduithub.74V0wiLi.mjs';
1
+ import { ConduithubError } from '../../error/index.mjs';
2
+ import { c as createLogger } from '../../shared/conduithub.BNefRQsK.mjs';
3
+ import 'process';
4
+ import 'readline';
5
+ import { g as generateUuid } from '../../shared/conduithub.CkOQG3cD.mjs';
6
+ import { E as ERROR_CODE } from '../../shared/conduithub.G7ICpZIy.mjs';
2
7
  import 'uuid';
3
8
 
4
9
  class EventBus {
5
10
  handlers = {};
11
+ locks = /* @__PURE__ */ new Map();
6
12
  initialized = false;
7
13
  logger;
14
+ maxHandlersPerEvent;
15
+ handlerTimeoutMs;
16
+ onError;
8
17
  constructor(options) {
9
18
  this.logger = createLogger(options?.logger);
19
+ this.maxHandlersPerEvent = options?.maxHandlersPerEvent ?? 100;
20
+ this.handlerTimeoutMs = options?.handlerTimeoutMs ?? 5e3;
21
+ this.onError = options?.onError;
22
+ }
23
+ async withEventLock(type, operation) {
24
+ const currentLock = this.locks.get(type) ?? Promise.resolve();
25
+ let resolveLock;
26
+ const newLock = new Promise((resolve) => {
27
+ resolveLock = resolve;
28
+ });
29
+ this.locks.set(
30
+ type,
31
+ currentLock.then(() => newLock)
32
+ );
33
+ await currentLock;
34
+ try {
35
+ return await operation();
36
+ } finally {
37
+ resolveLock();
38
+ }
10
39
  }
11
40
  ensureInitialized() {
12
- if (!this.initialized) throw new Error("EventBus is not initialized");
41
+ if (!this.initialized) {
42
+ throw new ConduithubError(ERROR_CODE.EVENT_BUS_NOT_INITIALIZED);
43
+ }
44
+ }
45
+ sanitizeLog(data) {
46
+ if (typeof data === "string") {
47
+ return data.length > 100 ? `${data.substring(0, 100)}...` : data;
48
+ }
49
+ if (typeof data === "object" && data !== null) {
50
+ try {
51
+ const json = JSON.stringify(data);
52
+ return json.length > 100 ? `${json.substring(0, 100)}...` : json;
53
+ } catch {
54
+ return "[Unserializable Object]";
55
+ }
56
+ }
57
+ return String(data);
13
58
  }
14
59
  async initialize() {
15
60
  if (this.initialized) return;
@@ -18,73 +63,125 @@ class EventBus {
18
63
  }
19
64
  async shutdown() {
20
65
  this.ensureInitialized();
21
- this.handlers = {};
66
+ const totalHandlers = this.getTotalHandlerCount();
67
+ this.clearAllHandlers();
22
68
  this.initialized = false;
23
- this.logger.success("EventBus system shutdown completed");
69
+ this.logger.success(
70
+ `EventBus system shutdown completed - cleared ${totalHandlers} handlers`
71
+ );
72
+ }
73
+ getTotalHandlerCount() {
74
+ return Object.values(this.handlers).reduce(
75
+ (sum, list) => sum + (list?.length ?? 0),
76
+ 0
77
+ );
78
+ }
79
+ clearAllHandlers() {
80
+ for (const key in this.handlers) {
81
+ delete this.handlers[key];
82
+ }
24
83
  }
25
- on(type, handler) {
84
+ on(type, handler, priority = 0, customId) {
26
85
  this.ensureInitialized();
27
- const id = generateUuid();
28
- const record = {
29
- id,
30
- handler,
31
- once: false
32
- };
33
- (this.handlers[type] ??= []).push(record);
34
- this.logger.debug(`Event handler registered: '${String(type)}' \u2192 ${id}`);
35
- return id;
86
+ return this.registerHandler(type, handler, false, priority, customId);
36
87
  }
37
- once(type, handler) {
88
+ once(type, handler, priority = 0, customId) {
38
89
  this.ensureInitialized();
39
- const id = generateUuid();
90
+ return this.registerHandler(type, handler, true, priority, customId);
91
+ }
92
+ registerHandler(type, handler, once, priority, customId) {
93
+ const list = this.handlers[type] ??= [];
94
+ if (list.length >= this.maxHandlersPerEvent) {
95
+ throw new ConduithubError(
96
+ `${ERROR_CODE.EVENT_HANDLER_LIMIT_EXCEEDED} ${String(type)} (${this.maxHandlersPerEvent})`
97
+ );
98
+ }
99
+ const id = customId ?? generateUuid();
100
+ if (customId && list.some((h) => h.id === customId)) {
101
+ throw new ConduithubError(
102
+ `${ERROR_CODE.DUPLICATE_EVENT_HANDLER_ID} ${String(type)}: ${customId}`
103
+ );
104
+ }
40
105
  const record = {
41
106
  id,
42
107
  handler,
43
- once: true
108
+ once,
109
+ priority
44
110
  };
45
- (this.handlers[type] ??= []).push(record);
111
+ list.push(record);
112
+ const handlerType = once ? "One-time event handler" : "Event handler";
46
113
  this.logger.debug(
47
- `One-time event handler registered: '${String(type)}' \u2192 ${id}`
114
+ `${handlerType} registered: '${String(type)}' \u2192 ${id} (priority: ${priority})`
48
115
  );
49
116
  return id;
50
117
  }
51
118
  off(type, id) {
52
119
  this.ensureInitialized();
53
120
  const list = this.handlers[type];
54
- if (!list) return;
121
+ if (!list) {
122
+ this.logger.debug(`No handlers found for event: '${String(type)}'`);
123
+ return;
124
+ }
55
125
  if (!id) {
56
126
  delete this.handlers[type];
57
127
  this.logger.debug(`All event handlers removed for: '${String(type)}'`);
58
128
  return;
59
129
  }
60
130
  const index = list.findIndex((h) => h.id === id);
61
- if (index !== -1) {
62
- list.splice(index, 1);
63
- this.logger.debug(`Event handler removed: '${String(type)}' \u2192 ${id}`);
64
- if (list.length === 0) delete this.handlers[type];
131
+ if (index === -1) {
132
+ this.logger.warn(`Handler not found: '${String(type)}' \u2192 ${id}`);
133
+ return;
134
+ }
135
+ list.splice(index, 1);
136
+ this.logger.debug(`Event handler removed: '${String(type)}' \u2192 ${id}`);
137
+ if (list.length === 0) {
138
+ delete this.handlers[type];
65
139
  }
66
140
  }
67
- async emit(type, payload, source = "event-bus") {
68
- this.ensureInitialized();
69
- const list = this.handlers[type];
70
- if (!list?.length) return;
71
- const event = {
72
- type,
73
- payload,
74
- timestamp: Date.now(),
75
- source
76
- };
77
- for (const { id, handler, once } of [...list]) {
78
- try {
79
- await handler(event);
80
- if (once) this.off(type, id);
81
- } catch (err) {
82
- this.logger.error(
83
- `Event handler execution failed: '${String(type)}' \u2192 ${id}`,
84
- err
85
- );
141
+ async emit(type, payload, source = "event-bus", context) {
142
+ await this.withEventLock(type, async () => {
143
+ this.ensureInitialized();
144
+ const list = this.handlers[type];
145
+ if (!list?.length) {
146
+ this.logger.debug(`No handlers for event: '${String(type)}'`);
147
+ return;
86
148
  }
87
- }
149
+ const sortedList = [...list].sort((a, b) => b.priority - a.priority);
150
+ const event = {
151
+ type,
152
+ payload,
153
+ timestamp: Date.now(),
154
+ source,
155
+ context
156
+ };
157
+ let successCount = 0;
158
+ let errorCount = 0;
159
+ for (const { id, handler, once } of sortedList) {
160
+ try {
161
+ await Promise.race([
162
+ Promise.resolve(handler(event, context)),
163
+ new Promise(
164
+ (_, reject) => setTimeout(
165
+ () => reject(new Error("Handler timeout")),
166
+ this.handlerTimeoutMs
167
+ )
168
+ )
169
+ ]);
170
+ successCount++;
171
+ if (once) this.off(type, id);
172
+ } catch (err) {
173
+ errorCount++;
174
+ const errorMessage = err instanceof Error ? err.message : String(err);
175
+ this.logger.error(
176
+ `Event handler execution failed: '${String(type)}' \u2192 ${id} - ${this.sanitizeLog(errorMessage)}`
177
+ );
178
+ this.onError?.(err, type);
179
+ }
180
+ }
181
+ this.logger.debug(
182
+ `Event emitted: '${String(type)}' (${successCount} succeeded, ${errorCount} failed)`
183
+ );
184
+ });
88
185
  }
89
186
  removeAllListeners(type) {
90
187
  this.ensureInitialized();
@@ -94,7 +191,7 @@ class EventBus {
94
191
  `All listeners removed for event type: '${String(type)}'`
95
192
  );
96
193
  } else {
97
- this.handlers = {};
194
+ this.clearAllHandlers();
98
195
  this.logger.debug("All event listeners cleared from EventBus");
99
196
  }
100
197
  }
@@ -105,15 +202,19 @@ class EventBus {
105
202
  return Object.keys(this.handlers);
106
203
  }
107
204
  getStats() {
108
- const names = this.eventNames();
109
- const countMap = Object.fromEntries(
110
- names.map((name) => [name, this.listenerCount(name)])
205
+ const eventNames = this.eventNames();
206
+ const listenerCount = Object.fromEntries(
207
+ eventNames.map((name) => [name, this.listenerCount(name)])
208
+ );
209
+ const totalListeners = Object.values(listenerCount).reduce(
210
+ (sum, count) => sum + count,
211
+ 0
111
212
  );
112
213
  return {
113
- totalEvents: names.length,
114
- totalListeners: Object.values(countMap).reduce((a, b) => a + b, 0),
115
- eventNames: names,
116
- listenerCount: countMap
214
+ totalEvents: eventNames.length,
215
+ totalListeners,
216
+ eventNames,
217
+ listenerCount
117
218
  };
118
219
  }
119
220
  get isInitialized() {