@nimbus-cqrs/core 2.0.0-beta.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 (79) hide show
  1. package/LICENSE +85 -0
  2. package/README.md +56 -0
  3. package/esm/_dnt.shims.d.ts +2 -0
  4. package/esm/_dnt.shims.d.ts.map +1 -0
  5. package/esm/_dnt.shims.js +57 -0
  6. package/esm/deps/jsr.io/@std/fmt/1.0.10/colors.d.ts +700 -0
  7. package/esm/deps/jsr.io/@std/fmt/1.0.10/colors.d.ts.map +1 -0
  8. package/esm/deps/jsr.io/@std/fmt/1.0.10/colors.js +903 -0
  9. package/esm/deps/jsr.io/@std/ulid/1.0.0/_util.d.ts +14 -0
  10. package/esm/deps/jsr.io/@std/ulid/1.0.0/_util.d.ts.map +1 -0
  11. package/esm/deps/jsr.io/@std/ulid/1.0.0/_util.js +65 -0
  12. package/esm/deps/jsr.io/@std/ulid/1.0.0/decode_time.d.ts +20 -0
  13. package/esm/deps/jsr.io/@std/ulid/1.0.0/decode_time.d.ts.map +1 -0
  14. package/esm/deps/jsr.io/@std/ulid/1.0.0/decode_time.js +43 -0
  15. package/esm/deps/jsr.io/@std/ulid/1.0.0/mod.d.ts +44 -0
  16. package/esm/deps/jsr.io/@std/ulid/1.0.0/mod.d.ts.map +1 -0
  17. package/esm/deps/jsr.io/@std/ulid/1.0.0/mod.js +47 -0
  18. package/esm/deps/jsr.io/@std/ulid/1.0.0/monotonic_ulid.d.ts +44 -0
  19. package/esm/deps/jsr.io/@std/ulid/1.0.0/monotonic_ulid.d.ts.map +1 -0
  20. package/esm/deps/jsr.io/@std/ulid/1.0.0/monotonic_ulid.js +51 -0
  21. package/esm/deps/jsr.io/@std/ulid/1.0.0/ulid.d.ts +31 -0
  22. package/esm/deps/jsr.io/@std/ulid/1.0.0/ulid.d.ts.map +1 -0
  23. package/esm/deps/jsr.io/@std/ulid/1.0.0/ulid.js +37 -0
  24. package/esm/index.d.ts +18 -0
  25. package/esm/index.d.ts.map +1 -0
  26. package/esm/index.js +17 -0
  27. package/esm/lib/eventBus/eventBus.d.ts +329 -0
  28. package/esm/lib/eventBus/eventBus.d.ts.map +1 -0
  29. package/esm/lib/eventBus/eventBus.js +473 -0
  30. package/esm/lib/exception/exception.d.ts +10 -0
  31. package/esm/lib/exception/exception.d.ts.map +1 -0
  32. package/esm/lib/exception/exception.js +26 -0
  33. package/esm/lib/exception/forbiddenException.d.ts +8 -0
  34. package/esm/lib/exception/forbiddenException.d.ts.map +1 -0
  35. package/esm/lib/exception/forbiddenException.js +9 -0
  36. package/esm/lib/exception/genericException.d.ts +8 -0
  37. package/esm/lib/exception/genericException.d.ts.map +1 -0
  38. package/esm/lib/exception/genericException.js +9 -0
  39. package/esm/lib/exception/invalidInputException.d.ts +18 -0
  40. package/esm/lib/exception/invalidInputException.d.ts.map +1 -0
  41. package/esm/lib/exception/invalidInputException.js +28 -0
  42. package/esm/lib/exception/notFoundException.d.ts +8 -0
  43. package/esm/lib/exception/notFoundException.d.ts.map +1 -0
  44. package/esm/lib/exception/notFoundException.js +9 -0
  45. package/esm/lib/exception/unauthorizedException.d.ts +8 -0
  46. package/esm/lib/exception/unauthorizedException.d.ts.map +1 -0
  47. package/esm/lib/exception/unauthorizedException.js +9 -0
  48. package/esm/lib/log/logFormatter.d.ts +26 -0
  49. package/esm/lib/log/logFormatter.d.ts.map +1 -0
  50. package/esm/lib/log/logFormatter.js +59 -0
  51. package/esm/lib/log/logLevel.d.ts +24 -0
  52. package/esm/lib/log/logLevel.d.ts.map +1 -0
  53. package/esm/lib/log/logLevel.js +27 -0
  54. package/esm/lib/log/logger.d.ts +377 -0
  55. package/esm/lib/log/logger.d.ts.map +1 -0
  56. package/esm/lib/log/logger.js +394 -0
  57. package/esm/lib/log/options.d.ts +34 -0
  58. package/esm/lib/log/options.d.ts.map +1 -0
  59. package/esm/lib/log/options.js +9 -0
  60. package/esm/lib/message/command.d.ts +100 -0
  61. package/esm/lib/message/command.d.ts.map +1 -0
  62. package/esm/lib/message/command.js +47 -0
  63. package/esm/lib/message/event.d.ts +103 -0
  64. package/esm/lib/message/event.d.ts.map +1 -0
  65. package/esm/lib/message/event.js +47 -0
  66. package/esm/lib/message/message.d.ts +18 -0
  67. package/esm/lib/message/message.d.ts.map +1 -0
  68. package/esm/lib/message/message.js +1 -0
  69. package/esm/lib/message/query.d.ts +95 -0
  70. package/esm/lib/message/query.d.ts.map +1 -0
  71. package/esm/lib/message/query.js +45 -0
  72. package/esm/lib/message/router.d.ts +233 -0
  73. package/esm/lib/message/router.d.ts.map +1 -0
  74. package/esm/lib/message/router.js +304 -0
  75. package/esm/lib/tracing/withSpan.d.ts +67 -0
  76. package/esm/lib/tracing/withSpan.d.ts.map +1 -0
  77. package/esm/lib/tracing/withSpan.js +87 -0
  78. package/esm/package.json +3 -0
  79. package/package.json +33 -0
