@haskou/ddd-kernel 0.1.1 → 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 (120) hide show
  1. package/README.md +5 -10
  2. package/dist/DomainEventConsumer-Bg-bOwmh.d.cts +11 -0
  3. package/dist/DomainEventConsumer-BroJmVty.d.ts +11 -0
  4. package/dist/DomainMessageBus-3jYk7TPw.d.ts +13 -0
  5. package/dist/DomainMessageBus-OyliPu3Z.d.cts +13 -0
  6. package/dist/MessageBus-BtUXnd0Y.d.cts +10 -0
  7. package/dist/MessageBus-oQ9BnW84.d.ts +10 -0
  8. package/dist/{NoFailedMessagesError-0YJKRWPF.d.ts → NoFailedMessagesError-BLpGI-G4.d.ts} +6 -1
  9. package/dist/{NoFailedMessagesError-Kz7CYWpT.d.cts → NoFailedMessagesError-BjxYoKTR.d.cts} +6 -1
  10. package/dist/PublisherHookErrorPolicy-CjouTcSR.d.cts +8 -0
  11. package/dist/PublisherHookErrorPolicy-DSsCNE6O.d.ts +8 -0
  12. package/dist/RetryPredicate-U7dYnQ4N.d.ts +15 -0
  13. package/dist/RetryPredicate-yT_z9zk1.d.cts +15 -0
  14. package/dist/{Scheduler-oigqNOUJ.d.ts → Scheduler-BW-U5Ccg.d.cts} +1 -1
  15. package/dist/{Scheduler-oigqNOUJ.d.cts → Scheduler-BW-U5Ccg.d.ts} +1 -1
  16. package/dist/ServiceClass-BkEHcXDi.d.cts +72 -0
  17. package/dist/ServiceClass-Bq_fBC5R.d.ts +72 -0
  18. package/dist/{Kernel-BWUOUWWI.d.cts → ShutdownHook-BjbnCKzr.d.cts} +49 -7
  19. package/dist/{Kernel-CUaqHa1s.d.ts → ShutdownHook-CMWLsfu-.d.ts} +49 -7
  20. package/dist/Subscription-4vuAAxax.d.cts +23 -0
  21. package/dist/Subscription-vtF0lEHP.d.ts +23 -0
  22. package/dist/adapters/index.cjs +665 -37
  23. package/dist/adapters/index.cjs.map +1 -1
  24. package/dist/adapters/index.d.cts +15 -13
  25. package/dist/adapters/index.d.ts +15 -13
  26. package/dist/adapters/index.js +659 -37
  27. package/dist/adapters/index.js.map +1 -1
  28. package/dist/adapters/pubsub/amqp/index.cjs +241 -16
  29. package/dist/adapters/pubsub/amqp/index.cjs.map +1 -1
  30. package/dist/adapters/pubsub/amqp/index.d.cts +16 -8
  31. package/dist/adapters/pubsub/amqp/index.d.ts +16 -8
  32. package/dist/adapters/pubsub/amqp/index.js +241 -16
  33. package/dist/adapters/pubsub/amqp/index.js.map +1 -1
  34. package/dist/adapters/pubsub/in-memory/index.cjs +96 -8
  35. package/dist/adapters/pubsub/in-memory/index.cjs.map +1 -1
  36. package/dist/adapters/pubsub/in-memory/index.d.cts +9 -3
  37. package/dist/adapters/pubsub/in-memory/index.d.ts +9 -3
  38. package/dist/adapters/pubsub/in-memory/index.js +96 -8
  39. package/dist/adapters/pubsub/in-memory/index.js.map +1 -1
  40. package/dist/adapters/pubsub/index.cjs +397 -27
  41. package/dist/adapters/pubsub/index.cjs.map +1 -1
  42. package/dist/adapters/pubsub/index.d.cts +89 -7
  43. package/dist/adapters/pubsub/index.d.ts +89 -7
  44. package/dist/adapters/pubsub/index.js +389 -26
  45. package/dist/adapters/pubsub/index.js.map +1 -1
  46. package/dist/adapters/ui/express/index.cjs +279 -11
  47. package/dist/adapters/ui/express/index.cjs.map +1 -1
  48. package/dist/adapters/ui/express/index.d.cts +127 -12
  49. package/dist/adapters/ui/express/index.d.ts +127 -12
  50. package/dist/adapters/ui/express/index.js +270 -11
  51. package/dist/adapters/ui/express/index.js.map +1 -1
  52. package/dist/adapters/ui/index.cjs +412 -27
  53. package/dist/adapters/ui/index.cjs.map +1 -1
  54. package/dist/adapters/ui/index.d.cts +7 -8
  55. package/dist/adapters/ui/index.d.ts +7 -8
  56. package/dist/adapters/ui/index.js +413 -27
  57. package/dist/adapters/ui/index.js.map +1 -1
  58. package/dist/adapters/ui/routes/index.cjs +136 -9
  59. package/dist/adapters/ui/routes/index.cjs.map +1 -1
  60. package/dist/adapters/ui/routes/index.js +136 -9
  61. package/dist/adapters/ui/routes/index.js.map +1 -1
  62. package/dist/contracts/index.cjs +16 -17
  63. package/dist/contracts/index.cjs.map +1 -1
  64. package/dist/contracts/index.d.cts +10 -2
  65. package/dist/contracts/index.d.ts +10 -2
  66. package/dist/contracts/index.js +16 -17
  67. package/dist/contracts/index.js.map +1 -1
  68. package/dist/contracts/kernel/index.cjs.map +1 -1
  69. package/dist/contracts/kernel/index.d.cts +7 -1
  70. package/dist/contracts/kernel/index.d.ts +7 -1
  71. package/dist/contracts/pubsub/index.cjs.map +1 -1
  72. package/dist/contracts/pubsub/index.d.cts +5 -1
  73. package/dist/contracts/pubsub/index.d.ts +5 -1
  74. package/dist/contracts/ui/index.cjs +16 -17
  75. package/dist/contracts/ui/index.cjs.map +1 -1
  76. package/dist/contracts/ui/index.d.cts +16 -16
  77. package/dist/contracts/ui/index.d.ts +16 -16
  78. package/dist/contracts/ui/index.js +16 -17
  79. package/dist/contracts/ui/index.js.map +1 -1
  80. package/dist/domain/index.cjs.map +1 -1
  81. package/dist/domain/index.d.cts +6 -2
  82. package/dist/domain/index.d.ts +6 -2
  83. package/dist/domain/index.js.map +1 -1
  84. package/dist/index.cjs +152 -26
  85. package/dist/index.cjs.map +1 -1
  86. package/dist/index.d.cts +8 -7
  87. package/dist/index.d.ts +8 -7
  88. package/dist/index.js +152 -26
  89. package/dist/index.js.map +1 -1
  90. package/dist/infrastructure/dependency-injection/index.cjs +119 -3
  91. package/dist/infrastructure/dependency-injection/index.cjs.map +1 -1
  92. package/dist/infrastructure/dependency-injection/index.d.cts +4 -1
  93. package/dist/infrastructure/dependency-injection/index.d.ts +4 -1
  94. package/dist/infrastructure/dependency-injection/index.js +119 -3
  95. package/dist/infrastructure/dependency-injection/index.js.map +1 -1
  96. package/dist/infrastructure/express/index.cjs +279 -11
  97. package/dist/infrastructure/express/index.cjs.map +1 -1
  98. package/dist/infrastructure/express/index.d.cts +7 -8
  99. package/dist/infrastructure/express/index.d.ts +7 -8
  100. package/dist/infrastructure/express/index.js +270 -11
  101. package/dist/infrastructure/express/index.js.map +1 -1
  102. package/dist/infrastructure/scheduler/index.cjs +136 -9
  103. package/dist/infrastructure/scheduler/index.cjs.map +1 -1
  104. package/dist/infrastructure/scheduler/index.d.cts +2 -2
  105. package/dist/infrastructure/scheduler/index.d.ts +2 -2
  106. package/dist/infrastructure/scheduler/index.js +136 -9
  107. package/dist/infrastructure/scheduler/index.js.map +1 -1
  108. package/package.json +92 -17
  109. package/dist/Consumer-CC8ZRCsd.d.cts +0 -17
  110. package/dist/Consumer-CeT0Wbxb.d.ts +0 -17
  111. package/dist/DomainEventConsumer-3WBMSSr2.d.cts +0 -7
  112. package/dist/DomainEventConsumer-B4hkIUmP.d.ts +0 -7
  113. package/dist/DomainEventPublisher-8G0lvmdy.d.cts +0 -7
  114. package/dist/DomainEventPublisher-DhGgM3f2.d.ts +0 -7
  115. package/dist/ServiceClass-BmNw8fJj.d.cts +0 -37
  116. package/dist/ServiceClass-C7NCKdSS.d.ts +0 -37
  117. package/dist/ShutdownHook-BGskq2-q.d.ts +0 -9
  118. package/dist/ShutdownHook-Dib5uNKB.d.cts +0 -9
  119. package/dist/Subscription-Bwkb_did.d.ts +0 -9
  120. package/dist/Subscription-P9WROD_6.d.cts +0 -9
