@arts-n-crafts/ts 3.18.0 → 3.19.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arts-n-crafts/ts",
3
- "version": "3.18.0",
3
+ "version": "3.19.0",
4
4
  "workspaces": [
5
5
  "packages/*"
6
6
  ],
@@ -5,7 +5,7 @@ var crypto = require('crypto');
5
5
  // src/core/utils/createCommand.ts
6
6
 
7
7
  // src/core/utils/getTimestamp.ts
8
- var getTimestamp = (date = /* @__PURE__ */ new Date()) => Math.floor(date.getTime() / 1e3);
8
+ var getTimestamp = (date = /* @__PURE__ */ new Date()) => date.getTime();
9
9
 
10
10
  // src/core/utils/createCommand.ts
11
11
  function createCommand(type, aggregateId, aggregateType, payload, metadata = {}) {
@@ -180,6 +180,42 @@ var FieldGreaterThan = class extends CompositeSpecification {
180
180
  return createQueryNode("gt", this.field, this.value);
181
181
  }
182
182
  };
183
+ function createIntegrationEvent(type, payload, metadata) {
184
+ return Object.freeze({
185
+ id: crypto.randomUUID(),
186
+ type,
187
+ payload,
188
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
189
+ metadata: {
190
+ ...metadata
191
+ },
192
+ kind: "integration"
193
+ });
194
+ }
195
+
196
+ // src/domain/utils/convertDomainEventToIntegrationEvent.ts
197
+ function convertDomainEventToIntegrationEvent(event) {
198
+ return createIntegrationEvent(event.type, event.payload, {
199
+ outcome: "accepted",
200
+ aggregateType: event.aggregateType,
201
+ aggregateId: event.aggregateId
202
+ });
203
+ }
204
+
205
+ // src/domain/utils/convertRejectionToIntegrationEvent.ts
206
+ function convertRejectionToIntegrationEvent(rejection) {
207
+ return createIntegrationEvent(
208
+ rejection.commandType,
209
+ { ...rejection.details, reasonCode: rejection.reasonCode },
210
+ {
211
+ outcome: "rejected",
212
+ aggregateType: rejection.metadata?.aggregateType,
213
+ aggregateId: rejection.metadata?.aggregateId,
214
+ commandType: rejection.commandType,
215
+ commandId: rejection.commandId
216
+ }
217
+ );
218
+ }
183
219
  function createDomainEvent(type, aggregateId, aggregateType, payload, metadata = {}) {
184
220
  return Object.freeze({
185
221
  id: crypto.randomUUID(),
@@ -227,8 +263,10 @@ function isDomainEvent(event) {
227
263
  }
228
264
 
229
265
  // src/domain/utils/isRejection.ts
230
- function isRejection(event) {
231
- return isEvent(event) && "commandId" in event && "reasonCode" in event && event.kind === "rejection";
266
+ function isRejection(candidate) {
267
+ if (candidate === null || typeof candidate !== "object")
268
+ return false;
269
+ return "commandId" in candidate && "commandType" in candidate && "reasonCode" in candidate && "timestamp" in candidate;
232
270
  }
233
271
 
234
272
  // src/infrastructure/CommandBus/implementations/SimpleCommandBus.ts
@@ -347,7 +385,7 @@ var SimpleEventBus = class {
347
385
  await this.consume(stream, anEvent);
348
386
  }
349
387
  };
350
- function createIntegrationEvent(type, payload, metadata) {
388
+ function createExternalEvent(type, payload, metadata) {
351
389
  return Object.freeze({
352
390
  id: crypto.randomUUID(),
353
391
  type,
@@ -356,15 +394,63 @@ function createIntegrationEvent(type, payload, metadata) {
356
394
  metadata: {
357
395
  ...metadata
358
396
  },
359
- kind: "integration"
397
+ kind: "external"
360
398
  });
361
399
  }
362
400
 
401
+ // src/infrastructure/EventBus/utils/isExternalEvent.ts
402
+ function isExternalEvent(event) {
403
+ return isEvent(event) && event.kind === "external";
404
+ }
405
+
363
406
  // src/infrastructure/EventBus/utils/isIntegrationEvent.ts
364
407
  function isIntegrationEvent(event) {
365
408
  return isEvent(event) && event.kind === "integration";
366
409
  }
367
410
 
411
+ // src/infrastructure/EventBus/utils/mapDomainEventToIntegrationEvent.ts
412
+ function mapDomainEventToIntegrationEvent(domainEvent) {
413
+ const metadata = {
414
+ ...domainEvent.metadata,
415
+ aggregateType: domainEvent.aggregateType,
416
+ aggregateId: domainEvent.aggregateId,
417
+ outcome: "accepted"
418
+ };
419
+ return {
420
+ id: domainEvent.id,
421
+ type: domainEvent.type,
422
+ payload: domainEvent.payload,
423
+ timestamp: new Date(domainEvent.timestamp).toISOString(),
424
+ metadata,
425
+ kind: "integration"
426
+ };
427
+ }
428
+
429
+ // src/infrastructure/EventBus/utils/mapRejectionToIntegrationEvent.ts
430
+ function mapRejectionToIntegrationEvent(rejection) {
431
+ const metadata = {
432
+ ...rejection.metadata,
433
+ outcome: "rejected",
434
+ commandId: rejection.commandId,
435
+ commandType: rejection.commandType
436
+ };
437
+ return {
438
+ id: rejection.id,
439
+ type: rejection.type,
440
+ payload: {
441
+ reasonCode: rejection.reasonCode,
442
+ reason: rejection.reason,
443
+ classification: rejection.classification,
444
+ retryable: rejection.retryable,
445
+ details: rejection.details,
446
+ validationErrors: rejection.validationErrors
447
+ },
448
+ timestamp: new Date(rejection.timestamp).toISOString(),
449
+ metadata,
450
+ kind: "integration"
451
+ };
452
+ }
453
+
368
454
  // src/utils/streamKey/makeStreamKey.ts
369
455
  function makeStreamKey(streamName, aggregateId) {
370
456
  return `${streamName}#${aggregateId}`;
@@ -469,18 +555,23 @@ var GenericOutboxWorker = class {
469
555
  }, intervalMs);
470
556
  }
471
557
  };
558
+ function createOutboxEntry(event) {
559
+ return {
560
+ id: crypto.randomUUID(),
561
+ event,
562
+ published: false,
563
+ retryCount: 0,
564
+ lastAttemptAt: void 0
565
+ };
566
+ }
472
567
 
473
568
  // src/infrastructure/Outbox/implementations/InMemoryOutbox.ts
474
569
  var InMemoryOutbox = class {
475
570
  entries = [];
476
571
  idCounter = 0;
477
572
  async enqueue(event) {
478
- this.entries.push({
479
- id: (this.idCounter++).toString(),
480
- event,
481
- published: false,
482
- retryCount: 0
483
- });
573
+ const integrationEvent = isRejection(event) ? convertRejectionToIntegrationEvent(event) : convertDomainEventToIntegrationEvent(event);
574
+ this.entries.push(createOutboxEntry(integrationEvent));
484
575
  }
485
576
  async getPending(limit = 100) {
486
577
  return this.entries.filter((e) => !e.published).slice(0, limit);
@@ -499,15 +590,6 @@ var InMemoryOutbox = class {
499
590
  }
500
591
  }
501
592
  };
502
- function createOutboxEntry(event) {
503
- return Object.freeze({
504
- id: crypto.randomUUID(),
505
- event,
506
- published: false,
507
- retryCount: 0,
508
- lastAttemptAt: void 0
509
- });
510
- }
511
593
 
512
594
  // src/infrastructure/QueryBus/implementations/SimpleQueryBus.ts
513
595
  var SimpleQueryBus = class {
@@ -551,6 +633,122 @@ var SimpleRepository = class {
551
633
  }
552
634
  };
553
635
 
636
+ // src/infrastructure/ScenarioTest/ScenarioTest.ts
637
+ var ScenarioTest = class {
638
+ constructor(streamName, eventBus, eventStore, commandBus, queryBus, repository, outboxWorker, outbox) {
639
+ this.streamName = streamName;
640
+ this.eventBus = eventBus;
641
+ this.eventStore = eventStore;
642
+ this.commandBus = commandBus;
643
+ this.queryBus = queryBus;
644
+ this.repository = repository;
645
+ this.outboxWorker = outboxWorker;
646
+ this.outbox = outbox;
647
+ }
648
+ givenInput = [];
649
+ whenInput;
650
+ given(...events) {
651
+ this.givenInput = events;
652
+ return {
653
+ when: this.when.bind(this),
654
+ then: this.then.bind(this)
655
+ };
656
+ }
657
+ when(action) {
658
+ this.whenInput = action;
659
+ return {
660
+ then: this.then.bind(this)
661
+ };
662
+ }
663
+ async then(thenInput) {
664
+ await Promise.all([
665
+ this.repository.store(this.givenInput),
666
+ ...this.givenInput.map(async (event) => this.eventBus.consume(this.streamName, event))
667
+ ]);
668
+ if (!this.whenInput) {
669
+ throw new Error("In the ScenarioTest, the when-step cannot be empty");
670
+ }
671
+ if (isCommand(this.whenInput)) {
672
+ invariant(
673
+ isDomainEvent(thenInput) || isRejection(thenInput),
674
+ fail(new TypeError('When "command" expects a domain event or rejection in the then-step'))
675
+ );
676
+ await this.handleCommand(this.whenInput, thenInput);
677
+ return;
678
+ }
679
+ if (isQuery(this.whenInput)) {
680
+ invariant(
681
+ Array.isArray(thenInput),
682
+ fail(new TypeError('When "query" expects an array of expected results in the then-step'))
683
+ );
684
+ await this.handleQuery(this.whenInput, thenInput);
685
+ return;
686
+ }
687
+ invariant(
688
+ isDomainEvent(thenInput),
689
+ fail(new TypeError('When "domain event" or "integration event" expects a domain event in the then-step'))
690
+ );
691
+ await this.handleEvent(this.whenInput, thenInput);
692
+ }
693
+ async handleCommand(command, outcome) {
694
+ await this.commandBus.execute(command);
695
+ if (isRejection(outcome)) {
696
+ const pending = await this.outbox.getPending();
697
+ const foundRejection = pending.find(
698
+ (entry) => entry.event.metadata.outcome === "rejected" && entry.event.metadata.commandType === outcome.commandType && entry.event.payload.reasonCode === outcome.reasonCode
699
+ );
700
+ invariant(!!foundRejection, fail(new Error("ScenarioTest: rejection was not found in outbox")));
701
+ return;
702
+ }
703
+ const actualEvents = await this.eventStore.load(this.streamName, outcome.aggregateId);
704
+ const foundEvent = actualEvents.findLast(
705
+ (event) => isDomainEvent(event) && event.aggregateId === outcome.aggregateId && event.type === outcome.type
706
+ );
707
+ invariant(!!foundEvent, fail(new Error("ScenarioTest: event/command was not found")));
708
+ invariant(
709
+ outcome.type === foundEvent.type,
710
+ fail(new Error("ScenarioTest: event/command type was not equal"))
711
+ );
712
+ invariant(
713
+ outcome.aggregateId === foundEvent.aggregateId,
714
+ fail(new Error("ScenarioTest: event/command aggregate id was not equal"))
715
+ );
716
+ invariant(
717
+ isEqual(outcome.payload, foundEvent.payload),
718
+ fail(new Error("ScenarioTest: event/command payload was not equal"))
719
+ );
720
+ }
721
+ async handleQuery(query, expected) {
722
+ await this.outboxWorker.tick();
723
+ const actual = await this.queryBus.execute(query);
724
+ invariant(
725
+ isEqual(actual, expected),
726
+ fail(new Error("ScenarioTest: a different query result was returned"))
727
+ );
728
+ }
729
+ async handleEvent(event, outcome) {
730
+ await this.eventBus.publish(this.streamName, event);
731
+ const actualEvents = await this.eventStore.load(this.streamName, outcome.aggregateId);
732
+ const foundEvent = actualEvents.findLast(
733
+ (event2) => isEvent(event2) && event2.aggregateId === outcome.aggregateId && event2.type === outcome.type
734
+ );
735
+ invariant(!!foundEvent, fail(new Error("ScenarioTest: event was not found")));
736
+ invariant(isEvent(foundEvent), fail(new Error("ScenarioTest: event is not of type event")));
737
+ invariant(
738
+ outcome.type === foundEvent.type,
739
+ fail(new Error("ScenarioTest: event type was not equal"))
740
+ );
741
+ invariant(
742
+ outcome.aggregateId === foundEvent.aggregateId,
743
+ fail(new Error("ScenarioTest: event aggregate id was not equal"))
744
+ );
745
+ invariant(
746
+ isEqual(outcome.payload, foundEvent.payload),
747
+ fail(new Error("ScenarioTest: event payload was not equal"))
748
+ );
749
+ }
750
+ };
751
+
554
752
  exports.AndSpecification = AndSpecification;
555
753
  exports.CompositeSpecification = CompositeSpecification;
556
754
  exports.FieldEquals = FieldEquals;
@@ -560,14 +758,18 @@ exports.InMemoryOutbox = InMemoryOutbox;
560
758
  exports.NotSpecification = NotSpecification;
561
759
  exports.Operation = Operation;
562
760
  exports.OrSpecification = OrSpecification;
761
+ exports.ScenarioTest = ScenarioTest;
563
762
  exports.SimpleCommandBus = SimpleCommandBus;
564
763
  exports.SimpleDatabase = SimpleDatabase;
565
764
  exports.SimpleEventBus = SimpleEventBus;
566
765
  exports.SimpleEventStore = SimpleEventStore;
567
766
  exports.SimpleQueryBus = SimpleQueryBus;
568
767
  exports.SimpleRepository = SimpleRepository;
768
+ exports.convertDomainEventToIntegrationEvent = convertDomainEventToIntegrationEvent;
769
+ exports.convertRejectionToIntegrationEvent = convertRejectionToIntegrationEvent;
569
770
  exports.createCommand = createCommand;
570
771
  exports.createDomainEvent = createDomainEvent;
772
+ exports.createExternalEvent = createExternalEvent;
571
773
  exports.createIntegrationEvent = createIntegrationEvent;
572
774
  exports.createOutboxEntry = createOutboxEntry;
573
775
  exports.createQuery = createQuery;
@@ -581,10 +783,13 @@ exports.isCommand = isCommand;
581
783
  exports.isDomainEvent = isDomainEvent;
582
784
  exports.isEqual = isEqual;
583
785
  exports.isEvent = isEvent;
786
+ exports.isExternalEvent = isExternalEvent;
584
787
  exports.isIntegrationEvent = isIntegrationEvent;
585
788
  exports.isQuery = isQuery;
586
789
  exports.isRejection = isRejection;
587
790
  exports.makeStreamKey = makeStreamKey;
791
+ exports.mapDomainEventToIntegrationEvent = mapDomainEventToIntegrationEvent;
792
+ exports.mapRejectionToIntegrationEvent = mapRejectionToIntegrationEvent;
588
793
  exports.parseAsError = parseAsError;
589
794
  //# sourceMappingURL=index.cjs.map
590
795
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/core/utils/getTimestamp.ts","../src/core/utils/createCommand.ts","../src/core/utils/createQuery.ts","../src/core/utils/isCommand.ts","../src/core/utils/isQuery.ts","../src/domain/Specification/Specification.ts","../src/domain/Specification/utils/createQueryNode.ts","../src/domain/Specification/implementations/FieldEquals.specification.ts","../src/utils/fail/fail.ts","../src/utils/invariant/invariant.ts","../src/domain/Specification/implementations/FieldGreaterThan.specification.ts","../src/domain/utils/createDomainEvent.ts","../src/domain/utils/createRejection.ts","../src/domain/utils/isEvent.ts","../src/domain/utils/isDomainEvent.ts","../src/domain/utils/isRejection.ts","../src/infrastructure/CommandBus/implementations/SimpleCommandBus.ts","../src/infrastructure/Database/Database.ts","../src/infrastructure/Database/implementations/SimpleDatabase.exceptions.ts","../src/infrastructure/Database/implementations/SimpleDatabase.ts","../src/infrastructure/EventBus/implementations/SimpleEventBus.ts","../src/infrastructure/EventBus/utils/createIntegrationEvent.ts","../src/infrastructure/EventBus/utils/isIntegrationEvent.ts","../src/utils/streamKey/makeStreamKey.ts","../src/utils/isEqual/isEqual.ts","../src/utils/parseAsError/parseAsError.ts","../src/infrastructure/EventStore/utils/createStoredEvent.ts","../src/infrastructure/EventStore/implementations/SimpleEventStore.exceptions.ts","../src/infrastructure/EventStore/implementations/SimpleEventStore.ts","../src/infrastructure/Outbox/implementations/GenericOutboxWorker.ts","../src/infrastructure/Outbox/implementations/InMemoryOutbox.ts","../src/infrastructure/Outbox/utils/createOutboxEntry.ts","../src/infrastructure/QueryBus/implementations/SimpleQueryBus.ts","../src/infrastructure/Repository/implementations/SimpleRepository.ts"],"names":["randomUUID","Operation","event"],"mappings":"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","file":"index.cjs","sourcesContent":["export const getTimestamp = (date: Date = new Date()): number => Math.floor(date.getTime() / 1000)\n","import type { Command, CommandMetadata } from '@core/Command.ts'\nimport { randomUUID } from 'node:crypto'\nimport { getTimestamp } from '@core/utils/getTimestamp.ts'\n\nexport function createCommand<TType extends string, TPayload>(type: TType, aggregateId: string, aggregateType: string, payload: TPayload, metadata: Partial<CommandMetadata> = {}): Command<TType, TPayload> {\n return Object.freeze({\n id: randomUUID(),\n type,\n aggregateType,\n aggregateId: String(aggregateId),\n payload,\n kind: 'command',\n timestamp: getTimestamp(),\n metadata,\n })\n}\n","import type { Query, QueryMetadata } from '@core/Query.ts'\nimport { randomUUID } from 'node:crypto'\nimport { getTimestamp } from '@core/utils/getTimestamp.ts'\n\nexport function createQuery<TType extends string, TPayload>(type: TType, payload: TPayload, metadata: QueryMetadata = {}): Query<TType, TPayload> {\n return Object.freeze({\n id: randomUUID(),\n type,\n payload,\n kind: 'query',\n timestamp: getTimestamp(),\n metadata,\n })\n}\n","import type { Command } from '@core/Command.ts'\n\nexport function isCommand(candidate: unknown): candidate is Command<string, unknown> {\n if (candidate === null)\n return false\n if (typeof candidate !== 'object')\n return false\n if (!('type' in candidate))\n return false\n return 'kind' in candidate && candidate.kind === 'command'\n}\n","import type { Query } from '@core/Query.ts'\n\nexport function isQuery(candidate: unknown): candidate is Query<unknown> {\n if (candidate === null)\n return false\n if (typeof candidate !== 'object')\n return false\n if (!('type' in candidate))\n return false\n return 'kind' in candidate && candidate.kind === 'query'\n}\n","import type { QueryNode } from './QueryNode.ts'\n\nexport interface Specification<T> {\n isSatisfiedBy(entity: T): boolean\n}\n\nexport abstract class CompositeSpecification<T> implements Specification<T> {\n abstract isSatisfiedBy(entity: T): boolean\n\n abstract toQuery(): QueryNode\n\n and(other: CompositeSpecification<T>): CompositeSpecification<T> {\n return new AndSpecification(this, other)\n }\n\n or(other: CompositeSpecification<T>): CompositeSpecification<T> {\n return new OrSpecification(this, other)\n }\n\n not(): CompositeSpecification<T> {\n return new NotSpecification(this)\n }\n}\n\nexport class AndSpecification<T> extends CompositeSpecification<T> {\n constructor(private left: CompositeSpecification<T>, private right: CompositeSpecification<T>) {\n super()\n }\n\n isSatisfiedBy(entity: T): boolean {\n return this.left.isSatisfiedBy(entity) && this.right.isSatisfiedBy(entity)\n }\n\n toQuery(): QueryNode {\n return {\n type: 'and',\n nodes: [this.left.toQuery(), this.right.toQuery()],\n }\n }\n}\n\nexport class OrSpecification<T> extends CompositeSpecification<T> {\n constructor(private left: CompositeSpecification<T>, private right: CompositeSpecification<T>) {\n super()\n }\n\n isSatisfiedBy(entity: T): boolean {\n return this.left.isSatisfiedBy(entity) || this.right.isSatisfiedBy(entity)\n }\n\n toQuery(): QueryNode {\n return {\n type: 'or',\n nodes: [this.left.toQuery(), this.right.toQuery()],\n }\n }\n}\n\nexport class NotSpecification<T> extends CompositeSpecification<T> {\n constructor(private spec: CompositeSpecification<T>) {\n super()\n }\n\n isSatisfiedBy(entity: T): boolean {\n return !this.spec.isSatisfiedBy(entity)\n }\n\n toQuery(): QueryNode {\n return {\n type: 'not',\n node: this.spec.toQuery(),\n }\n }\n}\n","import type { Primitive } from '@core/types/Primitive.ts'\nimport type { QueryNode } from '../QueryNode.ts'\n\nexport function createQueryNode(type: 'eq' | 'gt' | 'lt', field: string | number | symbol, value: Primitive): QueryNode\nexport function createQueryNode(type: 'and' | 'or', field: undefined, value: QueryNode[]): QueryNode\nexport function createQueryNode(type: 'not', field: undefined, value: QueryNode): QueryNode\nexport function createQueryNode(\n type: QueryNode['type'],\n field: string | number | symbol | undefined,\n value: Primitive | QueryNode | QueryNode[],\n): QueryNode {\n switch (type) {\n case 'eq':\n case 'gt':\n case 'lt':\n return { type, field: field as string, value: value as Primitive }\n case 'and':\n case 'or':\n return { type, nodes: value as QueryNode[] }\n case 'not':\n return { type, node: value as QueryNode }\n }\n}\n","import type { Primitive } from '@core/types/Primitive.ts'\nimport type { QueryNode } from '../QueryNode.ts'\nimport { CompositeSpecification } from '../Specification.ts'\nimport { createQueryNode } from '../utils/createQueryNode.ts'\n\nexport class FieldEquals<T> extends CompositeSpecification<T> {\n constructor(private field: keyof T, private value: Primitive) {\n super()\n }\n\n isSatisfiedBy(entity: T): boolean {\n return entity[this.field] === this.value\n }\n\n toQuery(): QueryNode {\n return createQueryNode('eq', this.field, this.value)\n }\n}\n","export function fail(anExpression: Error) {\n return () => {\n throw anExpression\n }\n}\n","export function invariant(condition: boolean, onInvalid: () => never): asserts condition {\n if (!condition)\n onInvalid()\n}\n","import type { QueryNode } from '../QueryNode.ts'\nimport { fail } from '@utils/fail/fail.ts'\nimport { invariant } from '@utils/invariant/invariant.ts'\nimport { CompositeSpecification } from '../Specification.ts'\nimport { createQueryNode } from '../utils/createQueryNode.ts'\n\nexport class FieldGreaterThan<T> extends CompositeSpecification<T> {\n constructor(\n private field: keyof T,\n private value: number,\n ) {\n super()\n }\n\n private isNumber(value: unknown): value is number {\n return typeof value === 'number'\n }\n\n isSatisfiedBy(entity: T): boolean {\n const field = entity[this.field]\n invariant(\n this.isNumber(field),\n fail(new TypeError(`Field ${String(this.field)} is not a number`),\n ),\n )\n return field > this.value\n }\n\n toQuery(): QueryNode {\n return createQueryNode('gt', this.field, this.value)\n }\n}\n","import type { DomainEvent, DomainEventMetadata } from '@domain/DomainEvent.ts'\nimport { randomUUID } from 'node:crypto'\nimport { getTimestamp } from '@core/utils/getTimestamp.ts'\n\nexport function createDomainEvent<TPayload = unknown>(\n type: string,\n aggregateId: string,\n aggregateType: string,\n payload: TPayload,\n metadata: Partial<DomainEventMetadata> = {},\n): DomainEvent<TPayload> {\n return Object.freeze({\n id: randomUUID(),\n type,\n aggregateId,\n aggregateType,\n payload,\n kind: 'domain',\n timestamp: getTimestamp(),\n metadata,\n })\n}\n","import type { Rejection, RejectionMetadata } from '@domain/Rejection.ts'\nimport { randomUUID } from 'node:crypto'\nimport { getTimestamp } from '@core/utils/getTimestamp.ts'\n\nexport function createRejection<TDetails = unknown>(\n rejectionSpecifics: {\n commandId: Rejection['commandId']\n commandType: Rejection['commandType']\n reasonCode: Rejection['reasonCode']\n reason?: Rejection['reason']\n classification: Rejection['classification']\n retryable?: Rejection['retryable']\n validationErrors?: Rejection['validationErrors']\n type: 'Failed' | 'Rejected' | string\n details?: TDetails\n },\n metadata: Partial<RejectionMetadata> = {},\n): Rejection<TDetails> {\n return Object.freeze({\n id: randomUUID(),\n commandId: rejectionSpecifics.commandId,\n commandType: rejectionSpecifics.commandType,\n reasonCode: rejectionSpecifics.reasonCode,\n reason: rejectionSpecifics.reason,\n classification: rejectionSpecifics.classification,\n retryable: rejectionSpecifics.retryable,\n validationErrors: rejectionSpecifics.validationErrors,\n type: `${rejectionSpecifics.commandType}${rejectionSpecifics.type}`,\n details: rejectionSpecifics.details,\n kind: 'rejection',\n timestamp: getTimestamp(),\n metadata,\n })\n}\n","import type { DomainEvent } from '@domain/DomainEvent.ts'\nimport type { Rejection } from '@domain/Rejection.ts'\nimport type { ExternalEvent } from '@infrastructure/EventBus/ExternalEvent.ts'\nimport type { IntegrationEvent } from '@infrastructure/EventBus/IntegrationEvent.ts'\n\nexport function isEvent(event: unknown): event is DomainEvent | IntegrationEvent | ExternalEvent | Rejection {\n if (typeof event !== 'object')\n return false\n if (event === null)\n return false\n if (!('type' in event))\n return false\n return 'kind' in event\n}\n","import type { DomainEvent } from '../DomainEvent.ts'\nimport { isEvent } from './isEvent.ts'\n\nexport function isDomainEvent(event: unknown): event is DomainEvent {\n return isEvent(event)\n && 'aggregateId' in event\n && event.kind === 'domain'\n}\n","import type { Rejection } from '@domain/Rejection.ts'\nimport { isEvent } from './isEvent.ts'\n\nexport function isRejection(event: unknown): event is Rejection {\n return isEvent(event)\n && 'commandId' in event\n && 'reasonCode' in event\n && event.kind === 'rejection'\n}\n","import type { Command } from '@core/Command.ts'\nimport type { CommandHandler } from '@core/CommandHandler.ts'\nimport type { CommandBus } from '../CommandBus.ts'\n\nexport class SimpleCommandBus<TCommand extends Command> implements CommandBus<TCommand> {\n private handlers: Map<TCommand['type'], CommandHandler<TCommand>> = new Map()\n\n register(aTypeOfCommand: TCommand['type'], anHandler: CommandHandler<TCommand>): void {\n if (this.handlers.has(aTypeOfCommand)) {\n throw new Error(`Handler already registered for command type: ${aTypeOfCommand}`)\n }\n this.handlers.set(aTypeOfCommand, anHandler)\n }\n\n async execute(aCommand: TCommand): Promise<void> {\n const handler = this.handlers.get(aCommand.type)\n if (!handler) {\n throw new Error(`No handler found for command type: ${aCommand.type}`)\n }\n return handler.execute(aCommand)\n }\n}\n","import type { CompositeSpecification } from '@domain/Specification/Specification.ts'\nimport type { WithIdentifier } from '../../core/types/WithIdentifier.ts'\n\nexport enum Operation {\n CREATE = 'CREATE',\n PUT = 'PUT',\n PATCH = 'PATCH',\n DELETE = 'DELETE',\n}\n\ninterface Statement<TModel> {\n operation: Operation\n payload: TModel\n}\n\nexport interface CreateStatement<TModel> extends Statement<TModel> {\n operation: Operation.CREATE\n payload: TModel\n}\n\nexport interface PutStatement<TModel> extends Statement<TModel> {\n operation: Operation.PUT\n payload: TModel\n}\n\nexport interface PatchStatement<TModel> extends Statement<Partial<TModel>> {\n operation: Operation.PATCH\n payload: WithIdentifier<Partial<TModel>>\n}\n\nexport interface DeleteStatement extends Statement<WithIdentifier> {\n operation: Operation.DELETE\n payload: WithIdentifier\n}\n\ninterface Executable<TModel, TReturnType = Promise<void>> {\n execute(tableName: string, statement: CreateStatement<TModel>): TReturnType\n execute(tableName: string, statement: PutStatement<TModel>): TReturnType\n execute(tableName: string, statement: PatchStatement<TModel>): TReturnType\n execute(tableName: string, statement: DeleteStatement): TReturnType\n}\n\ninterface QueryAble<TModel, TReturnType = Promise<TModel[]>> {\n query(collectionName: string, specification: CompositeSpecification<TModel>): TReturnType\n}\n\nexport interface Database<TModel, TExecuteReturnType = Promise<void>, TQueryReturnType = Promise<TModel[]>>\n extends\n QueryAble<TModel, TQueryReturnType>,\n Executable<TModel, TExecuteReturnType> { }\n","export class RecordNotFoundException extends Error {\n constructor(id: string) {\n super(`Record not found for id: ${id}`)\n }\n}\n\nexport class DuplicateRecordException extends Error {\n constructor(id: string) {\n super(`Duplicate record found for id: ${id}`)\n }\n}\n\nexport class DatabaseOfflineException extends Error {\n constructor() {\n super(`Database is offline`)\n }\n}\n","import type { CompositeSpecification } from '@domain/Specification/Specification.ts'\nimport type { WithIdentifier } from '../../../core/types/WithIdentifier.ts'\nimport type { CreateStatement, Database, DeleteStatement, PatchStatement, PutStatement } from '../Database.ts'\nimport { Operation } from '../Database.ts'\nimport { DatabaseOfflineException, DuplicateRecordException, RecordNotFoundException } from './SimpleDatabase.exceptions.ts'\n\nexport class SimpleDatabase<TModel extends WithIdentifier> implements Database<TModel, Promise<void>, Promise<TModel[]>> {\n private readonly datasource = new Map<string, TModel[]>()\n private simulateOffline = false\n\n async query(\n tableName: string,\n specification: CompositeSpecification<TModel>,\n ): Promise<TModel[]> {\n if (this.simulateOffline)\n throw new DatabaseOfflineException()\n\n const tableRecords = (this.datasource.get(tableName) || [])\n return tableRecords\n .filter((record: TModel) => specification.isSatisfiedBy(record))\n }\n\n async execute(\n tableName: string,\n statement: CreateStatement<TModel> | PutStatement<TModel> | PatchStatement<TModel> | DeleteStatement,\n ): Promise<void> {\n if (this.simulateOffline)\n throw new DatabaseOfflineException()\n\n if (!this.datasource.has(tableName))\n this.datasource.set(tableName, [])\n const table = this.datasource.get(tableName)!\n\n switch (statement.operation) {\n case Operation.CREATE: {\n const isDuplicate = table.some(item => item.id === statement.payload.id)\n if (isDuplicate)\n throw new DuplicateRecordException(statement.payload.id)\n table.push(statement.payload)\n break\n }\n case Operation.PUT:{\n const index = table.findIndex(item => item.id === statement.payload.id)\n if (index === -1)\n throw new RecordNotFoundException(statement.payload.id)\n table[index] = statement.payload\n break\n }\n case Operation.PATCH:{\n const index = table.findIndex(item => item.id === statement.payload.id)\n if (index === -1)\n throw new RecordNotFoundException(statement.payload.id)\n table[index] = { ...table[index], ...statement.payload }\n break\n }\n case Operation.DELETE:{\n const index = table.findIndex(item => item.id === statement.payload.id)\n if (index === -1)\n throw new RecordNotFoundException(statement.payload.id)\n table.splice(index, 1)\n break\n }\n }\n }\n\n goOffline(): void {\n this.simulateOffline = true\n }\n}\n","import type { EventHandler } from '@core/EventHandler.ts'\nimport type { DomainEvent } from '@domain/DomainEvent.ts'\nimport type { ExternalEvent } from '@infrastructure/EventBus/ExternalEvent.ts'\nimport type { IntegrationEvent } from '@infrastructure/EventBus/IntegrationEvent.ts'\nimport type { EventConsumer, EventProducer } from '../EventBus.ts'\n\nexport class SimpleEventBus<TEvent extends DomainEvent | IntegrationEvent | ExternalEvent>\nimplements EventConsumer<TEvent>, EventProducer<TEvent> {\n private handlers = new Map<string, EventHandler<TEvent>[]>()\n\n subscribe(\n stream: string,\n aHandler: EventHandler<TEvent>,\n ): void {\n const handlersForType = this.handlers.get(stream) ?? []\n handlersForType.push(aHandler)\n this.handlers.set(stream, handlersForType)\n }\n\n async consume(stream: string, anEvent: TEvent): Promise<void> {\n if (!this.handlers.has(stream))\n return\n const handlers = this.handlers.get(stream) as EventHandler<TEvent>[]\n await Promise.all(handlers.map(async (handler) => {\n return handler.handle(anEvent)\n }))\n }\n\n async publish(stream: string, anEvent: TEvent): Promise<void> {\n await this.consume(stream, anEvent)\n }\n}\n","import type { IntegrationEvent, IntegrationEventMetadata } from '../IntegrationEvent.ts'\nimport { randomUUID } from 'node:crypto'\n\nexport function createIntegrationEvent<TPayload = unknown>(type: string, payload: TPayload, metadata?: Partial<IntegrationEventMetadata>): IntegrationEvent<TPayload> {\n return Object.freeze({\n id: randomUUID(),\n type,\n payload,\n timestamp: new Date().toISOString(),\n metadata: {\n ...metadata,\n },\n kind: 'integration',\n })\n}\n","import type { IntegrationEvent } from '../IntegrationEvent.ts'\nimport { isEvent } from '@domain/utils/isEvent.ts'\n\nexport function isIntegrationEvent<TPayload>(event: unknown): event is IntegrationEvent<TPayload> {\n return isEvent(event)\n && event.kind === 'integration'\n}\n","import type { StreamKey } from '@utils/streamKey/StreamKey.ts'\n\nexport function makeStreamKey(streamName: string, aggregateId: string): StreamKey {\n return `${streamName}#${aggregateId}`\n}\n","export function isEqual<T>(a: T, b: T): boolean {\n if (a === b) {\n return true\n }\n\n // eslint-disable-next-line ts/strict-boolean-expressions\n const bothAreObjects = a && b && typeof a === 'object' && typeof b === 'object'\n\n return Boolean(\n bothAreObjects\n && Object.keys(a).length === Object.keys(b).length\n && Object.entries(a).every(([k, v]) => isEqual(v, b[k as keyof T])),\n )\n}\n","export function parseAsError(value: unknown): Error {\n if (value instanceof Error)\n return value\n if (typeof value === 'string')\n return new Error(value)\n try {\n const json = JSON.stringify(value)\n return new Error(json ?? String(value))\n }\n catch {\n return new Error('Unknown error')\n }\n}\n","import type { DomainEvent } from '@domain/DomainEvent.ts'\nimport type { StoredEvent } from '../StoredEvent.ts'\nimport { getTimestamp } from '@core/utils/getTimestamp.ts'\nimport { makeStreamKey } from '@utils/index.ts'\n\nexport function createStoredEvent<TEvent extends DomainEvent>(\n streamName: string,\n version: number,\n event: TEvent,\n): StoredEvent<TEvent> {\n return Object.freeze({\n id: event.id,\n streamKey: makeStreamKey(streamName, event.aggregateId),\n version,\n timestamp: getTimestamp(),\n event,\n })\n}\n","export class MultipleAggregatesException extends Error {\n constructor() {\n super('EventStore append does not support multiple aggregates to be stored')\n }\n}\n","import type { DomainEvent } from '@domain/DomainEvent.ts'\nimport type { Database } from '@infrastructure/Database/Database.ts'\nimport type { EventStore } from '@infrastructure/EventStore/EventStore.ts'\nimport type { Outbox } from '@infrastructure/Outbox/Outbox.ts'\nimport type { StreamKey } from '@utils/streamKey/StreamKey.ts'\nimport type { StoredEvent } from '../StoredEvent.ts'\nimport { FieldEquals } from '@domain/Specification/implementations/FieldEquals.specification.ts'\nimport { Operation } from '@infrastructure/Database/Database.ts'\nimport { makeStreamKey } from '@utils/streamKey/makeStreamKey.ts'\nimport { createStoredEvent } from '../utils/createStoredEvent.ts'\nimport { MultipleAggregatesException } from './SimpleEventStore.exceptions.ts'\n\nexport class SimpleEventStore<TEvent extends DomainEvent> implements EventStore<TEvent, Promise<void>, Promise<TEvent[]>> {\n private readonly tableName: string = 'event_store'\n\n constructor(\n private readonly database: Database<StoredEvent<TEvent>, Promise<void>, Promise<StoredEvent<TEvent>[]>>,\n private readonly outbox?: Outbox,\n ) { }\n\n async load(streamName: string, aggregateId: string): Promise<TEvent[]> {\n const streamKey: StreamKey = makeStreamKey(streamName, aggregateId)\n const specification = new FieldEquals('streamKey', streamKey)\n const storedEvents = await this.database.query(this.tableName, specification)\n return storedEvents.map(storedEvent => storedEvent.event)\n }\n\n async append(streamName: string, events: TEvent[]): Promise<void> {\n const uniqueAggregateIds = new Set(events.map(event => event.aggregateId))\n if (uniqueAggregateIds.size > 1)\n throw new MultipleAggregatesException()\n\n const event = events[0]\n const currentStream = await this.load(streamName, event.aggregateId)\n const eventsToStore = events\n .map(event => createStoredEvent(streamName, currentStream.length + 1, event))\n await Promise.all(\n eventsToStore.map(async payload => this.database.execute(this.tableName, { operation: Operation.CREATE, payload }),\n ),\n )\n await Promise.all(events.map(async event => this.outbox?.enqueue(event)))\n }\n}\n","import type { DomainEvent } from '@domain/DomainEvent.ts'\nimport type { EventProducer } from '@infrastructure/EventBus/EventBus.js'\nimport type { ExternalEvent } from '@infrastructure/EventBus/ExternalEvent.ts'\nimport type { IntegrationEvent } from '@infrastructure/EventBus/IntegrationEvent.ts'\nimport type { OutboxWorker } from '@infrastructure/Outbox/OutboxWorker.ts'\nimport type { Outbox } from '../Outbox.ts'\n\nexport class GenericOutboxWorker implements OutboxWorker {\n constructor(\n protected outbox: Outbox,\n protected eventBus: EventProducer<DomainEvent | IntegrationEvent | ExternalEvent>,\n protected stream: string,\n ) {}\n\n async runOnce(): Promise<void> {\n const pending = await this.outbox.getPending()\n\n await Promise.all(pending.map(async (entry) => {\n try {\n await this.eventBus.publish(this.stream, entry.event)\n await this.outbox.markAsPublished(entry.id)\n }\n catch {\n await this.outbox.markAsFailed(entry.id)\n }\n }))\n }\n\n async tick(): Promise<void> {\n await this.runOnce()\n }\n\n start(intervalMs: number): void {\n setInterval(() => {\n void this.tick().catch(console.error)\n }, intervalMs)\n }\n}\n","import type { DomainEvent } from '@domain/DomainEvent.ts'\nimport type { Outbox } from '../Outbox.ts'\nimport type { OutboxEntry } from '../OutboxEntry.ts'\nimport { getTimestamp } from '@core/utils/getTimestamp.ts'\n\nexport class InMemoryOutbox implements Outbox {\n protected entries: OutboxEntry[] = []\n protected idCounter = 0\n\n async enqueue(event: DomainEvent<unknown>): Promise<void> {\n this.entries.push({\n id: (this.idCounter++).toString(),\n event,\n published: false,\n retryCount: 0,\n })\n }\n\n async getPending(limit = 100): Promise<OutboxEntry[]> {\n return this.entries.filter(e => !e.published).slice(0, limit)\n }\n\n async markAsPublished(id: string): Promise<void> {\n const entry = this.entries.find(e => e.id === id)\n if (entry) {\n entry.published = true\n }\n }\n\n async markAsFailed(id: string): Promise<void> {\n const entry = this.entries.find(e => e.id === id)\n if (entry) {\n entry.retryCount += 1\n entry.lastAttemptAt = getTimestamp()\n }\n }\n}\n","import type { DomainEvent } from '@domain/DomainEvent.ts'\nimport type { OutboxEntry } from '../OutboxEntry.ts'\nimport { randomUUID } from 'node:crypto'\n\nexport function createOutboxEntry(\n event: DomainEvent<unknown>,\n): OutboxEntry {\n return Object.freeze({\n id: randomUUID(),\n event,\n published: false,\n retryCount: 0,\n lastAttemptAt: undefined,\n })\n}\n","import type { Query } from '@core/Query.ts'\nimport type { QueryHandler } from '@core/QueryHandler.ts'\nimport type { QueryBus } from '../QueryBus.ts'\n\nexport class SimpleQueryBus<TQuery extends Query, TProjection> implements QueryBus<TQuery, Promise<TProjection>> {\n private handlers: Map<TQuery['type'], QueryHandler<TQuery, Promise<TProjection>>> = new Map()\n\n register(\n aTypeOfQuery: TQuery['type'],\n anHandler: QueryHandler<TQuery, Promise<TProjection>>,\n ): void {\n if (this.handlers.has(aTypeOfQuery)) {\n throw new Error(`Handler already registered for query type: ${aTypeOfQuery}`)\n }\n this.handlers.set(aTypeOfQuery, anHandler)\n }\n\n async execute(aQuery: TQuery): Promise<TProjection> {\n const handler = this.handlers.get(aQuery.type)\n if (!handler) {\n throw new Error(`No handler found for query type: ${aQuery.type}`)\n }\n return handler.execute(aQuery)\n }\n}\n","import type { Decider } from '@domain/Decider.ts'\nimport type { DomainEvent } from '@domain/DomainEvent.ts'\nimport type { Rejection } from '@domain/Rejection.ts'\nimport type { Repository } from '@domain/Repository.ts'\nimport type { EventStore } from '@infrastructure/EventStore/EventStore.ts'\n\nexport class SimpleRepository<TState, TCommand, TEvent extends DomainEvent, TRejection extends Rejection> implements Repository<TEvent, Promise<TState>, Promise<void>> {\n constructor(\n private readonly eventStore: EventStore<TEvent, Promise<void>, Promise<TEvent[]>>,\n readonly streamName: string,\n private readonly evolveFn: Decider<TState, TCommand, TEvent, TRejection>['evolve'],\n private readonly initialState: Decider<TState, TCommand, TEvent, TRejection>['initialState'],\n ) {\n }\n\n async load(aggregateId: string): Promise<TState> {\n const pastEvents = await this.eventStore.load(this.streamName, aggregateId)\n return pastEvents\n .reduce<TState>(this.evolveFn, this.initialState(aggregateId))\n }\n\n async store(events: TEvent[]): Promise<void> {\n await Promise.all(\n events.map(\n async event => this.eventStore.append(\n this.streamName,\n [event],\n ),\n ),\n )\n }\n}\n"]}
1
+ {"version":3,"sources":["../src/core/utils/getTimestamp.ts","../src/core/utils/createCommand.ts","../src/core/utils/createQuery.ts","../src/core/utils/isCommand.ts","../src/core/utils/isQuery.ts","../src/domain/Specification/Specification.ts","../src/domain/Specification/utils/createQueryNode.ts","../src/domain/Specification/implementations/FieldEquals.specification.ts","../src/utils/fail/fail.ts","../src/utils/invariant/invariant.ts","../src/domain/Specification/implementations/FieldGreaterThan.specification.ts","../src/infrastructure/EventBus/utils/createIntegrationEvent.ts","../src/domain/utils/convertDomainEventToIntegrationEvent.ts","../src/domain/utils/convertRejectionToIntegrationEvent.ts","../src/domain/utils/createDomainEvent.ts","../src/domain/utils/createRejection.ts","../src/domain/utils/isEvent.ts","../src/domain/utils/isDomainEvent.ts","../src/domain/utils/isRejection.ts","../src/infrastructure/CommandBus/implementations/SimpleCommandBus.ts","../src/infrastructure/Database/Database.ts","../src/infrastructure/Database/implementations/SimpleDatabase.exceptions.ts","../src/infrastructure/Database/implementations/SimpleDatabase.ts","../src/infrastructure/EventBus/implementations/SimpleEventBus.ts","../src/infrastructure/EventBus/utils/createExternalEvent.ts","../src/infrastructure/EventBus/utils/isExternalEvent.ts","../src/infrastructure/EventBus/utils/isIntegrationEvent.ts","../src/infrastructure/EventBus/utils/mapDomainEventToIntegrationEvent.ts","../src/infrastructure/EventBus/utils/mapRejectionToIntegrationEvent.ts","../src/utils/streamKey/makeStreamKey.ts","../src/utils/isEqual/isEqual.ts","../src/utils/parseAsError/parseAsError.ts","../src/infrastructure/EventStore/utils/createStoredEvent.ts","../src/infrastructure/EventStore/implementations/SimpleEventStore.exceptions.ts","../src/infrastructure/EventStore/implementations/SimpleEventStore.ts","../src/infrastructure/Outbox/implementations/GenericOutboxWorker.ts","../src/infrastructure/Outbox/utils/createOutboxEntry.ts","../src/infrastructure/Outbox/implementations/InMemoryOutbox.ts","../src/infrastructure/QueryBus/implementations/SimpleQueryBus.ts","../src/infrastructure/Repository/implementations/SimpleRepository.ts","../src/infrastructure/ScenarioTest/ScenarioTest.ts"],"names":["randomUUID","Operation","event"],"mappings":"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","file":"index.cjs","sourcesContent":["export const getTimestamp = (date: Date = new Date()): number => date.getTime()\n","import type { Command, CommandMetadata } from '@core/Command.ts'\nimport { randomUUID } from 'node:crypto'\nimport { getTimestamp } from '@core/utils/getTimestamp.ts'\n\nexport function createCommand<TType extends string, TPayload>(type: TType, aggregateId: string, aggregateType: string, payload: TPayload, metadata: Partial<CommandMetadata> = {}): Command<TType, TPayload> {\n return Object.freeze({\n id: randomUUID(),\n type,\n aggregateType,\n aggregateId: String(aggregateId),\n payload,\n kind: 'command',\n timestamp: getTimestamp(),\n metadata,\n })\n}\n","import type { Query, QueryMetadata } from '@core/Query.ts'\nimport { randomUUID } from 'node:crypto'\nimport { getTimestamp } from '@core/utils/getTimestamp.ts'\n\nexport function createQuery<TType extends string, TPayload>(type: TType, payload: TPayload, metadata: QueryMetadata = {}): Query<TType, TPayload> {\n return Object.freeze({\n id: randomUUID(),\n type,\n payload,\n kind: 'query',\n timestamp: getTimestamp(),\n metadata,\n })\n}\n","import type { Command } from '@core/Command.ts'\n\nexport function isCommand(candidate: unknown): candidate is Command<string, unknown> {\n if (candidate === null)\n return false\n if (typeof candidate !== 'object')\n return false\n if (!('type' in candidate))\n return false\n return 'kind' in candidate && candidate.kind === 'command'\n}\n","import type { Query } from '@core/Query.ts'\n\nexport function isQuery(candidate: unknown): candidate is Query<unknown> {\n if (candidate === null)\n return false\n if (typeof candidate !== 'object')\n return false\n if (!('type' in candidate))\n return false\n return 'kind' in candidate && candidate.kind === 'query'\n}\n","import type { QueryNode } from './QueryNode.ts'\n\nexport interface Specification<T> {\n isSatisfiedBy(entity: T): boolean\n}\n\nexport abstract class CompositeSpecification<T> implements Specification<T> {\n abstract isSatisfiedBy(entity: T): boolean\n\n abstract toQuery(): QueryNode\n\n and(other: CompositeSpecification<T>): CompositeSpecification<T> {\n return new AndSpecification(this, other)\n }\n\n or(other: CompositeSpecification<T>): CompositeSpecification<T> {\n return new OrSpecification(this, other)\n }\n\n not(): CompositeSpecification<T> {\n return new NotSpecification(this)\n }\n}\n\nexport class AndSpecification<T> extends CompositeSpecification<T> {\n constructor(private left: CompositeSpecification<T>, private right: CompositeSpecification<T>) {\n super()\n }\n\n isSatisfiedBy(entity: T): boolean {\n return this.left.isSatisfiedBy(entity) && this.right.isSatisfiedBy(entity)\n }\n\n toQuery(): QueryNode {\n return {\n type: 'and',\n nodes: [this.left.toQuery(), this.right.toQuery()],\n }\n }\n}\n\nexport class OrSpecification<T> extends CompositeSpecification<T> {\n constructor(private left: CompositeSpecification<T>, private right: CompositeSpecification<T>) {\n super()\n }\n\n isSatisfiedBy(entity: T): boolean {\n return this.left.isSatisfiedBy(entity) || this.right.isSatisfiedBy(entity)\n }\n\n toQuery(): QueryNode {\n return {\n type: 'or',\n nodes: [this.left.toQuery(), this.right.toQuery()],\n }\n }\n}\n\nexport class NotSpecification<T> extends CompositeSpecification<T> {\n constructor(private spec: CompositeSpecification<T>) {\n super()\n }\n\n isSatisfiedBy(entity: T): boolean {\n return !this.spec.isSatisfiedBy(entity)\n }\n\n toQuery(): QueryNode {\n return {\n type: 'not',\n node: this.spec.toQuery(),\n }\n }\n}\n","import type { Primitive } from '@core/types/Primitive.ts'\nimport type { QueryNode } from '../QueryNode.ts'\n\nexport function createQueryNode(type: 'eq' | 'gt' | 'lt', field: string | number | symbol, value: Primitive): QueryNode\nexport function createQueryNode(type: 'and' | 'or', field: undefined, value: QueryNode[]): QueryNode\nexport function createQueryNode(type: 'not', field: undefined, value: QueryNode): QueryNode\nexport function createQueryNode(\n type: QueryNode['type'],\n field: string | number | symbol | undefined,\n value: Primitive | QueryNode | QueryNode[],\n): QueryNode {\n switch (type) {\n case 'eq':\n case 'gt':\n case 'lt':\n return { type, field: field as string, value: value as Primitive }\n case 'and':\n case 'or':\n return { type, nodes: value as QueryNode[] }\n case 'not':\n return { type, node: value as QueryNode }\n }\n}\n","import type { Primitive } from '@core/types/Primitive.ts'\nimport type { QueryNode } from '../QueryNode.ts'\nimport { CompositeSpecification } from '../Specification.ts'\nimport { createQueryNode } from '../utils/createQueryNode.ts'\n\nexport class FieldEquals<T> extends CompositeSpecification<T> {\n constructor(private field: keyof T, private value: Primitive) {\n super()\n }\n\n isSatisfiedBy(entity: T): boolean {\n return entity[this.field] === this.value\n }\n\n toQuery(): QueryNode {\n return createQueryNode('eq', this.field, this.value)\n }\n}\n","export function fail(anExpression: Error) {\n return () => {\n throw anExpression\n }\n}\n","export function invariant(condition: boolean, onInvalid: () => never): asserts condition {\n if (!condition)\n onInvalid()\n}\n","import type { QueryNode } from '../QueryNode.ts'\nimport { fail } from '@utils/fail/fail.ts'\nimport { invariant } from '@utils/invariant/invariant.ts'\nimport { CompositeSpecification } from '../Specification.ts'\nimport { createQueryNode } from '../utils/createQueryNode.ts'\n\nexport class FieldGreaterThan<T> extends CompositeSpecification<T> {\n constructor(\n private field: keyof T,\n private value: number,\n ) {\n super()\n }\n\n private isNumber(value: unknown): value is number {\n return typeof value === 'number'\n }\n\n isSatisfiedBy(entity: T): boolean {\n const field = entity[this.field]\n invariant(\n this.isNumber(field),\n fail(new TypeError(`Field ${String(this.field)} is not a number`),\n ),\n )\n return field > this.value\n }\n\n toQuery(): QueryNode {\n return createQueryNode('gt', this.field, this.value)\n }\n}\n","import type { IntegrationEvent, IntegrationEventMetadata } from '../IntegrationEvent.ts'\nimport { randomUUID } from 'node:crypto'\n\nexport function createIntegrationEvent<TPayload = unknown>(type: string, payload: TPayload, metadata?: Partial<IntegrationEventMetadata>): IntegrationEvent<TPayload> {\n return Object.freeze({\n id: randomUUID(),\n type,\n payload,\n timestamp: new Date().toISOString(),\n metadata: {\n ...metadata,\n },\n kind: 'integration',\n })\n}\n","import type { DomainEvent } from '@domain/DomainEvent.ts'\nimport type { IntegrationEvent } from '@infrastructure/EventBus/IntegrationEvent.ts'\nimport { createIntegrationEvent } from '@infrastructure/EventBus/utils/createIntegrationEvent.ts'\n\nexport function convertDomainEventToIntegrationEvent(event: DomainEvent): IntegrationEvent {\n return createIntegrationEvent(event.type, event.payload, {\n outcome: 'accepted',\n aggregateType: event.aggregateType,\n aggregateId: event.aggregateId,\n })\n}\n","import type { Rejection } from '@domain/Rejection.ts'\nimport type { IntegrationEvent } from '@infrastructure/EventBus/IntegrationEvent.ts'\nimport { createIntegrationEvent } from '@infrastructure/EventBus/utils/createIntegrationEvent.ts'\n\nexport function convertRejectionToIntegrationEvent(rejection: Rejection): IntegrationEvent {\n return createIntegrationEvent(\n rejection.commandType,\n { ...rejection.details, reasonCode: rejection.reasonCode },\n {\n outcome: 'rejected',\n aggregateType: rejection.metadata?.aggregateType,\n aggregateId: rejection.metadata?.aggregateId,\n commandType: rejection.commandType,\n commandId: rejection.commandId,\n },\n )\n}\n","import type { DomainEvent, DomainEventMetadata } from '@domain/DomainEvent.ts'\nimport { randomUUID } from 'node:crypto'\nimport { getTimestamp } from '@core/utils/getTimestamp.ts'\n\nexport function createDomainEvent<TPayload = unknown>(\n type: string,\n aggregateId: string,\n aggregateType: string,\n payload: TPayload,\n metadata: Partial<DomainEventMetadata> = {},\n): DomainEvent<TPayload> {\n return Object.freeze({\n id: randomUUID(),\n type,\n aggregateId,\n aggregateType,\n payload,\n kind: 'domain',\n timestamp: getTimestamp(),\n metadata,\n })\n}\n","import type { Rejection, RejectionMetadata } from '@domain/Rejection.ts'\nimport { randomUUID } from 'node:crypto'\nimport { getTimestamp } from '@core/utils/getTimestamp.ts'\n\nexport function createRejection<TDetails = unknown>(\n rejectionSpecifics: {\n commandId: Rejection['commandId']\n commandType: Rejection['commandType']\n reasonCode: Rejection['reasonCode']\n reason?: Rejection['reason']\n classification: Rejection['classification']\n retryable?: Rejection['retryable']\n validationErrors?: Rejection['validationErrors']\n type: 'Failed' | 'Rejected' | string\n details?: TDetails\n },\n metadata: Partial<RejectionMetadata> = {},\n): Rejection<TDetails> {\n return Object.freeze({\n id: randomUUID(),\n commandId: rejectionSpecifics.commandId,\n commandType: rejectionSpecifics.commandType,\n reasonCode: rejectionSpecifics.reasonCode,\n reason: rejectionSpecifics.reason,\n classification: rejectionSpecifics.classification,\n retryable: rejectionSpecifics.retryable,\n validationErrors: rejectionSpecifics.validationErrors,\n type: `${rejectionSpecifics.commandType}${rejectionSpecifics.type}`,\n details: rejectionSpecifics.details,\n kind: 'rejection',\n timestamp: getTimestamp(),\n metadata,\n })\n}\n","import type { DomainEvent } from '@domain/DomainEvent.ts'\nimport type { Rejection } from '@domain/Rejection.ts'\nimport type { ExternalEvent } from '@infrastructure/EventBus/ExternalEvent.ts'\nimport type { IntegrationEvent } from '@infrastructure/EventBus/IntegrationEvent.ts'\n\nexport function isEvent(event: unknown): event is DomainEvent | IntegrationEvent | ExternalEvent | Rejection {\n if (typeof event !== 'object')\n return false\n if (event === null)\n return false\n if (!('type' in event))\n return false\n return 'kind' in event\n}\n","import type { DomainEvent } from '../DomainEvent.ts'\nimport { isEvent } from './isEvent.ts'\n\nexport function isDomainEvent(event: unknown): event is DomainEvent {\n return isEvent(event)\n && 'aggregateId' in event\n && event.kind === 'domain'\n}\n","import type { Rejection } from '@domain/Rejection.ts'\n\nexport function isRejection(candidate: unknown): candidate is Rejection {\n if (candidate === null || typeof candidate !== 'object')\n return false\n return (\n 'commandId' in candidate\n && 'commandType' in candidate\n && 'reasonCode' in candidate\n && 'timestamp' in candidate\n )\n}\n","import type { Command } from '@core/Command.ts'\nimport type { CommandHandler } from '@core/CommandHandler.ts'\nimport type { CommandBus } from '../CommandBus.ts'\n\nexport class SimpleCommandBus<TCommand extends Command> implements CommandBus<TCommand> {\n private handlers: Map<TCommand['type'], CommandHandler<TCommand>> = new Map()\n\n register(aTypeOfCommand: TCommand['type'], anHandler: CommandHandler<TCommand>): void {\n if (this.handlers.has(aTypeOfCommand)) {\n throw new Error(`Handler already registered for command type: ${aTypeOfCommand}`)\n }\n this.handlers.set(aTypeOfCommand, anHandler)\n }\n\n async execute(aCommand: TCommand): Promise<void> {\n const handler = this.handlers.get(aCommand.type)\n if (!handler) {\n throw new Error(`No handler found for command type: ${aCommand.type}`)\n }\n return handler.execute(aCommand)\n }\n}\n","import type { CompositeSpecification } from '@domain/Specification/Specification.ts'\nimport type { WithIdentifier } from '../../core/types/WithIdentifier.ts'\n\nexport enum Operation {\n CREATE = 'CREATE',\n PUT = 'PUT',\n PATCH = 'PATCH',\n DELETE = 'DELETE',\n}\n\ninterface Statement<TModel> {\n operation: Operation\n payload: TModel\n}\n\nexport interface CreateStatement<TModel> extends Statement<TModel> {\n operation: Operation.CREATE\n payload: TModel\n}\n\nexport interface PutStatement<TModel> extends Statement<TModel> {\n operation: Operation.PUT\n payload: TModel\n}\n\nexport interface PatchStatement<TModel> extends Statement<Partial<TModel>> {\n operation: Operation.PATCH\n payload: WithIdentifier<Partial<TModel>>\n}\n\nexport interface DeleteStatement extends Statement<WithIdentifier> {\n operation: Operation.DELETE\n payload: WithIdentifier\n}\n\ninterface Executable<TModel, TReturnType = Promise<void>> {\n execute(tableName: string, statement: CreateStatement<TModel>): TReturnType\n execute(tableName: string, statement: PutStatement<TModel>): TReturnType\n execute(tableName: string, statement: PatchStatement<TModel>): TReturnType\n execute(tableName: string, statement: DeleteStatement): TReturnType\n}\n\ninterface QueryAble<TModel, TReturnType = Promise<TModel[]>> {\n query(collectionName: string, specification: CompositeSpecification<TModel>): TReturnType\n}\n\nexport interface Database<TModel, TExecuteReturnType = Promise<void>, TQueryReturnType = Promise<TModel[]>>\n extends\n QueryAble<TModel, TQueryReturnType>,\n Executable<TModel, TExecuteReturnType> { }\n","export class RecordNotFoundException extends Error {\n constructor(id: string) {\n super(`Record not found for id: ${id}`)\n }\n}\n\nexport class DuplicateRecordException extends Error {\n constructor(id: string) {\n super(`Duplicate record found for id: ${id}`)\n }\n}\n\nexport class DatabaseOfflineException extends Error {\n constructor() {\n super(`Database is offline`)\n }\n}\n","import type { CompositeSpecification } from '@domain/Specification/Specification.ts'\nimport type { WithIdentifier } from '../../../core/types/WithIdentifier.ts'\nimport type { CreateStatement, Database, DeleteStatement, PatchStatement, PutStatement } from '../Database.ts'\nimport { Operation } from '../Database.ts'\nimport { DatabaseOfflineException, DuplicateRecordException, RecordNotFoundException } from './SimpleDatabase.exceptions.ts'\n\nexport class SimpleDatabase<TModel extends WithIdentifier> implements Database<TModel, Promise<void>, Promise<TModel[]>> {\n private readonly datasource = new Map<string, TModel[]>()\n private simulateOffline = false\n\n async query(\n tableName: string,\n specification: CompositeSpecification<TModel>,\n ): Promise<TModel[]> {\n if (this.simulateOffline)\n throw new DatabaseOfflineException()\n\n const tableRecords = (this.datasource.get(tableName) || [])\n return tableRecords\n .filter((record: TModel) => specification.isSatisfiedBy(record))\n }\n\n async execute(\n tableName: string,\n statement: CreateStatement<TModel> | PutStatement<TModel> | PatchStatement<TModel> | DeleteStatement,\n ): Promise<void> {\n if (this.simulateOffline)\n throw new DatabaseOfflineException()\n\n if (!this.datasource.has(tableName))\n this.datasource.set(tableName, [])\n const table = this.datasource.get(tableName)!\n\n switch (statement.operation) {\n case Operation.CREATE: {\n const isDuplicate = table.some(item => item.id === statement.payload.id)\n if (isDuplicate)\n throw new DuplicateRecordException(statement.payload.id)\n table.push(statement.payload)\n break\n }\n case Operation.PUT:{\n const index = table.findIndex(item => item.id === statement.payload.id)\n if (index === -1)\n throw new RecordNotFoundException(statement.payload.id)\n table[index] = statement.payload\n break\n }\n case Operation.PATCH:{\n const index = table.findIndex(item => item.id === statement.payload.id)\n if (index === -1)\n throw new RecordNotFoundException(statement.payload.id)\n table[index] = { ...table[index], ...statement.payload }\n break\n }\n case Operation.DELETE:{\n const index = table.findIndex(item => item.id === statement.payload.id)\n if (index === -1)\n throw new RecordNotFoundException(statement.payload.id)\n table.splice(index, 1)\n break\n }\n }\n }\n\n goOffline(): void {\n this.simulateOffline = true\n }\n}\n","import type { EventHandler } from '@core/EventHandler.ts'\nimport type { DomainEvent } from '@domain/DomainEvent.ts'\nimport type { ExternalEvent } from '@infrastructure/EventBus/ExternalEvent.ts'\nimport type { IntegrationEvent } from '@infrastructure/EventBus/IntegrationEvent.ts'\nimport type { EventConsumer, EventProducer } from '../EventBus.ts'\n\nexport class SimpleEventBus<TEvent extends DomainEvent | IntegrationEvent | ExternalEvent>\nimplements EventConsumer<TEvent>, EventProducer<TEvent> {\n private handlers = new Map<string, EventHandler<TEvent>[]>()\n\n subscribe(\n stream: string,\n aHandler: EventHandler<TEvent>,\n ): void {\n const handlersForType = this.handlers.get(stream) ?? []\n handlersForType.push(aHandler)\n this.handlers.set(stream, handlersForType)\n }\n\n async consume(stream: string, anEvent: TEvent): Promise<void> {\n if (!this.handlers.has(stream))\n return\n const handlers = this.handlers.get(stream) as EventHandler<TEvent>[]\n await Promise.all(handlers.map(async (handler) => {\n return handler.handle(anEvent)\n }))\n }\n\n async publish(stream: string, anEvent: TEvent): Promise<void> {\n await this.consume(stream, anEvent)\n }\n}\n","import type { ExternalEvent, ExternalEventMetadata } from '../ExternalEvent.ts'\nimport { randomUUID } from 'node:crypto'\n\nexport function createExternalEvent<TPayload = unknown>(type: string, payload: TPayload, metadata?: Partial<ExternalEventMetadata>): ExternalEvent<TPayload> {\n return Object.freeze({\n id: randomUUID(),\n type,\n payload,\n timestamp: new Date().toISOString(),\n metadata: {\n ...metadata,\n },\n kind: 'external',\n })\n}\n","import type { ExternalEvent } from '@infrastructure/EventBus/ExternalEvent.ts'\nimport { isEvent } from '@domain/utils/isEvent.ts'\n\nexport function isExternalEvent<TPayload>(event: unknown): event is ExternalEvent<TPayload> {\n return isEvent(event)\n && event.kind === 'external'\n}\n","import type { IntegrationEvent } from '../IntegrationEvent.ts'\nimport { isEvent } from '@domain/utils/isEvent.ts'\n\nexport function isIntegrationEvent<TPayload>(event: unknown): event is IntegrationEvent<TPayload> {\n return isEvent(event)\n && event.kind === 'integration'\n}\n","import type { DomainEvent } from '@domain/DomainEvent.ts'\nimport type { IntegrationEvent, IntegrationEventMetadata } from '@infrastructure/EventBus/IntegrationEvent.ts'\n\nexport function mapDomainEventToIntegrationEvent<TPayload>(\n domainEvent: DomainEvent<TPayload>,\n): IntegrationEvent<TPayload> {\n const metadata: Partial<IntegrationEventMetadata> = {\n ...domainEvent.metadata,\n aggregateType: domainEvent.aggregateType,\n aggregateId: domainEvent.aggregateId,\n outcome: 'accepted',\n }\n\n return {\n id: domainEvent.id,\n type: domainEvent.type,\n payload: domainEvent.payload,\n timestamp: new Date(domainEvent.timestamp).toISOString(),\n metadata,\n kind: 'integration',\n }\n}\n","import type { Rejection } from '@domain/Rejection.ts'\nimport type { IntegrationEvent, IntegrationEventMetadata } from '@infrastructure/EventBus/IntegrationEvent.ts'\n\nexport function mapRejectionToIntegrationEvent<TDetails>(\n rejection: Rejection<TDetails>,\n): IntegrationEvent<{\n reasonCode: Rejection<TDetails>['reasonCode']\n reason?: string\n classification?: Rejection<TDetails>['classification']\n retryable?: boolean\n details?: TDetails\n validationErrors?: Rejection<TDetails>['validationErrors']\n}> {\n const metadata: Partial<IntegrationEventMetadata> = {\n ...rejection.metadata,\n outcome: 'rejected',\n commandId: rejection.commandId,\n commandType: rejection.commandType,\n }\n\n return {\n id: rejection.id,\n type: rejection.type,\n payload: {\n reasonCode: rejection.reasonCode,\n reason: rejection.reason,\n classification: rejection.classification,\n retryable: rejection.retryable,\n details: rejection.details,\n validationErrors: rejection.validationErrors,\n },\n timestamp: new Date(rejection.timestamp).toISOString(),\n metadata,\n kind: 'integration',\n }\n}\n","import type { StreamKey } from '@utils/streamKey/StreamKey.ts'\n\nexport function makeStreamKey(streamName: string, aggregateId: string): StreamKey {\n return `${streamName}#${aggregateId}`\n}\n","export function isEqual<T>(a: T, b: T): boolean {\n if (a === b) {\n return true\n }\n\n // eslint-disable-next-line ts/strict-boolean-expressions\n const bothAreObjects = a && b && typeof a === 'object' && typeof b === 'object'\n\n return Boolean(\n bothAreObjects\n && Object.keys(a).length === Object.keys(b).length\n && Object.entries(a).every(([k, v]) => isEqual(v, b[k as keyof T])),\n )\n}\n","export function parseAsError(value: unknown): Error {\n if (value instanceof Error)\n return value\n if (typeof value === 'string')\n return new Error(value)\n try {\n const json = JSON.stringify(value)\n return new Error(json ?? String(value))\n }\n catch {\n return new Error('Unknown error')\n }\n}\n","import type { DomainEvent } from '@domain/DomainEvent.ts'\nimport type { StoredEvent } from '../StoredEvent.ts'\nimport { getTimestamp } from '@core/utils/getTimestamp.ts'\nimport { makeStreamKey } from '@utils/index.ts'\n\nexport function createStoredEvent<TEvent extends DomainEvent>(\n streamName: string,\n version: number,\n event: TEvent,\n): StoredEvent<TEvent> {\n return Object.freeze({\n id: event.id,\n streamKey: makeStreamKey(streamName, event.aggregateId),\n version,\n timestamp: getTimestamp(),\n event,\n })\n}\n","export class MultipleAggregatesException extends Error {\n constructor() {\n super('EventStore append does not support multiple aggregates to be stored')\n }\n}\n","import type { DomainEvent } from '@domain/DomainEvent.ts'\nimport type { Database } from '@infrastructure/Database/Database.ts'\nimport type { EventStore } from '@infrastructure/EventStore/EventStore.ts'\nimport type { Outbox } from '@infrastructure/Outbox/Outbox.ts'\nimport type { StreamKey } from '@utils/streamKey/StreamKey.ts'\nimport type { StoredEvent } from '../StoredEvent.ts'\nimport { FieldEquals } from '@domain/Specification/implementations/FieldEquals.specification.ts'\nimport { Operation } from '@infrastructure/Database/Database.ts'\nimport { makeStreamKey } from '@utils/streamKey/makeStreamKey.ts'\nimport { createStoredEvent } from '../utils/createStoredEvent.ts'\nimport { MultipleAggregatesException } from './SimpleEventStore.exceptions.ts'\n\nexport class SimpleEventStore<TEvent extends DomainEvent> implements EventStore<TEvent, Promise<void>, Promise<TEvent[]>> {\n private readonly tableName: string = 'event_store'\n\n constructor(\n private readonly database: Database<StoredEvent<TEvent>, Promise<void>, Promise<StoredEvent<TEvent>[]>>,\n private readonly outbox?: Outbox,\n ) { }\n\n async load(streamName: string, aggregateId: string): Promise<TEvent[]> {\n const streamKey: StreamKey = makeStreamKey(streamName, aggregateId)\n const specification = new FieldEquals('streamKey', streamKey)\n const storedEvents = await this.database.query(this.tableName, specification)\n return storedEvents.map(storedEvent => storedEvent.event)\n }\n\n async append(streamName: string, events: TEvent[]): Promise<void> {\n const uniqueAggregateIds = new Set(events.map(event => event.aggregateId))\n if (uniqueAggregateIds.size > 1)\n throw new MultipleAggregatesException()\n\n const event = events[0]\n const currentStream = await this.load(streamName, event.aggregateId)\n const eventsToStore = events\n .map(event => createStoredEvent(streamName, currentStream.length + 1, event))\n await Promise.all(\n eventsToStore.map(async payload => this.database.execute(this.tableName, { operation: Operation.CREATE, payload }),\n ),\n )\n await Promise.all(events.map(async event => this.outbox?.enqueue(event)))\n }\n}\n","import type { DomainEvent } from '@domain/DomainEvent.ts'\nimport type { EventProducer } from '@infrastructure/EventBus/EventBus.js'\nimport type { ExternalEvent } from '@infrastructure/EventBus/ExternalEvent.ts'\nimport type { IntegrationEvent } from '@infrastructure/EventBus/IntegrationEvent.ts'\nimport type { OutboxWorker } from '@infrastructure/Outbox/OutboxWorker.ts'\nimport type { Outbox } from '../Outbox.ts'\n\nexport class GenericOutboxWorker implements OutboxWorker {\n constructor(\n protected outbox: Outbox,\n protected eventBus: EventProducer<DomainEvent | IntegrationEvent | ExternalEvent>,\n protected stream: string,\n ) {}\n\n async runOnce(): Promise<void> {\n const pending = await this.outbox.getPending()\n\n await Promise.all(pending.map(async (entry) => {\n try {\n await this.eventBus.publish(this.stream, entry.event)\n await this.outbox.markAsPublished(entry.id)\n }\n catch {\n await this.outbox.markAsFailed(entry.id)\n }\n }))\n }\n\n async tick(): Promise<void> {\n await this.runOnce()\n }\n\n start(intervalMs: number): void {\n setInterval(() => {\n void this.tick().catch(console.error)\n }, intervalMs)\n }\n}\n","import type { IntegrationEvent } from '@infrastructure/EventBus/IntegrationEvent.ts'\nimport type { OutboxEntry } from '../OutboxEntry.ts'\nimport { randomUUID } from 'node:crypto'\n\nexport function createOutboxEntry(\n event: IntegrationEvent,\n): OutboxEntry {\n return {\n id: randomUUID(),\n event,\n published: false,\n retryCount: 0,\n lastAttemptAt: undefined,\n }\n}\n","import type { DomainEvent } from '@domain/DomainEvent.ts'\nimport type { Rejection } from '@domain/Rejection.ts'\nimport type { Outbox } from '../Outbox.ts'\nimport type { OutboxEntry } from '../OutboxEntry.ts'\nimport { getTimestamp } from '@core/utils/getTimestamp.ts'\nimport { convertDomainEventToIntegrationEvent } from '@domain/utils/convertDomainEventToIntegrationEvent.ts'\nimport { convertRejectionToIntegrationEvent } from '@domain/utils/convertRejectionToIntegrationEvent.ts'\nimport { isRejection } from '@domain/utils/isRejection.ts'\nimport { createOutboxEntry } from '../utils/createOutboxEntry.ts'\n\nexport class InMemoryOutbox implements Outbox {\n protected entries: OutboxEntry[] = []\n protected idCounter = 0\n\n async enqueue(event: DomainEvent | Rejection): Promise<void> {\n const integrationEvent = isRejection(event)\n ? convertRejectionToIntegrationEvent(event)\n : convertDomainEventToIntegrationEvent(event)\n this.entries.push(createOutboxEntry(integrationEvent))\n }\n\n async getPending(limit = 100): Promise<OutboxEntry[]> {\n return this.entries.filter(e => !e.published).slice(0, limit)\n }\n\n async markAsPublished(id: string): Promise<void> {\n const entry = this.entries.find(e => e.id === id)\n if (entry) {\n entry.published = true\n }\n }\n\n async markAsFailed(id: string): Promise<void> {\n const entry = this.entries.find(e => e.id === id)\n if (entry) {\n entry.retryCount += 1\n entry.lastAttemptAt = getTimestamp()\n }\n }\n}\n","import type { Query } from '@core/Query.ts'\nimport type { QueryHandler } from '@core/QueryHandler.ts'\nimport type { QueryBus } from '../QueryBus.ts'\n\nexport class SimpleQueryBus<TQuery extends Query, TProjection> implements QueryBus<TQuery, Promise<TProjection>> {\n private handlers: Map<TQuery['type'], QueryHandler<TQuery, Promise<TProjection>>> = new Map()\n\n register(\n aTypeOfQuery: TQuery['type'],\n anHandler: QueryHandler<TQuery, Promise<TProjection>>,\n ): void {\n if (this.handlers.has(aTypeOfQuery)) {\n throw new Error(`Handler already registered for query type: ${aTypeOfQuery}`)\n }\n this.handlers.set(aTypeOfQuery, anHandler)\n }\n\n async execute(aQuery: TQuery): Promise<TProjection> {\n const handler = this.handlers.get(aQuery.type)\n if (!handler) {\n throw new Error(`No handler found for query type: ${aQuery.type}`)\n }\n return handler.execute(aQuery)\n }\n}\n","import type { Decider } from '@domain/Decider.ts'\nimport type { DomainEvent } from '@domain/DomainEvent.ts'\nimport type { Repository } from '@domain/Repository.ts'\nimport type { EventStore } from '@infrastructure/EventStore/EventStore.ts'\n\nexport class SimpleRepository<TState, TCommand, TEvent extends DomainEvent> implements Repository<TEvent, Promise<TState>, Promise<void>> {\n constructor(\n private readonly eventStore: EventStore<TEvent, Promise<void>, Promise<TEvent[]>>,\n readonly streamName: string,\n private readonly evolveFn: Decider<TState, TCommand, TEvent>['evolve'],\n private readonly initialState: Decider<TState, TCommand, TEvent>['initialState'],\n ) {\n }\n\n async load(aggregateId: string): Promise<TState> {\n const pastEvents = await this.eventStore.load(this.streamName, aggregateId)\n return pastEvents\n .reduce<TState>(this.evolveFn, this.initialState(aggregateId))\n }\n\n async store(events: TEvent[]): Promise<void> {\n await Promise.all(\n events.map(\n async event => this.eventStore.append(\n this.streamName,\n [event],\n ),\n ),\n )\n }\n}\n","import type { Command } from '@core/Command.ts'\nimport type { Query } from '@core/Query.ts'\nimport type { DomainEvent } from '@domain/DomainEvent.ts'\nimport type { Rejection } from '@domain/Rejection.ts'\nimport type { Repository } from '@domain/Repository.ts'\nimport type { EventConsumer, EventProducer } from '@infrastructure/EventBus/EventBus.ts'\nimport type { ExternalEvent } from '@infrastructure/EventBus/ExternalEvent.ts'\nimport type { IntegrationEvent } from '@infrastructure/EventBus/IntegrationEvent.ts'\nimport type { EventStore } from '@infrastructure/EventStore/EventStore.ts'\nimport type { Outbox } from '@infrastructure/Outbox/Outbox.ts'\nimport type { OutboxWorker } from '@infrastructure/Outbox/OutboxWorker.ts'\nimport type { CommandBus } from '../CommandBus/CommandBus.ts'\nimport type { QueryBus } from '../QueryBus/QueryBus.ts'\nimport { isCommand } from '@core/utils/isCommand.ts'\nimport { isQuery } from '@core/utils/isQuery.ts'\nimport { isDomainEvent } from '@domain/utils/isDomainEvent.ts'\nimport { isEvent } from '@domain/utils/isEvent.ts'\nimport { isRejection } from '@domain/utils/isRejection.ts'\nimport { fail } from '@utils/fail/fail.ts'\nimport { invariant } from '@utils/invariant/invariant.ts'\nimport { isEqual } from '@utils/isEqual/isEqual.ts'\n\ntype GivenInput = DomainEvent[]\ntype WhenInput = Command | Query | DomainEvent | IntegrationEvent | ExternalEvent\ntype ThenInput = DomainEvent | Rejection | Array<Record<string, unknown>>\n\nexport class ScenarioTest<TState, TEvent extends DomainEvent> {\n private givenInput: GivenInput = []\n private whenInput: WhenInput | undefined\n\n constructor(\n private readonly streamName: string,\n private readonly eventBus: EventProducer<DomainEvent | IntegrationEvent | ExternalEvent> & EventConsumer<DomainEvent | IntegrationEvent | ExternalEvent>,\n private readonly eventStore: EventStore<TEvent, Promise<void>, Promise<TEvent[]>>,\n private readonly commandBus: CommandBus<Command>,\n private readonly queryBus: QueryBus<Query, Promise<Record<string, unknown>[]>>,\n private readonly repository: Repository<DomainEvent, Promise<TState>>,\n private readonly outboxWorker: OutboxWorker,\n private readonly outbox: Outbox,\n ) {}\n\n given(...events: GivenInput): {\n when(action: WhenInput): ReturnType<ScenarioTest<TState, TEvent>['when']>\n then(outcome: ThenInput): Promise<void>\n } {\n this.givenInput = events\n return {\n when: this.when.bind(this),\n then: this.then.bind(this),\n }\n }\n\n when(action: WhenInput): {\n then(outcome: ThenInput): Promise<void>\n } {\n this.whenInput = action\n return {\n then: this.then.bind(this),\n }\n }\n\n async then(thenInput: ThenInput): Promise<void> {\n await Promise.all([\n this.repository.store(this.givenInput),\n ...this.givenInput.map(async event => this.eventBus.consume(this.streamName, event)),\n ])\n\n if (!this.whenInput) {\n throw new Error('In the ScenarioTest, the when-step cannot be empty')\n }\n\n if (isCommand(this.whenInput)) {\n invariant(\n isDomainEvent(thenInput) || isRejection(thenInput),\n fail(new TypeError('When \"command\" expects a domain event or rejection in the then-step')),\n )\n await this.handleCommand(this.whenInput, thenInput)\n return\n }\n\n if (isQuery(this.whenInput)) {\n invariant(\n Array.isArray(thenInput),\n fail(new TypeError('When \"query\" expects an array of expected results in the then-step')),\n )\n await this.handleQuery(this.whenInput, thenInput)\n return\n }\n\n invariant(\n isDomainEvent(thenInput),\n fail(new TypeError('When \"domain event\" or \"integration event\" expects a domain event in the then-step')),\n )\n await this.handleEvent(this.whenInput as DomainEvent | IntegrationEvent, thenInput)\n }\n\n private async handleCommand(command: Command, outcome: DomainEvent | Rejection): Promise<void> {\n await this.commandBus.execute(command)\n\n if (isRejection(outcome)) {\n const pending = await this.outbox.getPending()\n const foundRejection = pending.find(\n entry =>\n entry.event.metadata.outcome === 'rejected'\n && entry.event.metadata.commandType === outcome.commandType\n && (entry.event.payload as { reasonCode?: string }).reasonCode === outcome.reasonCode,\n )\n invariant(!!foundRejection, fail(new Error('ScenarioTest: rejection was not found in outbox')))\n return\n }\n\n const actualEvents = await this.eventStore.load(this.streamName, outcome.aggregateId)\n const foundEvent = actualEvents.findLast(\n event =>\n isDomainEvent(event)\n && event.aggregateId === outcome.aggregateId\n && event.type === outcome.type,\n )\n invariant(!!foundEvent, fail(new Error('ScenarioTest: event/command was not found')))\n invariant(\n outcome.type === foundEvent.type,\n fail(new Error('ScenarioTest: event/command type was not equal')),\n )\n invariant(\n outcome.aggregateId === foundEvent.aggregateId,\n fail(new Error('ScenarioTest: event/command aggregate id was not equal')),\n )\n invariant(\n isEqual(outcome.payload, foundEvent.payload),\n fail(new Error('ScenarioTest: event/command payload was not equal')),\n )\n }\n\n private async handleQuery(query: Query, expected: Array<Record<string, unknown>>): Promise<void> {\n await this.outboxWorker.tick()\n const actual = await this.queryBus.execute(query)\n invariant(\n isEqual(actual, expected),\n fail(new Error('ScenarioTest: a different query result was returned')),\n )\n }\n\n private async handleEvent(\n event: DomainEvent | IntegrationEvent,\n outcome: DomainEvent,\n ): Promise<void> {\n await this.eventBus.publish(this.streamName, event)\n const actualEvents = await this.eventStore.load(this.streamName, outcome.aggregateId)\n const foundEvent = actualEvents.findLast(\n event =>\n isEvent(event) && event.aggregateId === outcome.aggregateId && event.type === outcome.type,\n )\n invariant(!!foundEvent, fail(new Error('ScenarioTest: event was not found')))\n invariant(isEvent(foundEvent), fail(new Error('ScenarioTest: event is not of type event')))\n invariant(\n outcome.type === foundEvent.type,\n fail(new Error('ScenarioTest: event type was not equal')),\n )\n invariant(\n outcome.aggregateId === foundEvent.aggregateId,\n fail(new Error('ScenarioTest: event aggregate id was not equal')),\n )\n invariant(\n isEqual(outcome.payload, foundEvent.payload),\n fail(new Error('ScenarioTest: event payload was not equal')),\n )\n }\n}\n"]}