@@ -0,0 +1,473 @@
1
+ import { metrics, SpanKind, SpanStatusCode, trace } from '@opentelemetry/api';
2
+ import EventEmitter from 'node:events';
3
+ import { GenericException } from '../exception/genericException.js';
4
+ import { getLogger } from '../log/logger.js';
5
+ const tracer = trace.getTracer('nimbus');
6
+ const meter = metrics.getMeter('nimbus');
7
+ const eventsPublishedCounter = meter.createCounter('eventbus_events_published_total', {
8
+ description: 'Total number of events published to the event bus',
9
+ });
10
+ const eventsDeliveredCounter = meter.createCounter('eventbus_events_delivered_total', {
11
+ description: 'Total number of events delivered to handlers',
12
+ });
13
+ const handlingDuration = meter.createHistogram('eventbus_event_handling_duration_seconds', {
14
+ description: 'Duration of event handler execution in seconds',
15
+ unit: 's',
16
+ });
17
+ const retryAttemptsCounter = meter.createCounter('eventbus_retry_attempts_total', {
18
+ description: 'Total number of retry attempts for event handling',
19
+ });
20
+ const eventSizeBytes = meter.createHistogram('eventbus_event_size_bytes', {
21
+ description: 'Size of events published to the event bus in bytes',
22
+ unit: 'By',
23
+ });
24
+ /**
25
+ * The NimbusEventBus is used to publish and subscribe to events within the application.
26
+ *
27
+ * Events are delivered asynchronously to all registered handlers. If a handler fails,
28
+ * it will be retried using exponential backoff until it succeeds or the maximum retry
29
+ * count is reached.
30
+ *
31
+ * All operations are instrumented with OpenTelemetry tracing and metrics for observability.
32
+ *
33
+ * @example
34
+ * ```ts
35
+ * import { createEvent, NimbusEventBus } from '@nimbus/core';
36
+ *
37
+ * const eventBus = new NimbusEventBus({
38
+ * name: 'orders',
39
+ * maxRetries: 3,
40
+ * baseDelay: 1000,
41
+ * maxDelay: 30000,
42
+ * useJitter: true,
43
+ * logPublish: (event) => {
44
+ * console.log('Event published:', event.type, event.correlationid);
45
+ * },
46
+ * });
47
+ *
48
+ * // Subscribe to events
49
+ * eventBus.subscribeEvent({
50
+ * type: 'at.overlap.nimbus.order-created',
51
+ * handler: async (event) => {
52
+ * console.log('Order created:', event.data);
53
+ * },
54
+ * onError: (error, event) => {
55
+ * console.error('Failed to handle event:', event.id, error.message);
56
+ * },
57
+ * options: {
58
+ * maxRetries: 5,
59
+ * baseDelay: 500,
60
+ * maxDelay: 15000,
61
+ * useJitter: true,
62
+ * },
63
+ * });
64
+ *
65
+ * // Publish an event
66
+ * const event = createEvent({
67
+ * type: 'at.overlap.nimbus.order-created',
68
+ * source: 'https://api.example.com',
69
+ * correlationid: '550e8400-e29b-41d4-a716-446655440000',
70
+ * subject: '/orders/12345',
71
+ * data: { orderId: '12345', customerId: '67890' },
72
+ * datacontenttype: 'application/json',
73
+ * });
74
+ *
75
+ * eventBus.putEvent(event);
76
+ * ```
77
+ */
78
+ export class NimbusEventBus {
79
+ _eventEmitter;
80
+ _name;
81
+ _maxRetries;
82
+ _baseDelay;
83
+ _maxDelay;
84
+ _useJitter;
85
+ _logPublish;
86
+ /**
87
+ * Create a new NimbusEventBus instance.
88
+ *
89
+ * @param options - The options for the event bus.
90
+ * @param options.name - The name of the event bus instance for metrics and traces. Defaults to 'default'.
91
+ * @param options.maxRetries - The maximum number of retries for handling the event in case of an error. Defaults to 2.
92
+ * @param options.baseDelay - The base delay for exponential backoff in milliseconds. Defaults to 1000ms.
93
+ * @param options.maxDelay - The maximum delay cap for exponential backoff in milliseconds. Defaults to 30000ms.
94
+ * @param options.useJitter - Whether to add jitter to the retry delay. Defaults to true.
95
+ * @param options.logPublish - Optional callback invoked when an event is published.
96
+ *
97
+ * @example
98
+ * ```ts
99
+ * import { getLogger, NimbusEventBus } from '@nimbus/core';
100
+ *
101
+ * const eventBus = new NimbusEventBus({
102
+ * name: 'orders',
103
+ * maxRetries: 3,
104
+ * baseDelay: 1000,
105
+ * maxDelay: 30000,
106
+ * useJitter: true,
107
+ * logPublish: (event) => {
108
+ * getLogger().debug({
109
+ * category: 'EventBus',
110
+ * message: 'Published event',
111
+ * data: { type: event.type, id: event.id },
112
+ * correlationId: event.correlationid,
113
+ * });
114
+ * },
115
+ * });
116
+ * ```
117
+ */
118
+ constructor(options) {
119
+ this._eventEmitter = new EventEmitter();
120
+ this._name = options?.name ?? 'default';
121
+ this._maxRetries = options?.maxRetries ?? 2;
122
+ this._baseDelay = options?.baseDelay ?? 1000;
123
+ this._maxDelay = options?.maxDelay ?? 30000;
124
+ this._useJitter = options?.useJitter ?? true;
125
+ this._logPublish = options?.logPublish;
126
+ }
127
+ /**
128
+ * Publish an event to the event bus.
129
+ *
130
+ * The event is validated against the CloudEvents 64KB size limit before publishing.
131
+ * All subscribers registered for this event type will receive the event asynchronously.
132
+ *
133
+ * @param event - The CloudEvents-compliant event to publish.
134
+ * @throws {GenericException} If the event size exceeds 64KB.
135
+ *
136
+ * @example
137
+ * ```ts
138
+ * import { createEvent, getEventBus } from '@nimbus/core';
139
+ *
140
+ * const eventBus = getEventBus('default');
141
+ *
142
+ * // Create and publish an event with all CloudEvents properties
143
+ * const event = createEvent({
144
+ * type: 'at.overlap.nimbus.order-created',
145
+ * source: 'https://api.example.com',
146
+ * correlationid: '550e8400-e29b-41d4-a716-446655440000',
147
+ * subject: '/orders/12345',
148
+ * data: {
149
+ * orderId: '12345',
150
+ * customerId: '67890',
151
+ * items: ['item-1', 'item-2'],
152
+ * total: 99.99,
153
+ * },
154
+ * datacontenttype: 'application/json',
155
+ * dataschema: 'https://schemas.example.com/order-created.json',
156
+ * });
157
+ *
158
+ * eventBus.putEvent(event);
159
+ * ```
160
+ */
161
+ putEvent(event) {
162
+ const eventSize = this._validateEventSize(event);
163
+ const metricLabels = {
164
+ eventbus_name: this._name,
165
+ event_type: event.type,
166
+ };
167
+ tracer.startActiveSpan('eventbus.publish', {
168
+ kind: SpanKind.PRODUCER,
169
+ attributes: {
170
+ 'messaging.system': 'nimbusEventBus',
171
+ 'messaging.eventbus_name': this._name,
172
+ 'messaging.operation': 'publish',
173
+ 'messaging.destination': event.type,
174
+ 'cloudevents.event_id': event.id,
175
+ 'cloudevents.event_source': event.source,
176
+ ...(event.correlationid && {
177
+ correlation_id: event.correlationid,
178
+ }),
179
+ },
180
+ }, (span) => {
181
+ try {
182
+ eventsPublishedCounter.add(1, metricLabels);
183
+ eventSizeBytes.record(eventSize, metricLabels);
184
+ if (this._logPublish) {
185
+ this._logPublish(event);
186
+ }
187
+ this._eventEmitter.emit(event.type, event);
188
+ }
189
+ catch (error) {
190
+ span.setStatus({
191
+ code: SpanStatusCode.ERROR,
192
+ message: error instanceof Error
193
+ ? error.message
194
+ : 'Unknown error',
195
+ });
196
+ span.recordException(error instanceof Error
197
+ ? error
198
+ : new Error('Unknown error'));
199
+ throw error;
200
+ }
201
+ finally {
202
+ span.end();
203
+ }
204
+ });
205
+ }
206
+ /**
207
+ * Subscribe to an event type with a handler function.
208
+ *
209
+ * When an event matching the specified type is published, the handler is invoked.
210
+ * If the handler throws an error, it will be retried using exponential backoff
211
+ * (delay doubles with each attempt) until either it succeeds or the maximum retry
212
+ * count is reached.
213
+ *
214
+ * @param input - The subscription configuration.
215
+ * @param input.type - The CloudEvents event type to subscribe to.
216
+ * @param input.handler - The async handler function to process events.
217
+ * @param input.onError - Optional callback invoked when all retries are exhausted.
218
+ * @param input.options - Optional retry options to override EventBus defaults.
219
+ * @param input.options.maxRetries - Override maximum retry attempts for this subscription.
220
+ * @param input.options.baseDelay - Override base delay in milliseconds for this subscription.
221
+ * @param input.options.maxDelay - Override maximum delay cap in milliseconds for this subscription.
222
+ * @param input.options.useJitter - Override jitter setting for this subscription.
223
+ *
224
+ * @example
225
+ * ```ts
226
+ * import { getEventBus, getLogger } from '@nimbus/core';
227
+ *
228
+ * const eventBus = getEventBus('default');
229
+ *
230
+ * // Subscribe with all available options
231
+ * eventBus.subscribeEvent({
232
+ * type: 'at.overlap.nimbus.order-created',
233
+ * handler: async (event) => {
234
+ * // Process the event
235
+ * console.log('Order created:', event.data.orderId);
236
+ * console.log('Correlation ID:', event.correlationid);
237
+ * },
238
+ * onError: (error, event) => {
239
+ * getLogger().error({
240
+ * category: 'OrderHandler',
241
+ * message: 'Failed to process order after all retries',
242
+ * data: { eventId: event.id, orderId: event.data.orderId },
243
+ * error,
244
+ * correlationId: event.correlationid,
245
+ * });
246
+ * },
247
+ * options: {
248
+ * maxRetries: 5,
249
+ * baseDelay: 500,
250
+ * maxDelay: 15000,
251
+ * useJitter: true,
252
+ * },
253
+ * });
254
+ * ```
255
+ */
256
+ subscribeEvent({ type, handler, onError, options, }) {
257
+ getLogger().debug({
258
+ category: 'Nimbus',
259
+ message: `Subscribed to ${type} event`,
260
+ });
261
+ const maxRetries = options?.maxRetries ?? this._maxRetries;
262
+ const baseDelay = options?.baseDelay ?? this._baseDelay;
263
+ const maxDelay = options?.maxDelay ?? this._maxDelay;
264
+ const useJitter = options?.useJitter ?? this._useJitter;
265
+ const handleEvent = async (event) => {
266
+ try {
267
+ await this._processEvent(handler, event, maxRetries, baseDelay, maxDelay, useJitter);
268
+ }
269
+ catch (error) {
270
+ if (onError) {
271
+ onError(error, event);
272
+ }
273
+ else {
274
+ getLogger().error({
275
+ category: 'Nimbus',
276
+ message: error.message,
277
+ error,
278
+ });
279
+ }
280
+ }
281
+ };
282
+ this._eventEmitter.on(type, handleEvent);
283
+ }
284
+ _processEvent(handler, event, maxRetries, baseDelay, maxDelay, useJitter) {
285
+ const startTime = performance.now();
286
+ const metricLabels = {
287
+ eventbus_name: this._name,
288
+ event_type: event.type,
289
+ };
290
+ return tracer.startActiveSpan('eventbus.handle', {
291
+ kind: SpanKind.CONSUMER,
292
+ attributes: {
293
+ 'messaging.system': 'nimbusEventBus',
294
+ 'messaging.eventbus_name': this._name,
295
+ 'messaging.operation': 'process',
296
+ 'messaging.destination': event.type,
297
+ 'cloudevents.event_id': event.id,
298
+ 'cloudevents.event_source': event.source,
299
+ ...(event.correlationid && {
300
+ correlation_id: event.correlationid,
301
+ }),
302
+ },
303
+ }, async (span) => {
304
+ let attempt = 0;
305
+ while (attempt <= maxRetries) {
306
+ try {
307
+ await handler(event);
308
+ this._recordDeliveryMetrics(metricLabels, 'success', startTime);
309
+ span.end();
310
+ return;
311
+ }
312
+ catch (error) {
313
+ attempt++;
314
+ if (attempt > maxRetries) {
315
+ this._handleFinalFailure({
316
+ error,
317
+ event,
318
+ span,
319
+ metricLabels,
320
+ startTime,
321
+ retryConfig: {
322
+ maxRetries,
323
+ baseDelay,
324
+ maxDelay,
325
+ },
326
+ });
327
+ }
328
+ retryAttemptsCounter.add(1, metricLabels);
329
+ const delayMs = this._calculateRetryDelay(attempt, baseDelay, maxDelay, useJitter);
330
+ span.addEvent('retry', { attempt, delay_ms: delayMs });
331
+ await new Promise((resolve) => setTimeout(resolve, delayMs));
332
+ }
333
+ }
334
+ });
335
+ }
336
+ _recordDeliveryMetrics(metricLabels, status, startTime) {
337
+ eventsDeliveredCounter.add(1, { ...metricLabels, status });
338
+ handlingDuration.record((performance.now() - startTime) / 1000, metricLabels);
339
+ }
340
+ _handleFinalFailure(options) {
341
+ const { error, event, span, metricLabels, startTime, retryConfig } = options;
342
+ this._recordDeliveryMetrics(metricLabels, 'error', startTime);
343
+ const errorMessage = error instanceof Error
344
+ ? error.message
345
+ : 'Unknown error';
346
+ const errorInstance = error instanceof Error
347
+ ? error
348
+ : new Error('Unknown error');
349
+ span.setStatus({ code: SpanStatusCode.ERROR, message: errorMessage });
350
+ span.recordException(errorInstance);
351
+ span.end();
352
+ const exception = new GenericException(`Failed to handle event: ${event.type} from ${event.source}`, retryConfig);
353
+ if (error instanceof Error && error.stack) {
354
+ exception.stack = error.stack;
355
+ }
356
+ throw exception;
357
+ }
358
+ _calculateRetryDelay(attempt, baseDelay, maxDelay, useJitter) {
359
+ const delay = Math.min(baseDelay * Math.pow(2, attempt - 1), maxDelay);
360
+ const jitter = useJitter ? Math.random() * delay * 0.1 : 0;
361
+ return delay + jitter;
362
+ }
363
+ /**
364
+ * Validate the size of the event and return the size in bytes.
365
+ *
366
+ * To comply with the CloudEvent spec a transmitted event
367
+ * can only have a maximum size of 64KB.
368
+ *
369
+ * @param event - The event to validate.
370
+ * @returns The size of the event in bytes.
371
+ */
372
+ _validateEventSize(event) {
373
+ const eventJson = JSON.stringify(event);
374
+ const size = new TextEncoder().encode(eventJson).length;
375
+ const maxSizeBytes = 64 * 1024; // 64KB
376
+ if (size > maxSizeBytes) {
377
+ throw new GenericException(`Event size exceeds the limit of 64KB`, {
378
+ eventType: event.type,
379
+ eventSource: event.source,
380
+ eventSizeBytes: size,
381
+ maxSizeBytes,
382
+ });
383
+ }
384
+ return size;
385
+ }
386
+ }
387
+ /**
388
+ * Registry to store named EventBus instances.
389
+ */
390
+ const eventBusRegistry = new Map();
391
+ /**
392
+ * Setup a named EventBus instance and register it for later retrieval.
393
+ *
394
+ * Use this function to configure an EventBus with specific options at application
395
+ * startup, then retrieve it later using {@link getEventBus}.
396
+ *
397
+ * @param name - The unique name for this EventBus instance.
398
+ * @param options - Optional configuration options for the EventBus.
399
+ * @param options.maxRetries - The maximum number of retries for handling events. Defaults to 2.
400
+ * @param options.baseDelay - The base delay for exponential backoff in milliseconds. Defaults to 1000ms.
401
+ * @param options.maxDelay - The maximum delay cap for exponential backoff in milliseconds. Defaults to 30000ms.
402
+ * @param options.useJitter - Whether to add jitter to the retry delay. Defaults to true.
403
+ * @param options.logPublish - Optional callback invoked when an event is published.
404
+ *
405
+ * @example
406
+ * ```ts
407
+ * import { getLogger, setupEventBus } from '@nimbus/core';
408
+ *
409
+ * // At application startup, configure the event bus with all options
410
+ * setupEventBus('default', {
411
+ * maxRetries: 3,
412
+ * baseDelay: 1000,
413
+ * maxDelay: 30000,
414
+ * useJitter: true,
415
+ * logPublish: (event) => {
416
+ * getLogger().debug({
417
+ * category: 'EventBus',
418
+ * message: 'Published event',
419
+ * data: { type: event.type, id: event.id },
420
+ * correlationId: event.correlationid,
421
+ * });
422
+ * },
423
+ * });
424
+ * ```
425
+ */
426
+ export const setupEventBus = (name, options) => {
427
+ eventBusRegistry.set(name, new NimbusEventBus({ ...options, name }));
428
+ };
429
+ /**
430
+ * Get a named EventBus instance.
431
+ *
432
+ * If an EventBus with the given name has been configured via {@link setupEventBus},
433
+ * that instance is returned. Otherwise, a new EventBus with default options is created
434
+ * and registered.
435
+ *
436
+ * @param name - The name of the EventBus instance to retrieve. Defaults to 'default'.
437
+ * @returns The NimbusEventBus instance.
438
+ *
439
+ * @example
440
+ * ```ts
441
+ * import { createEvent, getEventBus } from '@nimbus/core';
442
+ *
443
+ * // Get the event bus configured earlier with setupEventBus
444
+ * const eventBus = getEventBus('default');
445
+ *
446
+ * // Subscribe to events
447
+ * eventBus.subscribeEvent({
448
+ * type: 'at.overlap.nimbus.order-created',
449
+ * handler: async (event) => {
450
+ * console.log('Order created:', event.data.orderId);
451
+ * },
452
+ * });
453
+ *
454
+ * // Publish an event
455
+ * const event = createEvent({
456
+ * type: 'at.overlap.nimbus.order-created',
457
+ * source: 'https://api.example.com',
458
+ * correlationid: '550e8400-e29b-41d4-a716-446655440000',
459
+ * data: { orderId: '12345', customerId: '67890' },
460
+ * datacontenttype: 'application/json',
461
+ * });
462
+ *
463
+ * eventBus.putEvent(event);
464
+ * ```
465
+ */
466
+ export const getEventBus = (name = 'default') => {
467
+ let eventBus = eventBusRegistry.get(name);
468
+ if (!eventBus) {
469
+ eventBus = new NimbusEventBus({ name });
470
+ eventBusRegistry.set(name, eventBus);
471
+ }
472
+ return eventBus;
473
+ };
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Base exception
3
+ */
4
+ export declare class Exception extends Error {
5
+ details?: Record<string, unknown>;
6
+ statusCode?: number;
7
+ constructor(name: string, message: string, details?: Record<string, unknown>, statusCode?: number);
8
+ fromError(error: Error): Exception;
9
+ }
10
+ //# sourceMappingURL=exception.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exception.d.ts","sourceRoot":"","sources":["../../../src/lib/exception/exception.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,qBAAa,SAAU,SAAQ,KAAK;IACzB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,UAAU,CAAC,EAAE,MAAM,CAAC;gBAGvB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACjC,UAAU,CAAC,EAAE,MAAM;IAmBhB,SAAS,CAAC,KAAK,EAAE,KAAK,GAAG,SAAS;CAM5C"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Base exception
3
+ */
4
+ export class Exception extends Error {
5
+ details;
6
+ statusCode;
7
+ constructor(name, message, details, statusCode) {
8
+ super(message);
9
+ this.name = name;
10
+ if (details) {
11
+ this.details = details;
12
+ }
13
+ if (statusCode) {
14
+ this.statusCode = statusCode;
15
+ }
16
+ // Maintains proper stack trace in V8 environments
17
+ if (Error.captureStackTrace) {
18
+ Error.captureStackTrace(this, this.constructor);
19
+ }
20
+ }
21
+ fromError(error) {
22
+ this.message = error.message;
23
+ this.stack = error.stack;
24
+ return this;
25
+ }
26
+ }
@@ -0,0 +1,8 @@
1
+ import { Exception } from './exception.js';
2
+ /**
3
+ * Forbidden exception
4
+ */
5
+ export declare class ForbiddenException extends Exception {
6
+ constructor(message?: string, details?: Record<string, unknown>);
7
+ }
8
+ //# sourceMappingURL=forbiddenException.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"forbiddenException.d.ts","sourceRoot":"","sources":["../../../src/lib/exception/forbiddenException.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE3C;;GAEG;AACH,qBAAa,kBAAmB,SAAQ,SAAS;gBACjC,OAAO,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;CAGlE"}
@@ -0,0 +1,9 @@
1
+ import { Exception } from './exception.js';
2
+ /**
3
+ * Forbidden exception
4
+ */
5
+ export class ForbiddenException extends Exception {
6
+ constructor(message, details) {
7
+ super('FORBIDDEN', message ?? 'Forbidden', details, 403);
8
+ }
9
+ }
@@ -0,0 +1,8 @@
1
+ import { Exception } from './exception.js';
2
+ /**
3
+ * Generic exception
4
+ */
5
+ export declare class GenericException extends Exception {
6
+ constructor(message?: string, details?: Record<string, unknown>);
7
+ }
8
+ //# sourceMappingURL=genericException.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"genericException.d.ts","sourceRoot":"","sources":["../../../src/lib/exception/genericException.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE3C;;GAEG;AACH,qBAAa,gBAAiB,SAAQ,SAAS;gBAC/B,OAAO,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;CAQlE"}
@@ -0,0 +1,9 @@
1
+ import { Exception } from './exception.js';
2
+ /**
3
+ * Generic exception
4
+ */
5
+ export class GenericException extends Exception {
6
+ constructor(message, details) {
7
+ super('INTERNAL_SERVER_ERROR', message ?? 'Internal server error', details, 500);
8
+ }
9
+ }
@@ -0,0 +1,18 @@
1
+ import type { ZodError } from 'zod';
2
+ import { Exception } from './exception.js';
3
+ /**
4
+ * Invalid input exception
5
+ */
6
+ export declare class InvalidInputException extends Exception {
7
+ constructor(message?: string, details?: Record<string, unknown>);
8
+ /**
9
+ * Takes a Zod error and creates an InvalidInputException from it.
10
+ * Takes care to preserve the stack and issues from the Zod error.
11
+ *
12
+ * @param {ZodError} error - The Zod error.
13
+ *
14
+ * @returns {InvalidInputException} The InvalidInputException.
15
+ */
16
+ fromZodError(error: ZodError): InvalidInputException;
17
+ }
18
+ //# sourceMappingURL=invalidInputException.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"invalidInputException.d.ts","sourceRoot":"","sources":["../../../src/lib/exception/invalidInputException.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,KAAK,CAAC;AACpC,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE3C;;GAEG;AACH,qBAAa,qBAAsB,SAAQ,SAAS;gBACpC,OAAO,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAS/D;;;;;;;OAOG;IACI,YAAY,CAAC,KAAK,EAAE,QAAQ,GAAG,qBAAqB;CAa9D"}
@@ -0,0 +1,28 @@
1
+ import { Exception } from './exception.js';
2
+ /**
3
+ * Invalid input exception
4
+ */
5
+ export class InvalidInputException extends Exception {
6
+ constructor(message, details) {
7
+ super('INVALID_INPUT', message ?? 'Invalid input', details, 400);
8
+ }
9
+ /**
10
+ * Takes a Zod error and creates an InvalidInputException from it.
11
+ * Takes care to preserve the stack and issues from the Zod error.
12
+ *
13
+ * @param {ZodError} error - The Zod error.
14
+ *
15
+ * @returns {InvalidInputException} The InvalidInputException.
16
+ */
17
+ fromZodError(error) {
18
+ if (error.stack) {
19
+ this.stack = error.stack;
20
+ }
21
+ if (error.issues) {
22
+ this.details = {
23
+ issues: error.issues,
24
+ };
25
+ }
26
+ return this;
27
+ }
28
+ }
@@ -0,0 +1,8 @@
1
+ import { Exception } from './exception.js';
2
+ /**
3
+ * Not found exception
4
+ */
5
+ export declare class NotFoundException extends Exception {
6
+ constructor(message?: string, details?: Record<string, unknown>);
7
+ }
8
+ //# sourceMappingURL=notFoundException.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notFoundException.d.ts","sourceRoot":"","sources":["../../../src/lib/exception/notFoundException.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE3C;;GAEG;AACH,qBAAa,iBAAkB,SAAQ,SAAS;gBAChC,OAAO,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;CAGlE"}
@@ -0,0 +1,9 @@
1
+ import { Exception } from './exception.js';
2
+ /**
3
+ * Not found exception
4
+ */
5
+ export class NotFoundException extends Exception {
6
+ constructor(message, details) {
7
+ super('NOT_FOUND', message ?? 'Not found', details, 404);
8
+ }
9
+ }
@@ -0,0 +1,8 @@
1
+ import { Exception } from './exception.js';
2
+ /**
3
+ * Unauthorized exception
4
+ */
5
+ export declare class UnauthorizedException extends Exception {
6
+ constructor(message?: string, details?: Record<string, unknown>);
7
+ }
8
+ //# sourceMappingURL=unauthorizedException.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"unauthorizedException.d.ts","sourceRoot":"","sources":["../../../src/lib/exception/unauthorizedException.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE3C;;GAEG;AACH,qBAAa,qBAAsB,SAAQ,SAAS;gBACpC,OAAO,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;CAQlE"}
@@ -0,0 +1,9 @@
1
+ import { Exception } from './exception.js';
2
+ /**
3
+ * Unauthorized exception
4
+ */
5
+ export class UnauthorizedException extends Exception {
6
+ constructor(message, details) {
7
+ super('UNAUTHORIZED', message ?? 'Unauthorized', details, 401);
8
+ }
9
+ }