@@ -32,13 +32,21 @@ var adapters_exports = {};
32
32
  __export(adapters_exports, {
33
33
  ConsoleKernelLogger: () => ConsoleKernelLogger,
34
34
  Consumer: () => Consumer,
35
+ ConsumerMiddlewarePipeline: () => ConsumerMiddlewarePipeline,
36
+ CorrelationConsumerMiddleware: () => CorrelationConsumerMiddleware,
37
+ DefaultPublisherHookErrorPolicy: () => DefaultPublisherHookErrorPolicy,
35
38
  ExpressKernelServer: () => ExpressKernelServer,
39
+ HttpErrorHandler: () => HttpErrorHandler,
40
+ IdempotencyConsumerMiddleware: () => IdempotencyConsumerMiddleware,
36
41
  InMemoryEventBus: () => InMemoryEventBus,
42
+ InMemoryIdempotencyStore: () => InMemoryIdempotencyStore,
37
43
  InMemoryPubSub: () => InMemoryPubSub,
38
44
  InMemoryRepository: () => InMemoryRepository,
39
45
  InvalidDomainEventError: () => InvalidDomainEventError,
40
46
  MongoRepository: () => MongoRepository,
41
47
  NoFailedMessagesError: () => NoFailedMessagesError,
48
+ PublisherHookPipeline: () => PublisherHookPipeline,
49
+ RetryConsumerMiddleware: () => RetryConsumerMiddleware,
42
50
  Route: () => Route,
43
51
  RoutePrefix: () => RoutePrefix
44
52
  });
