arvo-event-handler 2.3.3 → 3.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 (78) hide show
  1. package/dist/AbstractArvoEventHandler/index.d.ts +1 -1
  2. package/dist/ArvoEventHandler/helpers.d.ts +40 -6
  3. package/dist/ArvoEventHandler/helpers.js +40 -6
  4. package/dist/ArvoEventHandler/index.d.ts +78 -49
  5. package/dist/ArvoEventHandler/index.js +151 -82
  6. package/dist/ArvoEventHandler/types.d.ts +25 -2
  7. package/dist/ArvoMachine/createMachine.d.ts +208 -0
  8. package/dist/ArvoMachine/createMachine.js +283 -0
  9. package/dist/ArvoMachine/index.d.ts +93 -0
  10. package/dist/ArvoMachine/index.js +160 -0
  11. package/dist/ArvoMachine/types.d.ts +194 -0
  12. package/dist/ArvoMachine/utils.d.ts +40 -0
  13. package/dist/ArvoMachine/utils.js +70 -0
  14. package/dist/ArvoOrchestrator/error.d.ts +16 -0
  15. package/dist/ArvoOrchestrator/error.js +43 -0
  16. package/dist/ArvoOrchestrator/factory.d.ts +28 -0
  17. package/dist/ArvoOrchestrator/factory.js +56 -0
  18. package/dist/ArvoOrchestrator/index.d.ts +69 -0
  19. package/dist/ArvoOrchestrator/index.js +597 -0
  20. package/dist/ArvoOrchestrator/types.d.ts +98 -0
  21. package/dist/ArvoResumable/factory.d.ts +50 -0
  22. package/dist/ArvoResumable/factory.js +70 -0
  23. package/dist/ArvoResumable/index.d.ts +141 -0
  24. package/dist/ArvoResumable/index.js +694 -0
  25. package/dist/ArvoResumable/types.d.ts +147 -0
  26. package/dist/ArvoResumable/types.js +2 -0
  27. package/dist/MachineExecutionEngine/index.d.ts +29 -0
  28. package/dist/MachineExecutionEngine/index.js +132 -0
  29. package/dist/MachineExecutionEngine/interface.d.ts +14 -0
  30. package/dist/MachineExecutionEngine/interface.js +2 -0
  31. package/dist/MachineExecutionEngine/types.d.ts +14 -0
  32. package/dist/MachineExecutionEngine/types.js +2 -0
  33. package/dist/MachineMemory/Simple.d.ts +51 -0
  34. package/dist/MachineMemory/Simple.js +158 -0
  35. package/dist/MachineMemory/TelemetredSimple.d.ts +51 -0
  36. package/dist/MachineMemory/TelemetredSimple.js +230 -0
  37. package/dist/MachineMemory/interface.d.ts +57 -0
  38. package/dist/MachineMemory/interface.js +2 -0
  39. package/dist/MachineMemory/utils.d.ts +1 -0
  40. package/dist/MachineMemory/utils.js +18 -0
  41. package/dist/MachineRegistry/index.d.ts +37 -0
  42. package/dist/MachineRegistry/index.js +87 -0
  43. package/dist/MachineRegistry/interface.d.ts +21 -0
  44. package/dist/MachineRegistry/interface.js +2 -0
  45. package/dist/SyncEventResource/index.d.ts +110 -0
  46. package/dist/SyncEventResource/index.js +280 -0
  47. package/dist/SyncEventResource/types.d.ts +2 -0
  48. package/dist/SyncEventResource/types.js +2 -0
  49. package/dist/index.d.ts +26 -8
  50. package/dist/index.js +39 -16
  51. package/dist/utils/SimpleEventBroker/helper.d.ts +166 -0
  52. package/dist/utils/SimpleEventBroker/helper.js +276 -0
  53. package/dist/utils/SimpleEventBroker/index.d.ts +96 -0
  54. package/dist/utils/SimpleEventBroker/index.js +259 -0
  55. package/dist/utils/SimpleEventBroker/types.d.ts +6 -0
  56. package/dist/utils/SimpleEventBroker/types.js +2 -0
  57. package/dist/utils/SimpleEventBroker/utils.d.ts +1 -0
  58. package/dist/utils/SimpleEventBroker/utils.js +10 -0
  59. package/dist/{utils.d.ts → utils/index.d.ts} +3 -36
  60. package/dist/utils/index.js +91 -0
  61. package/dist/utils/object/index.d.ts +37 -0
  62. package/dist/utils/object/index.js +63 -0
  63. package/package.json +5 -3
  64. package/dist/ArvoEventRouter/helpers.d.ts +0 -19
  65. package/dist/ArvoEventRouter/helpers.js +0 -22
  66. package/dist/ArvoEventRouter/index.d.ts +0 -89
  67. package/dist/ArvoEventRouter/index.js +0 -268
  68. package/dist/ArvoEventRouter/types.d.ts +0 -36
  69. package/dist/ArvoEventRouter/utils.d.ts +0 -30
  70. package/dist/ArvoEventRouter/utils.js +0 -43
  71. package/dist/MultiArvoEventHandler/helpers.d.ts +0 -48
  72. package/dist/MultiArvoEventHandler/helpers.js +0 -56
  73. package/dist/MultiArvoEventHandler/index.d.ts +0 -68
  74. package/dist/MultiArvoEventHandler/index.js +0 -205
  75. package/dist/MultiArvoEventHandler/types.d.ts +0 -64
  76. package/dist/utils.js +0 -191
  77. /package/dist/{ArvoEventRouter → ArvoMachine}/types.js +0 -0
  78. /package/dist/{MultiArvoEventHandler → ArvoOrchestrator}/types.js +0 -0