@@ -134,6 +142,7 @@ var DependencyInjection = class _DependencyInjection {
134
142
  autowire;
135
143
  loader;
136
144
  container;
145
+ overrideTokenIds = /* @__PURE__ */ new Map();
137
146
  static configure(options) {
138
147
  _DependencyInjection.configuredInstance = new _DependencyInjection(options);
139
148
  return _DependencyInjection.configuredInstance;
@@ -158,6 +167,16 @@ var DependencyInjection = class _DependencyInjection {
158
167
  getServiceClassName(serviceName) {
159
168
  return typeof serviceName === "function" ? serviceName.name : void 0;
160
169
  }
170
+ getOverrideId(prefix, token) {
171
+ const tokenName = this.getServiceClassName(token) ?? String(token);
172
+ return `ddd-kernel.override.${prefix}.${tokenName}`;
173
+ }
174
+ ensureSyntheticService(id, value) {
175
+ const definition = this.container.register(id);
176
+ definition.public = true;
177
+ definition.synthetic = true;
178
+ this.container.set(id, value);
179
+ }
161
180
  parentMatchesService(parentId, serviceClassName) {
162
181
  if (!parentId) {
163
182
  return false;
@@ -169,6 +188,26 @@ var DependencyInjection = class _DependencyInjection {
169
188
  const serviceName = Buffer.from(serviceId, "base64").toString("utf8");
170
189
  return serviceName.endsWith(`__${serviceClassName}__${serviceClassName}`);
171
190
  }
191
+ serviceIdReferencesService(serviceId, serviceClassName) {
192
+ const serviceName = Buffer.from(serviceId, "base64").toString("utf8");
193
+ return serviceName.endsWith(`__${serviceClassName}`);
194
+ }
195
+ getReferenceId(value) {
196
+ if (typeof value === "object" && value !== null && "id" in value && typeof value.id === "string") {
197
+ return value.id;
198
+ }
199
+ return void 0;
200
+ }
201
+ getDefinitionArgumentReferences(definition) {
202
+ return [
203
+ ...definition._args ?? [],
204
+ ...definition._appendArgs ?? [],
205
+ ...definition._overrideArgs ?? []
206
+ ].flatMap((argument) => {
207
+ const referenceId = this.getReferenceId(argument);
208
+ return referenceId ? [referenceId] : [];
209
+ });
210
+ }
172
211
  findConcreteChildServiceId(serviceName) {
173
212
  const serviceClassName = this.getServiceClassName(serviceName);
174
213
  if (!serviceClassName) {
@@ -199,6 +238,86 @@ var DependencyInjection = class _DependencyInjection {
199
238
  );
200
239
  return matches[matches.length - 1];
201
240
  }
241
+ findReferencedServiceIds(serviceName) {
242
+ const serviceClassName = this.getServiceClassName(serviceName);
243
+ if (!serviceClassName) {
244
+ return [];
245
+ }
246
+ return [
247
+ ...new Set(
248
+ [...this.definitions.values()].flatMap(
249
+ (definition) => this.getDefinitionArgumentReferences(definition)
250
+ ).filter(
251
+ (id) => this.serviceIdReferencesService(id, serviceClassName)
252
+ )
253
+ )
254
+ ];
255
+ }
256
+ getOverrideTokenIds(token) {
257
+ const tokenIds = [
258
+ this.findRegisteredServiceId(token),
259
+ this.findAliasServiceId(token),
260
+ ...this.findReferencedServiceIds(token)
261
+ ].filter((id) => id !== void 0);
262
+ const existingTokenIds = [...new Set(tokenIds)];
263
+ if (existingTokenIds.length > 0) {
264
+ return existingTokenIds;
265
+ }
266
+ const overrideTokenId = this.getOverrideId("token", token);
267
+ this.ensureSyntheticService(overrideTokenId, void 0);
268
+ return [overrideTokenId];
269
+ }
270
+ getOverrideClassServiceId(ClassDefinition) {
271
+ const registeredServiceId = this.findRegisteredServiceId(ClassDefinition);
272
+ if (registeredServiceId) {
273
+ return registeredServiceId;
274
+ }
275
+ const overrideClassId = this.getOverrideId("class", ClassDefinition);
276
+ this.container.register(overrideClassId, ClassDefinition);
277
+ return overrideClassId;
278
+ }
279
+ applyClassOverride(override) {
280
+ if (!("useClass" in override)) {
281
+ return;
282
+ }
283
+ const tokenIds = this.getOverrideTokenIds(override.token);
284
+ const classId = this.getOverrideClassServiceId(override.useClass);
285
+ this.overrideTokenIds.set(override.token, tokenIds[0]);
286
+ for (const tokenId of tokenIds) {
287
+ this.container.setAlias(tokenId, classId);
288
+ }
289
+ }
290
+ applyFactoryOverride(override) {
291
+ if (!("useFactory" in override)) {
292
+ return;
293
+ }
294
+ const tokenIds = this.getOverrideTokenIds(override.token);
295
+ const factoryId = this.getOverrideId("factory", override.token);
296
+ this.ensureSyntheticService(factoryId, override.useFactory(this));
297
+ this.overrideTokenIds.set(override.token, tokenIds[0]);
298
+ for (const tokenId of tokenIds) {
299
+ this.container.setAlias(tokenId, factoryId);
300
+ }
301
+ }
302
+ applyValueOverride(override) {
303
+ if (!("useValue" in override)) {
304
+ return;
305
+ }
306
+ const tokenIds = this.getOverrideTokenIds(override.token);
307
+ const valueId = this.getOverrideId("value", override.token);
308
+ this.ensureSyntheticService(valueId, override.useValue);
309
+ this.overrideTokenIds.set(override.token, tokenIds[0]);
310
+ for (const tokenId of tokenIds) {
311
+ this.container.setAlias(tokenId, valueId);
312
+ }
313
+ }
314
+ applyOverrides() {
315
+ for (const override of this.options.overrides ?? []) {
316
+ this.applyClassOverride(override);
317
+ this.applyFactoryOverride(override);
318
+ this.applyValueOverride(override);
319
+ }
320
+ }
202
321
  registerParentAliases() {
203
322
  for (const [id, definition] of this.definitions.entries()) {
204
323
  if (definition._abstract === true || !definition._parent) {
@@ -221,17 +340,22 @@ var DependencyInjection = class _DependencyInjection {
221
340
  await this.loader.load(this.options.servicesYamlPath);
222
341
  }
223
342
  this.registerParentAliases();
343
+ this.applyOverrides();
224
344
  await this.container.compile();
225
345
  }
226
346
  getService(serviceName) {
227
- const childServiceId = this.findConcreteChildServiceId(serviceName);
228
- if (childServiceId) {
229
- return this.container.get(childServiceId);
347
+ const overrideTokenId = this.overrideTokenIds.get(serviceName);
348
+ if (overrideTokenId) {
349
+ return this.container.get(overrideTokenId);
230
350
  }
231
351
  const aliasServiceId = this.findAliasServiceId(serviceName);
232
352
  if (aliasServiceId) {
233
353
  return this.container.get(aliasServiceId);
234
354
  }
355
+ const childServiceId = this.findConcreteChildServiceId(serviceName);
356
+ if (childServiceId) {
357
+ return this.container.get(childServiceId);
358
+ }
235
359
  const registeredServiceId = this.findRegisteredServiceId(serviceName);
236
360
  if (registeredServiceId) {
237
361
  return this.container.get(registeredServiceId);
@@ -279,6 +403,9 @@ var Kernel = class _Kernel {
279
403
  static get logger() {
280
404
  return _Kernel.getActiveKernel().logger;
281
405
  }
406
+ static get active() {
407
+ return _Kernel.getActiveKernel();
408
+ }
282
409
  static get rootDirectory() {
283
410
  return process.cwd();
284
411
  }
@@ -347,13 +474,21 @@ var Kernel = class _Kernel {
347
474
  get schedulers() {
348
475
  return this.schedulersList;
349
476
  }
350
- async dependencyInjection() {
351
- this.dependencyInjectionInstance = this.dependencyInjectionInstance ?? DependencyInjection.configure({
352
- containerBuild: process.env.CONTAINER_BUILD === "true",
353
- servicesYamlPath: this.options.servicesYamlPath ?? import_node_path2.default.resolve(_Kernel.configDirectory, "container", "services.yaml"),
354
- sourceDirectory: this.options.sourceDirectory ?? _Kernel.sourceDirectory
355
- });
477
+ getDependencyInjectionOptions(options = {}) {
478
+ return {
479
+ containerBuild: options.containerBuild ?? process.env.CONTAINER_BUILD === "true",
480
+ overrides: options.overrides ?? [],
481
+ servicesYamlPath: options.servicesYamlPath ?? this.options.servicesYamlPath ?? import_node_path2.default.resolve(_Kernel.configDirectory, "container", "services.yaml"),
482
+ sourceDirectory: options.sourceDirectory ?? this.options.sourceDirectory ?? _Kernel.sourceDirectory
483
+ };
484
+ }
485
+ async dependencyInjection(options = {}) {
486
+ _Kernel.state.activeKernel = this;
487
+ this.dependencyInjectionInstance = this.dependencyInjectionInstance ?? DependencyInjection.configure(
488
+ this.getDependencyInjectionOptions(options)
489
+ );
356
490
  await this.dependencyInjectionInstance.compile();
491
+ _Kernel.state.activeKernel = this;
357
492
  }
358
493
  getRoutes() {
359
494
  return this.routes;
@@ -436,21 +571,52 @@ var Kernel = class _Kernel {
436
571
  }
437
572
  };
438
573
 
574
+ // src/adapters/pubsub/ConsumerMiddlewarePipeline.ts
575
+ var ConsumerMiddlewarePipeline = class {
576
+ constructor(middlewares) {
577
+ this.middlewares = middlewares;
578
+ }
579
+ middlewares;
580
+ async run(event, context, handler, index) {
581
+ const middleware = this.middlewares[index];
582
+ if (!middleware) {
583
+ await handler();
584
+ return;
585
+ }
586
+ await middleware.handle(
587
+ event,
588
+ () => this.run(event, context, handler, index + 1),
589
+ context
590
+ );
591
+ }
592
+ async execute(event, context, handler) {
593
+ await this.run(event, context, handler, 0);
594
+ }
595
+ };
596
+
439
597
  // src/adapters/pubsub/Consumer.ts
440
598
  var Consumer = class {
441
599
  constructor(consumer) {
442
600
  this.consumer = consumer;
443
601
  }
444
602
  consumer;
445
- async runMiddleware(event, middlewares, index) {
446
- const middleware = middlewares[index];
447
- if (!middleware) {
448
- await this.handler(event);
449
- return;
450
- }
451
- await middleware.handle(
603
+ async runMiddleware(event, consumerContext) {
604
+ const pipeline = new ConsumerMiddlewarePipeline(Kernel.consumerMiddleware);
605
+ const metadata = consumerContext?.metadata ?? {};
606
+ await pipeline.execute(
452
607
  event,
453
- () => this.runMiddleware(event, middlewares, index + 1)
608
+ {
609
+ causationId: event.getCausationId(),
610
+ correlationId: event.getCorrelationId(),
611
+ eventId: event.eventId,
612
+ eventName: this.eventName,
613
+ exchange: this.exchange,
614
+ kernel: Kernel.active,
615
+ metadata,
616
+ queueName: this.queueName,
617
+ rawMessage: metadata.rawMessage
618
+ },
619
+ () => this.handler(event)
454
620
  );
455
621
  }
456
622
  async init() {
@@ -459,7 +625,7 @@ var Consumer = class {
459
625
  this.eventName,
460
626
  this.domainEvent,
461
627
  this.exchange,
462
- (event) => this.runMiddleware(event, Kernel.consumerMiddleware, 0)
628
+ (event, context) => this.runMiddleware(event, context)
463
629
  );
464
630
  }
465
631
  get(service) {
@@ -467,6 +633,178 @@ var Consumer = class {
467
633
  }
468
634
  };
469
635
 
636
+ // src/adapters/pubsub/CorrelationConsumerMiddleware.ts
637
+ var CorrelationConsumerMiddleware = class {
638
+ constructor(options = {}) {
639
+ this.options = options;
640
+ }
641
+ options;
642
+ async handle(event, next, context) {
643
+ const correlationId = this.options.correlationId?.(event, context) ?? context.correlationId;
644
+ const causationId = this.options.causationId?.(event, context) ?? context.causationId;
645
+ if (correlationId) {
646
+ event.withCorrelationId(correlationId);
647
+ }
648
+ if (causationId) {
649
+ event.withCausationId(causationId);
650
+ }
651
+ await next();
652
+ }
653
+ };
654
+
655
+ // src/adapters/pubsub/DefaultPublisherHookErrorPolicy.ts
656
+ var DefaultPublisherHookErrorPolicy = class {
657
+ handleAfterPublishError(error, context) {
658
+ void error;
659
+ void context;
660
+ }
661
+ shouldFailAfterPublish(error, context) {
662
+ void error;
663
+ void context;
664
+ return false;
665
+ }
666
+ };
667
+
668
+ // src/adapters/pubsub/IdempotencyConsumerMiddleware.ts
669
+ var IdempotencyConsumerMiddleware = class {
670
+ constructor(options) {
671
+ this.options = options;
672
+ }
673
+ options;
674
+ async handleClaimedKey(key, next) {
675
+ const claimed = await this.options.store.claim?.(key);
676
+ if (!claimed) {
677
+ return;
678
+ }
679
+ try {
680
+ await next();
681
+ await (this.options.store.commit?.(key) ?? this.options.store.mark(key));
682
+ } catch (error) {
683
+ await this.options.store.release?.(key);
684
+ throw error;
685
+ }
686
+ }
687
+ async handleLegacyKey(key, next) {
688
+ if (await this.options.store.has(key)) {
689
+ return;
690
+ }
691
+ await next();
692
+ await this.options.store.mark(key);
693
+ }
694
+ async handle(event, next, context) {
695
+ const key = this.options.key?.(event, context) ?? context.eventId;
696
+ if (this.options.store.claim) {
697
+ await this.handleClaimedKey(key, next);
698
+ } else {
699
+ await this.handleLegacyKey(key, next);
700
+ }
701
+ }
702
+ };
703
+
704
+ // src/adapters/pubsub/InMemoryIdempotencyStore.ts
705
+ var InMemoryIdempotencyStore = class {
706
+ claimedKeys = /* @__PURE__ */ new Set();
707
+ handledKeys = /* @__PURE__ */ new Set();
708
+ claim(key) {
709
+ if (this.handledKeys.has(key) || this.claimedKeys.has(key)) {
710
+ return false;
711
+ }
712
+ this.claimedKeys.add(key);
713
+ return true;
714
+ }
715
+ commit(key) {
716
+ this.claimedKeys.delete(key);
717
+ this.handledKeys.add(key);
718
+ }
719
+ release(key) {
720
+ this.claimedKeys.delete(key);
721
+ }
722
+ has(key) {
723
+ return this.handledKeys.has(key);
724
+ }
725
+ mark(key) {
726
+ this.handledKeys.add(key);
727
+ }
728
+ };
729
+
730
+ // src/adapters/pubsub/PublisherHookPipeline.ts
731
+ var PublisherHookPipeline = class {
732
+ constructor(hooks = [], errorPolicy = new DefaultPublisherHookErrorPolicy()) {
733
+ this.errorPolicy = errorPolicy;
734
+ this.hooks.push(...hooks);
735
+ }
736
+ errorPolicy;
737
+ hooks = [];
738
+ async runAfterPublishHooks(context) {
739
+ for (const hook of this.hooks) {
740
+ await this.runAfterPublishHook(hook, context);
741
+ }
742
+ }
743
+ async runAfterPublishHook(hook, context) {
744
+ try {
745
+ await hook.afterPublish?.(context);
746
+ } catch (error) {
747
+ await this.errorPolicy.handleAfterPublishError(error, context);
748
+ if (this.errorPolicy.shouldFailAfterPublish(error, context)) {
749
+ throw error;
750
+ }
751
+ }
752
+ }
753
+ async runBeforePublishHooks(context) {
754
+ for (const hook of this.hooks) {
755
+ await hook.beforePublish?.(context);
756
+ }
757
+ }
758
+ async runPublishErrorHooks(error, context) {
759
+ for (const hook of this.hooks) {
760
+ await hook.onPublishError?.(error, context);
761
+ }
762
+ }
763
+ register(...hooks) {
764
+ this.hooks.push(...hooks);
765
+ }
766
+ async run(context, publish) {
767
+ await this.runBeforePublishHooks(context);
768
+ try {
769
+ const result = await publish();
770
+ await this.runAfterPublishHooks(context);
771
+ return result;
772
+ } catch (error) {
773
+ await this.runPublishErrorHooks(error, context);
774
+ throw error;
775
+ }
776
+ }
777
+ };
778
+
779
+ // src/adapters/pubsub/RetryConsumerMiddleware.ts
780
+ var RetryConsumerMiddleware = class {
781
+ constructor(options) {
782
+ this.options = options;
783
+ }
784
+ options;
785
+ async delay(attempt, error, context) {
786
+ const delayInMilliseconds = typeof this.options.delay === "function" ? await this.options.delay(attempt, error, context) : this.options.delay ?? 0;
787
+ if (delayInMilliseconds > 0) {
788
+ await new Promise((resolve) => setTimeout(resolve, delayInMilliseconds));
789
+ }
790
+ }
791
+ async handle(event, next, context) {
792
+ for (let attempt = 1; attempt <= this.options.maxAttempts; attempt++) {
793
+ try {
794
+ await next();
795
+ return;
796
+ } catch (error) {
797
+ const canRetry = attempt < this.options.maxAttempts && await (this.options.shouldRetry?.(error, attempt, context) ?? true);
798
+ if (!canRetry) {
799
+ throw error;
800
+ }
801
+ await this.options.onRetry?.(error, attempt, context);
802
+ await this.delay(attempt, error, context);
803
+ }
804
+ }
805
+ }
806
+ };
807
+
470
808
  // src/adapters/pubsub/amqp/AmqpMessageBusAdapter.ts
471
809
  var import_amqplib = __toESM(require("amqplib"), 1);
472
810
  var import_node_crypto = require("crypto");
@@ -489,11 +827,16 @@ var NoFailedMessagesError = class extends Error {
489
827
 
490
828
  // src/adapters/pubsub/in-memory/InMemoryEventBus.ts
491
829
  var InMemoryEventBus = class {
492
- constructor(context) {
830
+ constructor(context, publisherHooks = [], publisherHookErrorPolicy) {
493
831
  this.context = context;
832
+ this.publisherHookPipeline = new PublisherHookPipeline(
833
+ publisherHooks,
834
+ publisherHookErrorPolicy
835
+ );
494
836
  }
495
837
  context;
496
838
  handlers = /* @__PURE__ */ new Map();
839
+ publisherHookPipeline;
497
840
  subscribe(name, handler) {
498
841
  const handlers = this.handlers.get(name) ?? [];
499
842
  handlers.push(handler);
@@ -501,24 +844,42 @@ var InMemoryEventBus = class {
501
844
  }
502
845
  async publish(event) {
503
846
  const handlers = this.handlers.get(event.name) ?? [];
504
- for (const handler of handlers) {
505
- await handler(event, this.context);
506
- }
847
+ await this.publisherHookPipeline.run(
848
+ { message: event, metadata: event.metadata ?? {}, topic: event.name },
849
+ async () => {
850
+ for (const handler of handlers) {
851
+ await handler(event, this.context);
852
+ }
853
+ }
854
+ );
855
+ }
856
+ registerPublisherHooks(...hooks) {
857
+ this.publisherHookPipeline.register(...hooks);
507
858
  }
508
859
  };
509
860
 
510
861
  // src/adapters/pubsub/in-memory/InMemoryPubSub.ts
511
862
  var InMemoryPubSub = class {
512
- constructor(context) {
863
+ constructor(context, publisherHooks = [], publisherHookErrorPolicy) {
513
864
  this.context = context;
865
+ this.publisherHookPipeline = new PublisherHookPipeline(
866
+ publisherHooks,
867
+ publisherHookErrorPolicy
868
+ );
514
869
  }
515
870
  context;
516
871
  consumers = /* @__PURE__ */ new Map();
872
+ publisherHookPipeline;
517
873
  async publish(topic, message) {
518
874
  const consumers = this.consumers.get(topic) ?? /* @__PURE__ */ new Set();
519
- for (const consumer of consumers) {
520
- await consumer(message, this.context);
521
- }
875
+ await this.publisherHookPipeline.run(
876
+ { message, metadata: message.metadata ?? {}, topic },
877
+ async () => {
878
+ for (const consumer of consumers) {
879
+ await consumer(message, this.context);
880
+ }
881
+ }
882
+ );
522
883
  }
523
884
  subscribe(topic, consumer) {
524
885
  const consumers = this.consumers.get(topic) ?? /* @__PURE__ */ new Set();
@@ -532,31 +893,100 @@ var InMemoryPubSub = class {
532
893
  }
533
894
  });
534
895
  }
896
+ registerPublisherHooks(...hooks) {
897
+ this.publisherHookPipeline.register(...hooks);
898
+ }
535
899
  };
536
900
 
537
901
  // src/adapters/ui/express/ExpressKernelServer.ts
538
- var import_routing_controllers = require("routing-controllers");
902
+ var import_node_module = require("module");
903
+ var import_node_path3 = __toESM(require("path"), 1);
539
904
  var ExpressKernelServer = class {
540
905
  constructor(options) {
541
906
  this.options = options;
907
+ this.afterControllersHooks = this.copy(options.afterControllersHooks);
908
+ this.beforeControllersHooks = this.copy(options.beforeControllersHooks);
909
+ this.controllers = this.copy(options.controllers);
910
+ this.errorHandlers = this.copy(options.errorHandlers);
911
+ this.hooks = this.copy(options.hooks);
912
+ this.middlewares = this.copy(options.middlewares);
913
+ this.postControllerMiddlewares = this.copy(
914
+ options.postControllerMiddlewares
915
+ );
916
+ this.preControllerMiddlewares = this.copy(options.preControllerMiddlewares);
917
+ this.staticHooks = this.copy(options.staticHooks);
918
+ this.swaggerHooks = this.copy(options.swaggerHooks);
542
919
  }
543
920
  options;
921
+ applicationRequire = (0, import_node_module.createRequire)(
922
+ import_node_path3.default.resolve(process.cwd(), "package.json")
923
+ );
924
+ afterControllersHooks;
544
925
  appInstance;
926
+ beforeControllersHooks;
927
+ controllers;
928
+ errorHandlers;
929
+ hooks;
930
+ middlewares;
931
+ postControllerMiddlewares;
932
+ preControllerMiddlewares;
545
933
  serverInstance;
546
- registerErrorHandlers(app) {
547
- const handlers = this.options.errorHandlers ?? [this.defaultErrorHandler()];
934
+ staticHooks;
935
+ swaggerHooks;
936
+ copy(items) {
937
+ return [...items ?? []];
938
+ }
939
+ configureControllerContainer() {
940
+ const { useContainer } = this.getRoutingControllers();
941
+ useContainer(
942
+ {
943
+ /* c8 ignore next */
944
+ get: (ClassDefinition) => this.options.kernel.di.getService(ClassDefinition)
945
+ },
946
+ {
947
+ fallback: true,
948
+ fallbackOnErrors: true
949
+ }
950
+ );
951
+ }
952
+ getExpress() {
953
+ return this.applicationRequire("express");
954
+ }
955
+ getRoutingControllers() {
956
+ return this.applicationRequire("routing-controllers");
957
+ }
958
+ applyErrorHandlers(app) {
959
+ const handlers = this.errorHandlers.length > 0 ? this.errorHandlers : [this.defaultErrorHandler()];
548
960
  for (const handler of handlers) {
549
961
  app.use(handler);
550
962
  }
551
963
  }
552
964
  defaultErrorHandler() {
553
- return (error, request, response) => {
965
+ return (error, request, response, next) => {
966
+ void next;
554
967
  void request;
555
968
  response.status(500).json({
556
969
  error: error instanceof Error ? error.message : String(error)
557
970
  });
558
971
  };
559
972
  }
973
+ async runHooks(hooks, app) {
974
+ for (const hook of hooks) {
975
+ await hook(app);
976
+ }
977
+ }
978
+ async runPhaseHooks(phase, app) {
979
+ for (const hook of this.hooks) {
980
+ if (hook.phase === phase) {
981
+ await hook.handle(app);
982
+ }
983
+ }
984
+ }
985
+ applyMiddlewares(app, middlewares) {
986
+ for (const middleware of middlewares) {
987
+ app.use(middleware);
988
+ }
989
+ }
560
990
  get app() {
561
991
  if (!this.appInstance) {
562
992
  throw new Error("HTTP server is not running.");
@@ -569,6 +999,11 @@ var ExpressKernelServer = class {
569
999
  }
570
1000
  return this.serverInstance;
571
1001
  }
1002
+ assertServerIsNotRunning() {
1003
+ if (this.serverInstance) {
1004
+ throw new Error("HTTP server is already running.");
1005
+ }
1006
+ }
572
1007
  close() {
573
1008
  if (!this.serverInstance) {
574
1009
  return Promise.resolve();
@@ -585,15 +1020,74 @@ var ExpressKernelServer = class {
585
1020
  });
586
1021
  });
587
1022
  }
588
- run() {
589
- const app = (0, import_routing_controllers.createExpressServer)({
590
- controllers: this.options.kernel.getRoutes(),
1023
+ registerAfterControllersHooks(...hooks) {
1024
+ this.assertServerIsNotRunning();
1025
+ this.afterControllersHooks?.push(...hooks);
1026
+ return this;
1027
+ }
1028
+ registerBeforeControllersHooks(...hooks) {
1029
+ this.assertServerIsNotRunning();
1030
+ this.beforeControllersHooks?.push(...hooks);
1031
+ return this;
1032
+ }
1033
+ registerControllers(...controllers) {
1034
+ this.assertServerIsNotRunning();
1035
+ this.controllers.push(...controllers);
1036
+ return this;
1037
+ }
1038
+ registerErrorHandlers(...handlers) {
1039
+ this.assertServerIsNotRunning();
1040
+ this.errorHandlers.push(...handlers);
1041
+ return this;
1042
+ }
1043
+ registerHooks(...hooks) {
1044
+ this.assertServerIsNotRunning();
1045
+ this.hooks.push(...hooks);
1046
+ return this;
1047
+ }
1048
+ registerMiddlewares(...middlewares) {
1049
+ this.assertServerIsNotRunning();
1050
+ this.middlewares.push(...middlewares);
1051
+ return this;
1052
+ }
1053
+ registerPostControllerMiddlewares(...middlewares) {
1054
+ this.assertServerIsNotRunning();
1055
+ this.postControllerMiddlewares.push(...middlewares);
1056
+ return this;
1057
+ }
1058
+ registerPreControllerMiddlewares(...middlewares) {
1059
+ this.assertServerIsNotRunning();
1060
+ this.preControllerMiddlewares.push(...middlewares);
1061
+ return this;
1062
+ }
1063
+ async run() {
1064
+ if (this.serverInstance) {
1065
+ throw new Error("HTTP server is already running.");
1066
+ }
1067
+ const controllers = [
1068
+ ...this.options.kernel.getRoutes(),
1069
+ ...this.controllers
1070
+ ];
1071
+ const express = this.getExpress();
1072
+ const { useExpressServer } = this.getRoutingControllers();
1073
+ const app = express();
1074
+ this.applyMiddlewares(app, this.middlewares);
1075
+ this.applyMiddlewares(app, this.preControllerMiddlewares);
1076
+ await this.runHooks(this.beforeControllersHooks, app);
1077
+ await this.runPhaseHooks("beforeControllers", app);
1078
+ this.configureControllerContainer();
1079
+ useExpressServer(app, {
1080
+ ...this.options.routingControllersOptions,
1081
+ controllers,
591
1082
  routePrefix: this.options.routePrefix
592
1083
  });
593
- for (const middleware of this.options.middlewares ?? []) {
594
- app.use(middleware);
595
- }
596
- this.registerErrorHandlers(app);
1084
+ this.applyMiddlewares(app, this.postControllerMiddlewares);
1085
+ await this.runHooks(this.afterControllersHooks, app);
1086
+ await this.runPhaseHooks("afterControllers", app);
1087
+ await this.runHooks(this.swaggerHooks, app);
1088
+ await this.runHooks(this.staticHooks, app);
1089
+ await this.runPhaseHooks("beforeErrors", app);
1090
+ this.applyErrorHandlers(app);
597
1091
  this.appInstance = app;
598
1092
  return new Promise((resolve) => {
599
1093
  this.serverInstance = app.listen(this.options.port ?? 3e3, () => {
@@ -603,6 +1097,132 @@ var ExpressKernelServer = class {
603
1097
  }
604
1098
  };
605
1099
 
1100
+ // src/adapters/ui/express/HttpErrorHandler.ts
1101
+ var import_routing_controllers = require("routing-controllers");
1102
+
1103
+ // src/contracts/ui/HttpRouteStatusEnum.ts
1104
+ var HttpRouteStatusEnum = {
1105
+ BAD_REQUEST: 400,
1106
+ CONFLICT: 409,
1107
+ CREATED: 201,
1108
+ DEPRECATED: 299,
1109
+ FORBIDDEN: 403,
1110
+ INTERNAL_SERVER_ERROR: 500,
1111
+ NO_CONTENT: 204,
1112
+ NOT_FOUND: 404,
1113
+ OK: 200,
1114
+ PAYLOAD_TOO_LARGE: 413,
1115
+ SERVICE_UNAVAILABLE: 503,
1116
+ TOO_MANY_REQUESTS: 429,
1117
+ UNAUTHORIZED: 401,
1118
+ UNPROCESSABLE_ENTITY: 422
1119
+ };
1120
+
1121
+ // src/adapters/ui/express/HttpErrorHandler.ts
1122
+ var HttpErrorHandler = class {
1123
+ constructor(options = {}) {
1124
+ this.options = options;
1125
+ this.handlers = options.handlers ?? [];
1126
+ this.exposeUnhandledErrorsIn = options.exposeUnhandledErrorsIn ?? [
1127
+ "local",
1128
+ "test"
1129
+ ];
1130
+ }
1131
+ options;
1132
+ handlers;
1133
+ exposeUnhandledErrorsIn;
1134
+ formatValidationErrors(errors) {
1135
+ return errors.flatMap((error) => {
1136
+ if (error.children && error.children.length > 0) {
1137
+ return this.formatValidationErrors(error.children);
1138
+ }
1139
+ return [
1140
+ {
1141
+ details: error.constraints,
1142
+ property: error.property,
1143
+ value: error.value
1144
+ }
1145
+ ];
1146
+ });
1147
+ }
1148
+ getErrorMessage(error) {
1149
+ return error instanceof Error ? error.message : String(error);
1150
+ }
1151
+ getHttpStatus(error) {
1152
+ return error.httpCode ?? error.statusCode ?? error.status;
1153
+ }
1154
+ isPayloadTooLargeError(error) {
1155
+ return error.type === "entity.too.large" || this.getHttpStatus(error) === HttpRouteStatusEnum.PAYLOAD_TOO_LARGE;
1156
+ }
1157
+ logUnhandledError(error) {
1158
+ this.options.logger?.error(`Unhandled error: ${error.message}`);
1159
+ this.options.logger?.debug(error.stack ?? "No stack trace available");
1160
+ }
1161
+ handleSyntaxError(error, response) {
1162
+ if (!(error instanceof SyntaxError)) {
1163
+ return false;
1164
+ }
1165
+ response.status(HttpRouteStatusEnum.BAD_REQUEST).json({
1166
+ code: "SyntaxError",
1167
+ message: "Malformed JSON"
1168
+ });
1169
+ return true;
1170
+ }
1171
+ handlePayloadTooLargeError(error, response) {
1172
+ if (!this.isPayloadTooLargeError(error)) {
1173
+ return false;
1174
+ }
1175
+ response.status(HttpRouteStatusEnum.PAYLOAD_TOO_LARGE).json({
1176
+ code: "PayloadTooLargeError",
1177
+ httpStatus: HttpRouteStatusEnum.PAYLOAD_TOO_LARGE,
1178
+ message: "Request entity too large."
1179
+ });
1180
+ return true;
1181
+ }
1182
+ handleHttpError(error, response) {
1183
+ const httpError = error;
1184
+ const httpStatus = this.getHttpStatus(httpError);
1185
+ if (!httpStatus && !(error instanceof import_routing_controllers.HttpError)) {
1186
+ return false;
1187
+ }
1188
+ response.status(httpStatus ?? HttpRouteStatusEnum.INTERNAL_SERVER_ERROR).json({
1189
+ code: error.name,
1190
+ errors: this.formatValidationErrors(
1191
+ error.errors ?? []
1192
+ ),
1193
+ httpStatus: httpStatus ?? HttpRouteStatusEnum.INTERNAL_SERVER_ERROR,
1194
+ message: error.message
1195
+ });
1196
+ return true;
1197
+ }
1198
+ handleUnhandledError(error, response) {
1199
+ if (this.exposeUnhandledErrorsIn.includes(process.env.NODE_ENV ?? "")) {
1200
+ this.logUnhandledError(error);
1201
+ }
1202
+ response.status(HttpRouteStatusEnum.INTERNAL_SERVER_ERROR).json({
1203
+ code: error.constructor.name || String(HttpRouteStatusEnum.INTERNAL_SERVER_ERROR),
1204
+ message: error.message || "Unknown error"
1205
+ });
1206
+ }
1207
+ error(error, request, response, next) {
1208
+ void request;
1209
+ const handlers = [
1210
+ this.handleSyntaxError.bind(this),
1211
+ this.handlePayloadTooLargeError.bind(this),
1212
+ ...this.handlers,
1213
+ this.handleHttpError.bind(this)
1214
+ ];
1215
+ if (handlers.some((handler) => handler(error, response))) {
1216
+ return;
1217
+ }
1218
+ void next;
1219
+ this.handleUnhandledError(error, response);
1220
+ }
1221
+ handle = (error, request, response, next) => {
1222
+ this.error(error, request, response, next);
1223
+ };
1224
+ };
1225
+
606
1226
  // src/adapters/ui/express/RoutePrefix.ts
607
1227
  var RoutePrefix = class _RoutePrefix {
608
1228
  value;
@@ -638,13 +1258,21 @@ var Route = class {
638
1258
  0 && (module.exports = {
639
1259
  ConsoleKernelLogger,
640
1260
  Consumer,
1261
+ ConsumerMiddlewarePipeline,
1262
+ CorrelationConsumerMiddleware,
1263
+ DefaultPublisherHookErrorPolicy,
641
1264
  ExpressKernelServer,
1265
+ HttpErrorHandler,
1266
+ IdempotencyConsumerMiddleware,
642
1267
  InMemoryEventBus,
1268
+ InMemoryIdempotencyStore,
643
1269
  InMemoryPubSub,
644
1270
  InMemoryRepository,
645
1271
  InvalidDomainEventError,
646
1272
  MongoRepository,
647
1273
  NoFailedMessagesError,
1274
+ PublisherHookPipeline,
1275
+ RetryConsumerMiddleware,
648
1276
  Route,
649
1277
  RoutePrefix
650
1278
  });