@@ -0,0 +1,276 @@
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
+ var __generator = (this && this.__generator) || function (thisArg, body) {
12
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
13
+ return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
14
+ function verb(n) { return function (v) { return step([n, v]); }; }
15
+ function step(op) {
16
+ if (f) throw new TypeError("Generator is already executing.");
17
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
18
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
19
+ if (y = 0, t) op = [op[0] & 2, t.value];
20
+ switch (op[0]) {
21
+ case 0: case 1: t = op; break;
22
+ case 4: _.label++; return { value: op[1], done: false };
23
+ case 5: _.label++; y = op[1]; op = [0]; continue;
24
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
25
+ default:
26
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
27
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
28
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
29
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
30
+ if (t[2]) _.ops.pop();
31
+ _.trys.pop(); continue;
32
+ }
33
+ op = body.call(thisArg, _);
34
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
35
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
36
+ }
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.createSimpleEventBroker = void 0;
40
+ var _1 = require(".");
41
+ /**
42
+ * Creates a local event broker configured with domain event handlers and provides event resolution capabilities
43
+ *
44
+ * This factory function establishes a comprehensive event-driven architecture within a single process,
45
+ * automatically wiring event handlers to their source topics and providing sophisticated event propagation
46
+ * with domain-specific routing capabilities. The broker implements sequential queue-based processing
47
+ * with built-in error handling and observability features.
48
+ *
49
+ * **Core Architecture:**
50
+ * The broker acts as an in-memory event bus that connects ArvoResumable orchestrators, ArvoOrchestrator
51
+ * state machines, and ArvoEventHandler services in a unified event-driven system. This enables
52
+ * local testing of distributed workflows and provides a foundation for event-driven microservices.
53
+ *
54
+ * **Event Processing Flow:**
55
+ * 1. Events are published to handler source topics
56
+ * 2. Handlers execute and produce response events
57
+ * 3. Domain-specific events are routed through onDomainedEvents callback
58
+ * 4. Default domain events are automatically propagated through the broker
59
+ * 5. Event chains continue until all handlers complete processing
60
+ *
61
+ * @param eventHandlers - Array of event handlers to register with the broker. Each handler is automatically
62
+ * subscribed to its source topic and executed when matching events are received.
63
+ * Supports ArvoResumable, ArvoOrchestrator, and ArvoEventHandler instances.
64
+ *
65
+ * @param options - Optional configuration for customizing broker behavior and event processing
66
+ * @param options.onError - Custom error handler invoked when processing failures occur. Receives the error
67
+ * and triggering event for logging, monitoring, or recovery actions. Defaults to
68
+ * console.error with structured event information for debugging.
69
+ * @param options.onDomainedEvents - Callback for processing domain-specific events produced by handlers.
70
+ * Enables custom routing logic, external system integration, or
71
+ * domain-specific event processing patterns. Receives events grouped
72
+ * by domain (excluding 'all') and the broker instance for republishing.
73
+ *
74
+ * @returns Configuration object containing the broker instance and event resolution function
75
+ * @returns result.broker - Configured SimpleEventBroker with all handlers subscribed and ready for processing
76
+ * @returns result.resolve - Async function that executes complete event processing chains and returns
77
+ * the final resolved event. Returns null if resolution fails or handler is not found
78
+ * for an intermetiate event.
79
+ *
80
+ * @throws {Error} When event source conflicts with registered handler sources during resolution
81
+ *
82
+ * @example
83
+ * **Basic Event-Driven Architecture Setup:**
84
+ * ```typescript
85
+ * const userHandler = createArvoEventHandler({
86
+ * contract: userContract,
87
+ * handler: { '1.0.0': async ({ event }) => ({ type: 'user.processed', data: event.data }) }
88
+ * });
89
+ *
90
+ * const orderOrchestrator = createArvoResumable({
91
+ * contracts: { self: orderContract, services: { user: userContract } },
92
+ * handler: {
93
+ * '1.0.0': async ({ init, service }) => {
94
+ * if (init) return { services: [{ type: 'user.process', data: init.data }] };
95
+ * if (service) return { complete: { data: { orderId: 'order-123' } } };
96
+ * }
97
+ * }
98
+ * });
99
+ *
100
+ * const { broker, resolve } = createSimpleEventBroker([userHandler, orderOrchestrator]);
101
+ * ```
102
+ *
103
+ * @example
104
+ * **Advanced Configuration with Domain Routing:**
105
+ * ```typescript
106
+ * const { broker, resolve } = createSimpleEventBroker(
107
+ * [orchestrator, paymentHandler, notificationHandler],
108
+ * {
109
+ * onError: (error, event) => {
110
+ * logger.error('Event processing failed', {
111
+ * error: error.message,
112
+ * eventType: event.type,
113
+ * eventId: event.id,
114
+ * source: event.source,
115
+ * timestamp: new Date().toISOString()
116
+ * });
117
+ * // Could implement retry logic, dead letter queues, etc.
118
+ * },
119
+ * onDomainedEvents: ({ events, broker }) => {
120
+ * // Route payment events to external payment processor
121
+ * if (events.payment) {
122
+ * events.payment.forEach(event => paymentGateway.send(event));
123
+ * }
124
+ *
125
+ * // Route notification events to messaging service
126
+ * if (events.notifications) {
127
+ * events.notifications.forEach(event => messagingService.send(event));
128
+ * }
129
+ *
130
+ * // Republish other domain events through the broker
131
+ * Object.entries(events).forEach(([domain, domainEvents]) => {
132
+ * if (!['payment', 'notifications'].includes(domain)) {
133
+ * domainEvents.forEach(event => broker.publish(event));
134
+ * }
135
+ * });
136
+ * }
137
+ * }
138
+ * );
139
+ * ```
140
+ *
141
+ * @example
142
+ * **Event Resolution for Integration Testing:**
143
+ * ```typescript
144
+ * // Test complete workflow execution
145
+ * const testEvent = createArvoEvent({
146
+ * type: 'order.create',
147
+ * source: 'test.client',
148
+ * to: 'order.orchestrator',
149
+ * data: { userId: '123', items: ['item1', 'item2'] }
150
+ * });
151
+ *
152
+ * const finalEvent = await resolve(testEvent);
153
+ *
154
+ * if (finalEvent) {
155
+ * // Verify the complete workflow executed successfully
156
+ * expect(finalEvent.type).toBe('order.completed');
157
+ * expect(finalEvent.data.orderId).toBeDefined();
158
+ * expect(finalEvent.source).toBe('test.client'); // Original source preserved
159
+ * } else {
160
+ * throw new Error('Order processing workflow failed');
161
+ * }
162
+ * ```
163
+ *
164
+ * @example
165
+ * **Direct Event Publishing:**
166
+ * ```typescript
167
+ * // Publish events directly to the broker for real-time processing
168
+ * await broker.publish(createArvoEvent({
169
+ * type: 'user.signup',
170
+ * source: 'web.app',
171
+ * to: 'user.service',
172
+ * data: { email: 'user@example.com', name: 'John Doe' }
173
+ * }));
174
+ *
175
+ * // The event will be routed to the user service handler automatically
176
+ * // Any resulting events will propagate through the broker
177
+ * ```
178
+ *
179
+ * @remarks
180
+ * **Event Source Conflict Prevention:**
181
+ * The resolve function validates that the input event's source doesn't conflict
182
+ * with registered handler sources to prevent infinite loops and routing ambiguity.
183
+ *
184
+ * **Sequential Processing Guarantee:**
185
+ * Events are processed sequentially within each topic to maintain ordering
186
+ * guarantees and prevent race conditions in workflow state management.
187
+ *
188
+ * **Integration Testing Benefits:**
189
+ * This pattern enables comprehensive integration testing of event-driven workflows
190
+ * without requiring external message brokers, making test suites faster and
191
+ * more reliable while maintaining production-like behavior patterns.
192
+ */
193
+ var createSimpleEventBroker = function (eventHandlers, options) {
194
+ var _a;
195
+ var resolvedHandlerName = 'broker.arvo.simple.handle';
196
+ var resolvedHandlerNameDuplicated = false;
197
+ var broker = new _1.SimpleEventBroker({
198
+ maxQueueSize: 1000,
199
+ errorHandler: (_a = options === null || options === void 0 ? void 0 : options.onError) !== null && _a !== void 0 ? _a : (function (error, event) {
200
+ console.error('Broker error:', {
201
+ message: error.message,
202
+ eventType: event.to,
203
+ event: event,
204
+ });
205
+ }),
206
+ });
207
+ // Wire up each handler to its source topic
208
+ // biome-ignore lint/complexity/noForEach: TODO - fix later
209
+ eventHandlers.forEach(function (handler) {
210
+ resolvedHandlerNameDuplicated = broker.topics.includes(resolvedHandlerName);
211
+ broker.subscribe(handler.source, function (event) { return __awaiter(void 0, void 0, void 0, function () {
212
+ var response, _i, _a, evt;
213
+ var _b;
214
+ return __generator(this, function (_c) {
215
+ switch (_c.label) {
216
+ case 0: return [4 /*yield*/, handler.execute(event, {
217
+ inheritFrom: 'EVENT',
218
+ })];
219
+ case 1:
220
+ response = _c.sent();
221
+ _i = 0, _a = response.events;
222
+ _c.label = 2;
223
+ case 2:
224
+ if (!(_i < _a.length)) return [3 /*break*/, 7];
225
+ evt = _a[_i];
226
+ if (!event.domain) return [3 /*break*/, 4];
227
+ return [4 /*yield*/, ((_b = options === null || options === void 0 ? void 0 : options.onDomainedEvents) === null || _b === void 0 ? void 0 : _b.call(options, {
228
+ domain: event.domain,
229
+ event: event,
230
+ broker: broker,
231
+ }))];
232
+ case 3:
233
+ _c.sent();
234
+ return [3 /*break*/, 6];
235
+ case 4: return [4 /*yield*/, broker.publish(evt)];
236
+ case 5:
237
+ _c.sent();
238
+ _c.label = 6;
239
+ case 6:
240
+ _i++;
241
+ return [3 /*break*/, 2];
242
+ case 7: return [2 /*return*/];
243
+ }
244
+ });
245
+ }); }, true);
246
+ });
247
+ return {
248
+ broker: broker,
249
+ resolve: function (_event) { return __awaiter(void 0, void 0, void 0, function () {
250
+ var resolvedEvent;
251
+ return __generator(this, function (_a) {
252
+ switch (_a.label) {
253
+ case 0:
254
+ if (broker.topics.includes(_event.source)) {
255
+ throw new Error("The event source cannot be one of the handlers in the broker. Please update the event.source, the given is '".concat(_event.source, "'"));
256
+ }
257
+ resolvedEvent = null;
258
+ broker.subscribe(_event.source, function (event) { return __awaiter(void 0, void 0, void 0, function () {
259
+ return __generator(this, function (_a) {
260
+ resolvedEvent = event;
261
+ return [2 /*return*/];
262
+ });
263
+ }); });
264
+ return [4 /*yield*/, broker.publish(_event)];
265
+ case 1:
266
+ _a.sent();
267
+ if (resolvedEvent === null) {
268
+ return [2 /*return*/, null];
269
+ }
270
+ return [2 /*return*/, resolvedEvent];
271
+ }
272
+ });
273
+ }); },
274
+ };
275
+ };
276
+ exports.createSimpleEventBroker = createSimpleEventBroker;
@@ -0,0 +1,96 @@
1
+ import type { ArvoEvent } from 'arvo-core';
2
+ import type { EventBusListener, EventBusOptions } from './types';
3
+ /**
4
+ * A simple event broker for handling local event-driven workflows within function scope.
5
+ * Ideal for composing function handlers and coordinating local business logic steps.
6
+ *
7
+ * @description
8
+ * Use SimpleEventBroker when you need:
9
+ * - Local event handling within a function's execution scope
10
+ * - Decoupling steps in a business process
11
+ * - Simple composition of handlers for a workflow
12
+ * - In-memory event management for a single operation
13
+ *
14
+ * Not suitable for:
15
+ * - Long-running processes or persistent event storage
16
+ * - Cross-process or distributed event handling
17
+ * - High-throughput event processing (>1000s events/sec)
18
+ * - Mission critical or fault-tolerant systems
19
+ * - Complex event routing or filtering
20
+ *
21
+ * Typical use cases:
22
+ * - Coordinating steps in a registration process
23
+ * - Managing validation and processing workflows
24
+ * - Decoupling business logic steps
25
+ * - Local event-driven state management
26
+ *
27
+ * @example
28
+ * ```typescript
29
+ * // During a registration flow
30
+ * const broker = new SimpleEventBroker({ ... });
31
+ *
32
+ * broker.subscribe('validation.complete', async (event) => {
33
+ * // Handle validation results
34
+ * });
35
+ *
36
+ * broker.subscribe('user.created', async (event) => {
37
+ * // Handle user creation side effects
38
+ * });
39
+ *
40
+ * await broker.publish({
41
+ * to: 'validation.complete',
42
+ * payload: userData
43
+ * });
44
+ * ```
45
+ */
46
+ export declare class SimpleEventBroker {
47
+ private readonly subscribers;
48
+ private readonly queue;
49
+ readonly events: ArvoEvent[];
50
+ private readonly maxQueueSize;
51
+ private readonly onError;
52
+ private isProcessing;
53
+ private readonly eventProcessDelay;
54
+ constructor(options: EventBusOptions);
55
+ /**
56
+ * All event types that have registered listeners.
57
+ */
58
+ get topics(): string[];
59
+ /**
60
+ * Subscribe to a specific event type
61
+ * @param topic - Event type to subscribe to
62
+ * @param handler - Function to handle the event
63
+ * @param assertUnique - Asserts the uniqne-ness of the handler.
64
+ * If true, then only one handler per topic
65
+ * otherwise, throws error
66
+ * @returns Unsubscribe function
67
+ */
68
+ subscribe(topic: string, handler: EventBusListener, assertUnique?: boolean): () => void;
69
+ /**
70
+ * Publish an event to subscribers
71
+ * @param event - Event to publish
72
+ * @throws Error if queue is full or event has no topic
73
+ */
74
+ publish(event: ArvoEvent): Promise<void>;
75
+ /**
76
+ * Current number of events in queue
77
+ */
78
+ get queueLength(): number;
79
+ /**
80
+ * Number of subscribers for a given topic
81
+ */
82
+ getSubscriberCount(topic: string): number;
83
+ /**
84
+ * Processes queued events asynchronously, ensuring sequential execution.
85
+ * Handles error cases and maintains the processing state.
86
+ *
87
+ * @remarks
88
+ * - Only one instance of processQueue runs at a time
89
+ * - Events are processed in FIFO order
90
+ * - Failed event handlers trigger onError callback
91
+ * - All handlers for an event are processed in parallel
92
+ *
93
+ * @throws Propagates any unhandled errors from event processing
94
+ */
95
+ private processQueue;
96
+ }
@@ -0,0 +1,259 @@
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
+ var __generator = (this && this.__generator) || function (thisArg, body) {
12
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
13
+ return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
14
+ function verb(n) { return function (v) { return step([n, v]); }; }
15
+ function step(op) {
16
+ if (f) throw new TypeError("Generator is already executing.");
17
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
18
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
19
+ if (y = 0, t) op = [op[0] & 2, t.value];
20
+ switch (op[0]) {
21
+ case 0: case 1: t = op; break;
22
+ case 4: _.label++; return { value: op[1], done: false };
23
+ case 5: _.label++; y = op[1]; op = [0]; continue;
24
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
25
+ default:
26
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
27
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
28
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
29
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
30
+ if (t[2]) _.ops.pop();
31
+ _.trys.pop(); continue;
32
+ }
33
+ op = body.call(thisArg, _);
34
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
35
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
36
+ }
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.SimpleEventBroker = void 0;
40
+ var utils_1 = require("./utils");
41
+ /**
42
+ * A simple event broker for handling local event-driven workflows within function scope.
43
+ * Ideal for composing function handlers and coordinating local business logic steps.
44
+ *
45
+ * @description
46
+ * Use SimpleEventBroker when you need:
47
+ * - Local event handling within a function's execution scope
48
+ * - Decoupling steps in a business process
49
+ * - Simple composition of handlers for a workflow
50
+ * - In-memory event management for a single operation
51
+ *
52
+ * Not suitable for:
53
+ * - Long-running processes or persistent event storage
54
+ * - Cross-process or distributed event handling
55
+ * - High-throughput event processing (>1000s events/sec)
56
+ * - Mission critical or fault-tolerant systems
57
+ * - Complex event routing or filtering
58
+ *
59
+ * Typical use cases:
60
+ * - Coordinating steps in a registration process
61
+ * - Managing validation and processing workflows
62
+ * - Decoupling business logic steps
63
+ * - Local event-driven state management
64
+ *
65
+ * @example
66
+ * ```typescript
67
+ * // During a registration flow
68
+ * const broker = new SimpleEventBroker({ ... });
69
+ *
70
+ * broker.subscribe('validation.complete', async (event) => {
71
+ * // Handle validation results
72
+ * });
73
+ *
74
+ * broker.subscribe('user.created', async (event) => {
75
+ * // Handle user creation side effects
76
+ * });
77
+ *
78
+ * await broker.publish({
79
+ * to: 'validation.complete',
80
+ * payload: userData
81
+ * });
82
+ * ```
83
+ */
84
+ var SimpleEventBroker = /** @class */ (function () {
85
+ function SimpleEventBroker(options) {
86
+ this.eventProcessDelay = 1;
87
+ this.subscribers = new Map();
88
+ this.queue = [];
89
+ this.events = [];
90
+ this.isProcessing = false;
91
+ this.maxQueueSize = options.maxQueueSize;
92
+ this.onError = options.errorHandler;
93
+ }
94
+ Object.defineProperty(SimpleEventBroker.prototype, "topics", {
95
+ /**
96
+ * All event types that have registered listeners.
97
+ */
98
+ get: function () {
99
+ return Array.from(this.subscribers.keys());
100
+ },
101
+ enumerable: false,
102
+ configurable: true
103
+ });
104
+ /**
105
+ * Subscribe to a specific event type
106
+ * @param topic - Event type to subscribe to
107
+ * @param handler - Function to handle the event
108
+ * @param assertUnique - Asserts the uniqne-ness of the handler.
109
+ * If true, then only one handler per topic
110
+ * otherwise, throws error
111
+ * @returns Unsubscribe function
112
+ */
113
+ SimpleEventBroker.prototype.subscribe = function (topic, handler, assertUnique) {
114
+ var _this = this;
115
+ var _a, _b;
116
+ if (assertUnique === void 0) { assertUnique = false; }
117
+ if (!this.subscribers.has(topic)) {
118
+ this.subscribers.set(topic, new Set());
119
+ }
120
+ if (assertUnique && ((_b = (_a = this.subscribers.get(topic)) === null || _a === void 0 ? void 0 : _a.size) !== null && _b !== void 0 ? _b : 0) > 1) {
121
+ throw new Error("Only one subscriber allowed per topic: ".concat(topic));
122
+ }
123
+ // biome-ignore lint/style/noNonNullAssertion: non issue
124
+ var handlers = this.subscribers.get(topic);
125
+ handlers.add(handler);
126
+ return function () {
127
+ handlers.delete(handler);
128
+ if (handlers.size === 0) {
129
+ _this.subscribers.delete(topic);
130
+ }
131
+ };
132
+ };
133
+ /**
134
+ * Publish an event to subscribers
135
+ * @param event - Event to publish
136
+ * @throws Error if queue is full or event has no topic
137
+ */
138
+ SimpleEventBroker.prototype.publish = function (event) {
139
+ return __awaiter(this, void 0, void 0, function () {
140
+ return __generator(this, function (_a) {
141
+ switch (_a.label) {
142
+ case 0:
143
+ if (!event.to) {
144
+ throw new Error('Event must have a "to" property');
145
+ }
146
+ if (this.queue.length >= this.maxQueueSize) {
147
+ throw new Error("Event queue is full (max size: ".concat(this.maxQueueSize, ")"));
148
+ }
149
+ this.queue.push(event);
150
+ this.events.push(event);
151
+ if (!!this.isProcessing) return [3 /*break*/, 2];
152
+ return [4 /*yield*/, this.processQueue()];
153
+ case 1:
154
+ _a.sent();
155
+ _a.label = 2;
156
+ case 2: return [2 /*return*/];
157
+ }
158
+ });
159
+ });
160
+ };
161
+ Object.defineProperty(SimpleEventBroker.prototype, "queueLength", {
162
+ /**
163
+ * Current number of events in queue
164
+ */
165
+ get: function () {
166
+ return this.queue.length;
167
+ },
168
+ enumerable: false,
169
+ configurable: true
170
+ });
171
+ /**
172
+ * Number of subscribers for a given topic
173
+ */
174
+ SimpleEventBroker.prototype.getSubscriberCount = function (topic) {
175
+ var _a, _b;
176
+ return (_b = (_a = this.subscribers.get(topic)) === null || _a === void 0 ? void 0 : _a.size) !== null && _b !== void 0 ? _b : 0;
177
+ };
178
+ /**
179
+ * Processes queued events asynchronously, ensuring sequential execution.
180
+ * Handles error cases and maintains the processing state.
181
+ *
182
+ * @remarks
183
+ * - Only one instance of processQueue runs at a time
184
+ * - Events are processed in FIFO order
185
+ * - Failed event handlers trigger onError callback
186
+ * - All handlers for an event are processed in parallel
187
+ *
188
+ * @throws Propagates any unhandled errors from event processing
189
+ */
190
+ SimpleEventBroker.prototype.processQueue = function () {
191
+ return __awaiter(this, void 0, void 0, function () {
192
+ var _loop_1, this_1;
193
+ var _this = this;
194
+ var _a;
195
+ return __generator(this, function (_b) {
196
+ switch (_b.label) {
197
+ case 0:
198
+ if (this.isProcessing)
199
+ return [2 /*return*/];
200
+ this.isProcessing = true;
201
+ _b.label = 1;
202
+ case 1:
203
+ _b.trys.push([1, , 5, 6]);
204
+ _loop_1 = function () {
205
+ var event_1, handlers, handlerPromises;
206
+ return __generator(this, function (_c) {
207
+ switch (_c.label) {
208
+ case 0:
209
+ event_1 = this_1.queue.pop();
210
+ if (!event_1)
211
+ return [2 /*return*/, "continue"];
212
+ if (!this_1.eventProcessDelay) return [3 /*break*/, 2];
213
+ return [4 /*yield*/, (0, utils_1.promiseTimeout)(this_1.eventProcessDelay)];
214
+ case 1:
215
+ _c.sent();
216
+ _c.label = 2;
217
+ case 2:
218
+ handlers = this_1.subscribers.get((_a = event_1.to) !== null && _a !== void 0 ? _a : '');
219
+ if (!(handlers === null || handlers === void 0 ? void 0 : handlers.size)) {
220
+ this_1.onError(new Error("No handlers registered for event type: ".concat(event_1.to)), event_1);
221
+ return [2 /*return*/, "continue"];
222
+ }
223
+ handlerPromises = Array.from(handlers).map(function (handler) {
224
+ return handler(event_1, _this.publish.bind(_this)).catch(function (error) {
225
+ if (error instanceof Error) {
226
+ _this.onError(error, event_1);
227
+ }
228
+ else {
229
+ _this.onError(new Error(String(error)), event_1);
230
+ }
231
+ });
232
+ });
233
+ return [4 /*yield*/, Promise.all(handlerPromises)];
234
+ case 3:
235
+ _c.sent();
236
+ return [2 /*return*/];
237
+ }
238
+ });
239
+ };
240
+ this_1 = this;
241
+ _b.label = 2;
242
+ case 2:
243
+ if (!(this.queue.length > 0)) return [3 /*break*/, 4];
244
+ return [5 /*yield**/, _loop_1()];
245
+ case 3:
246
+ _b.sent();
247
+ return [3 /*break*/, 2];
248
+ case 4: return [3 /*break*/, 6];
249
+ case 5:
250
+ this.isProcessing = false;
251
+ return [7 /*endfinally*/];
252
+ case 6: return [2 /*return*/];
253
+ }
254
+ });
255
+ });
256
+ };
257
+ return SimpleEventBroker;
258
+ }());
259
+ exports.SimpleEventBroker = SimpleEventBroker;
@@ -0,0 +1,6 @@
1
+ import type { ArvoEvent } from 'arvo-core';
2
+ export type EventBusListener = (event: ArvoEvent, publish: (event: ArvoEvent) => Promise<void>) => Promise<void>;
3
+ export interface EventBusOptions {
4
+ maxQueueSize: number;
5
+ errorHandler: (error: Error, event: ArvoEvent) => void;
6
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1 @@
1
+ export declare const promiseTimeout: (timeout?: number) => Promise<void>;
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.promiseTimeout = void 0;
4
+ var promiseTimeout = function (timeout) {
5
+ if (timeout === void 0) { timeout = 10; }
6
+ return new Promise(function (resolve) {
7
+ setTimeout(resolve, timeout);
8
+ });
9
+ };
10
+ exports.promiseTimeout = promiseTimeout;