@ddd-ts-kit/testing 0.8.0 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (134) hide show
  1. package/README.md +19 -0
  2. package/dist/contracts/event-store/companion-stores-suite.d.ts +12 -0
  3. package/dist/contracts/event-store/companion-stores-suite.d.ts.map +1 -0
  4. package/dist/contracts/event-store/companion-stores-suite.js +60 -0
  5. package/dist/contracts/event-store/companion-stores-suite.js.map +1 -0
  6. package/dist/contracts/event-store/consignment-registered.d.ts +8 -0
  7. package/dist/contracts/event-store/consignment-registered.d.ts.map +1 -0
  8. package/dist/contracts/event-store/consignment-registered.js +10 -0
  9. package/dist/contracts/event-store/consignment-registered.js.map +1 -0
  10. package/dist/contracts/event-store/consignment-weighed.d.ts +9 -0
  11. package/dist/contracts/event-store/consignment-weighed.d.ts.map +1 -0
  12. package/dist/contracts/event-store/consignment-weighed.js +12 -0
  13. package/dist/contracts/event-store/consignment-weighed.js.map +1 -0
  14. package/dist/contracts/event-store/consignment.d.ts +16 -0
  15. package/dist/contracts/event-store/consignment.d.ts.map +1 -0
  16. package/dist/contracts/event-store/consignment.js +36 -0
  17. package/dist/contracts/event-store/consignment.js.map +1 -0
  18. package/dist/contracts/event-store/consignments.d.ts +10 -0
  19. package/dist/contracts/event-store/consignments.d.ts.map +1 -0
  20. package/dist/contracts/event-store/consignments.js +34 -0
  21. package/dist/contracts/event-store/consignments.js.map +1 -0
  22. package/dist/contracts/event-store/event-of.d.ts +4 -0
  23. package/dist/contracts/event-store/event-of.d.ts.map +1 -0
  24. package/dist/contracts/event-store/event-of.js +13 -0
  25. package/dist/contracts/event-store/event-of.js.map +1 -0
  26. package/dist/contracts/event-store/event-store-under-contract.d.ts +11 -0
  27. package/dist/contracts/event-store/event-store-under-contract.d.ts.map +1 -0
  28. package/dist/contracts/event-store/event-store-under-contract.js +2 -0
  29. package/dist/contracts/event-store/event-store-under-contract.js.map +1 -0
  30. package/dist/contracts/event-store/one-transaction-suite.d.ts +18 -0
  31. package/dist/contracts/event-store/one-transaction-suite.d.ts.map +1 -0
  32. package/dist/contracts/event-store/one-transaction-suite.js +92 -0
  33. package/dist/contracts/event-store/one-transaction-suite.js.map +1 -0
  34. package/dist/contracts/event-store/store-suite.d.ts +10 -0
  35. package/dist/contracts/event-store/store-suite.d.ts.map +1 -0
  36. package/dist/contracts/event-store/store-suite.js +44 -0
  37. package/dist/contracts/event-store/store-suite.js.map +1 -0
  38. package/dist/contracts/event-store/stream-suite.d.ts +11 -0
  39. package/dist/contracts/event-store/stream-suite.d.ts.map +1 -0
  40. package/dist/contracts/event-store/stream-suite.js +91 -0
  41. package/dist/contracts/event-store/stream-suite.js.map +1 -0
  42. package/dist/contracts/event-store-contract.d.ts +20 -0
  43. package/dist/contracts/event-store-contract.d.ts.map +1 -0
  44. package/dist/contracts/event-store-contract.js +21 -0
  45. package/dist/contracts/event-store-contract.js.map +1 -0
  46. package/dist/contracts/event-store-unit-of-work-contract.d.ts +15 -0
  47. package/dist/contracts/event-store-unit-of-work-contract.d.ts.map +1 -0
  48. package/dist/contracts/event-store-unit-of-work-contract.js +10 -0
  49. package/dist/contracts/event-store-unit-of-work-contract.js.map +1 -0
  50. package/dist/contracts/file-storage/arrangement-suite.d.ts +9 -0
  51. package/dist/contracts/file-storage/arrangement-suite.d.ts.map +1 -0
  52. package/dist/contracts/file-storage/arrangement-suite.js +51 -0
  53. package/dist/contracts/file-storage/arrangement-suite.js.map +1 -0
  54. package/dist/contracts/file-storage/checksum-of.d.ts +3 -0
  55. package/dist/contracts/file-storage/checksum-of.d.ts.map +1 -0
  56. package/dist/contracts/file-storage/checksum-of.js +10 -0
  57. package/dist/contracts/file-storage/checksum-of.js.map +1 -0
  58. package/dist/contracts/file-storage/chunks-of.d.ts +3 -0
  59. package/dist/contracts/file-storage/chunks-of.d.ts.map +1 -0
  60. package/dist/contracts/file-storage/chunks-of.js +5 -0
  61. package/dist/contracts/file-storage/chunks-of.js.map +1 -0
  62. package/dist/contracts/file-storage/content-suite.d.ts +12 -0
  63. package/dist/contracts/file-storage/content-suite.d.ts.map +1 -0
  64. package/dist/contracts/file-storage/content-suite.js +110 -0
  65. package/dist/contracts/file-storage/content-suite.js.map +1 -0
  66. package/dist/contracts/file-storage/contents.d.ts +7 -0
  67. package/dist/contracts/file-storage/contents.d.ts.map +1 -0
  68. package/dist/contracts/file-storage/contents.js +7 -0
  69. package/dist/contracts/file-storage/contents.js.map +1 -0
  70. package/dist/contracts/file-storage/file-storage-contract-options.d.ts +17 -0
  71. package/dist/contracts/file-storage/file-storage-contract-options.d.ts.map +1 -0
  72. package/dist/contracts/file-storage/file-storage-contract-options.js +2 -0
  73. package/dist/contracts/file-storage/file-storage-contract-options.js.map +1 -0
  74. package/dist/contracts/file-storage/file-storage-suite.d.ts +14 -0
  75. package/dist/contracts/file-storage/file-storage-suite.d.ts.map +1 -0
  76. package/dist/contracts/file-storage/file-storage-suite.js +30 -0
  77. package/dist/contracts/file-storage/file-storage-suite.js.map +1 -0
  78. package/dist/contracts/file-storage/follow-served.d.ts +9 -0
  79. package/dist/contracts/file-storage/follow-served.d.ts.map +1 -0
  80. package/dist/contracts/file-storage/follow-served.js +28 -0
  81. package/dist/contracts/file-storage/follow-served.js.map +1 -0
  82. package/dist/contracts/file-storage/follow-with-fetch.d.ts +5 -0
  83. package/dist/contracts/file-storage/follow-with-fetch.d.ts.map +1 -0
  84. package/dist/contracts/file-storage/follow-with-fetch.js +14 -0
  85. package/dist/contracts/file-storage/follow-with-fetch.js.map +1 -0
  86. package/dist/contracts/file-storage/followed-response.d.ts +7 -0
  87. package/dist/contracts/file-storage/followed-response.d.ts.map +1 -0
  88. package/dist/contracts/file-storage/followed-response.js +2 -0
  89. package/dist/contracts/file-storage/followed-response.js.map +1 -0
  90. package/dist/contracts/file-storage/large-content.d.ts +3 -0
  91. package/dist/contracts/file-storage/large-content.d.ts.map +1 -0
  92. package/dist/contracts/file-storage/large-content.js +8 -0
  93. package/dist/contracts/file-storage/large-content.js.map +1 -0
  94. package/dist/contracts/file-storage/read-all.d.ts +3 -0
  95. package/dist/contracts/file-storage/read-all.d.ts.map +1 -0
  96. package/dist/contracts/file-storage/read-all.js +9 -0
  97. package/dist/contracts/file-storage/read-all.js.map +1 -0
  98. package/dist/contracts/file-storage/signed-links-suite.d.ts +11 -0
  99. package/dist/contracts/file-storage/signed-links-suite.d.ts.map +1 -0
  100. package/dist/contracts/file-storage/signed-links-suite.js +93 -0
  101. package/dist/contracts/file-storage/signed-links-suite.js.map +1 -0
  102. package/dist/contracts/file-storage/signed-request.d.ts +8 -0
  103. package/dist/contracts/file-storage/signed-request.d.ts.map +1 -0
  104. package/dist/contracts/file-storage/signed-request.js +2 -0
  105. package/dist/contracts/file-storage/signed-request.js.map +1 -0
  106. package/dist/contracts/file-storage/tampered.d.ts +3 -0
  107. package/dist/contracts/file-storage/tampered.d.ts.map +1 -0
  108. package/dist/contracts/file-storage/tampered.js +5 -0
  109. package/dist/contracts/file-storage/tampered.js.map +1 -0
  110. package/dist/contracts/file-storage-contract.d.ts +11 -0
  111. package/dist/contracts/file-storage-contract.d.ts.map +1 -0
  112. package/dist/contracts/file-storage-contract.js +16 -0
  113. package/dist/contracts/file-storage-contract.js.map +1 -0
  114. package/dist/contracts.d.ts +9 -0
  115. package/dist/contracts.d.ts.map +1 -1
  116. package/dist/contracts.js +5 -0
  117. package/dist/contracts.js.map +1 -1
  118. package/dist/event-sourcing/expect-snapshot-equivalence.d.ts +14 -0
  119. package/dist/event-sourcing/expect-snapshot-equivalence.d.ts.map +1 -0
  120. package/dist/event-sourcing/expect-snapshot-equivalence.js +48 -0
  121. package/dist/event-sourcing/expect-snapshot-equivalence.js.map +1 -0
  122. package/dist/event-sourcing/given-events.d.ts +12 -0
  123. package/dist/event-sourcing/given-events.d.ts.map +1 -0
  124. package/dist/event-sourcing/given-events.js +16 -0
  125. package/dist/event-sourcing/given-events.js.map +1 -0
  126. package/dist/event-sourcing/snapshot-equivalence.d.ts +12 -0
  127. package/dist/event-sourcing/snapshot-equivalence.d.ts.map +1 -0
  128. package/dist/event-sourcing/snapshot-equivalence.js +2 -0
  129. package/dist/event-sourcing/snapshot-equivalence.js.map +1 -0
  130. package/dist/index.d.ts +3 -0
  131. package/dist/index.d.ts.map +1 -1
  132. package/dist/index.js +2 -0
  133. package/dist/index.js.map +1 -1
  134. package/package.json +4 -4
package/README.md CHANGED
@@ -184,6 +184,22 @@ side, so they read well under any runner. An error raised by `when` is never swa
184
184
  assertion but `thenError` fails on it. When `when` (or the arrangement) is asynchronous, the
185
185
  chain is a promise: `await given(order).when(async (o) => ...).thenEventNames([...])`.
186
186
 
187
+ ### An event-sourced aggregate
188
+
189
+ `givenEvents(rehydrate, events)` rebuilds the aggregate by replaying its history, without a
190
+ database, and the scenario goes on as above: one command, then the events it recorded or the
191
+ refusal.
192
+
193
+ ```ts
194
+ givenEvents((id, history) => AttendanceRecord.rehydrate(id, history), [opened, noShowNoted, noShowNoted])
195
+ .when((record) => record.noteNoShow('appointment-9', now))
196
+ .thenEvents([NoShowNoted, AttendanceRecordBarred]);
197
+ ```
198
+
199
+ `expectSnapshotEquivalence({ events, rehydrate, policy, state })` proves the snapshots of an
200
+ aggregate: for every version of the history, the aggregate rebuilt from the snapshot its policy
201
+ would store and the events after it has the state and the version of the full replay.
202
+
187
203
  ## Refusals
188
204
 
189
205
  A business refusal is known by its code, and carries its facts as data: a test asserts both,
@@ -436,12 +452,15 @@ repositoryContract(runner, { ...options, name: 'DrizzleOrderRepository', createR
436
452
  | `unitOfWorkContract` | any `UnitOfWork`, called through `run` without a command bus: domain events wait for the end and are dispatched before the commit, so handlers see every save and what they write, the outbox included, commits with it; a failure in a save, in the work, in a handler or in the commit (a deferred constraint) leaves nothing behind; `after-commit` handlers run once the rows are committed, never otherwise. An adapter not built on `withinUnitOfWork` fails here |
437
453
  | `outboxStoreContract` | any outbox store: order, limit, lease, concurrent claims, published, failed, dead, `retryDead`, purge; with `carriesTenant: true`, the tenant of each event kept |
438
454
  | `processedEventStoreContract` | any `ProcessedEventStore`: once per consumer and event, also under concurrent deliveries |
455
+ | `eventStoreContract` | any `EventStore`: a stream created at version 0 and read back in order, numbered from 1, with its type, shape version, data, metadata and instant; an append at a version the stream no longer has (behind or ahead) refused with `CONCURRENCY_CONFLICT` and nothing kept of it; one of two appends at the same version through; streams numbered apart; the whole store read in the order of the appends, positions rising from 1, after a position and within a limit; `head()` |
456
+ | `eventStoreUnitOfWorkContract` | a transactional `EventStore` with the outbox of its database under one `UnitOfWork`: the stream and the outbox records published for its events commit together; nothing left in the outbox for an append rolled back, nor for one refused by a concurrency conflict. `createSubject()` answers `{ unitOfWork, store, outbox }` |
439
457
  | `cacheContract` | any `Cache`: round trip of every shape of value, isolation of entries, deletion, time to live |
440
458
  | `lockContract` | any `Lock`: one holder at a time also under concurrent requests, release, expiry, a late release ignored, growing fencing token, `waitMs` |
441
459
  | `jobSchedulerContract` | any `JobScheduler`: registration and description, a duplicate name and an unreadable schedule refused, `runNow` (also for a disabled job, an unknown name rejected), nothing by time before `start` or after `stop`, no overlap by default, a failing job answered `failed` with its code while the others go on, the execution context of a run |
442
460
  | `loggerContract` | any `Logger`: every level with its message and fields of every shape, level and message that no field forges, children that add their fields and nest, fields read at each entry, an entry below the level dropped without reading a field, `isLevelEnabled` answering what is written (for a child too), no throw on a circular field or a getter that throws, at the top of the fields included; an `Error` passed as a field written as its description (`type`, `code` of a `DomainError`, `message`, own `stack`, `cause`, eight errors deep at most), its message replaced when the logger scrubs unless it is a `DomainError`; every entry in the sink once `flush()` resolves, then no throw from a log call or a second flush. `createLogger({ level, fields, scrubMessages })` answers the logger and `lines()`, what its sink received as `{ level, message, fields }`. No capability flag: `InMemoryLogger` takes the same three options and passes the whole suite |
443
461
  | `criteriaContract` | any translator of criteria, the in-memory evaluator included: a table of criteria and the ids each answers, in order, over eight fixed rows. Every operator on every type it applies to, decimals as numbers, instants to the millisecond and across zones, case and the characters a `LIKE` would trip on, nulls under each operator, `and`, `or`, `not` and what a negation does to a null, sorts with ties and nulls in both directions, offset pages with their total, every sort walked by cursor one and two rows at a time, the four kinds of access scope, and hostile values. `createReadModel(rows)` answers `{ search(scopedCriteria) }` over exactly those rows, read with `criteriaContractDefinition` |
444
462
  | `readModelStoreContract` | any `ReadModelTable` under `TableReadModelStore`: rows of every type round trip, the current row handed to a later event, an event applied once, never one older than the row, order by event id at the same instant and by version when given, concurrent writes ending on the latest, deletions that last, listing by criteria and scope, and `ProjectionRebuild`: rebuilt from the source alone, no event lost while it exports (on a row already copied and on one not yet), stale and new events after the swap, deletions during and before it, a failed export leaving the table as it was, the table still itself after two rebuilds. `createTable()` answers `{ table, unitOfWork }`; `SourceOfTruth` is the fake of the source |
463
+ | `fileStorageContract` | any `FileStorage`: content round trip with size, media type and checksum, several mebibytes streamed, a write beyond `maxBytes` refused leaving the previous content, keys that could leave their place refused, deletion, copy, move, listing by prefix, signed download and upload links that expire, refuse a changed signature or another media type, and are never signed for more than an hour, a download served as an attachment even without a name. `follow` sends a request to a link: `fetch` by default, `followServed(storage)` for a storage the application serves |
445
464
  | `rateLimiterContract` | any `RateLimiter`: limit, `remaining` and `retryAfterMs`, refused calls not counted, sliding window, isolation of keys, concurrent calls |
446
465
 
447
466
  The cache, lock and rate limiter suites also take `elapse(ms)`, which makes time pass for the
@@ -0,0 +1,12 @@
1
+ import { type EventSourcingStores } from '@ddd-ts-kit/kernel';
2
+ import { ContractSuite } from '../contract-suite.js';
3
+ type Companions = Pick<EventSourcingStores, 'snapshots' | 'checkpoints' | 'subjectKeys'>;
4
+ /** The stores that come with an event store: snapshots, checkpoints of the subscriptions, keys of the data subjects. */
5
+ export declare class CompanionStoresSuite extends ContractSuite<Companions> {
6
+ protected tests(): void;
7
+ private keepsTheLatestSnapshot;
8
+ private movesCheckpointsFromWhereTheyStand;
9
+ private destroysKeys;
10
+ }
11
+ export {};
12
+ //# sourceMappingURL=companion-stores-suite.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"companion-stores-suite.d.ts","sourceRoot":"","sources":["../../../src/contracts/event-store/companion-stores-suite.ts"],"names":[],"mappings":"AAAA,OAAO,EAAwB,KAAK,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACpF,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAGrD,KAAK,UAAU,GAAG,IAAI,CAAC,mBAAmB,EAAE,WAAW,GAAG,aAAa,GAAG,aAAa,CAAC,CAAC;AAEzF,wHAAwH;AACxH,qBAAa,oBAAqB,SAAQ,aAAa,CAAC,UAAU,CAAC;IACjE,SAAS,CAAC,KAAK,IAAI,IAAI,CAItB;IAED,OAAO,CAAC,sBAAsB;IAc9B,OAAO,CAAC,kCAAkC;IA6B1C,OAAO,CAAC,YAAY;CAcrB"}
@@ -0,0 +1,60 @@
1
+ import { CONCURRENCY_CONFLICT } from '@ddd-ts-kit/kernel';
2
+ import { ContractSuite } from '../contract-suite.js';
3
+ import { failureOf } from '../failure-of.js';
4
+ /** The stores that come with an event store: snapshots, checkpoints of the subscriptions, keys of the data subjects. */
5
+ export class CompanionStoresSuite extends ContractSuite {
6
+ tests() {
7
+ this.keepsTheLatestSnapshot();
8
+ this.movesCheckpointsFromWhereTheyStand();
9
+ this.destroysKeys();
10
+ }
11
+ keepsTheLatestSnapshot() {
12
+ this.it('keeps the snapshot of a stream as saved, and never replaces it by an older one', async () => {
13
+ const { snapshots } = this.subject;
14
+ const later = { stream: 'consignment-c1', version: 6, schemaVersion: 2, data: { grams: 600, tags: ['a'] } };
15
+ await snapshots.save({ stream: 'consignment-c1', version: 3, schemaVersion: 2, data: { grams: 300 } });
16
+ await snapshots.save(later);
17
+ await snapshots.save({ stream: 'consignment-c1', version: 4, schemaVersion: 2, data: { grams: 400 } });
18
+ this.expect(await snapshots.find('consignment-c1')).toEqual(later);
19
+ this.expect(await snapshots.find('consignment-c2')).toBe(undefined);
20
+ });
21
+ }
22
+ movesCheckpointsFromWhereTheyStand() {
23
+ this.it('starts a subscriber at 0 and moves it from where it stands, refusing a move from elsewhere', async () => {
24
+ const { checkpoints } = this.subject;
25
+ this.expect(await checkpoints.position('shipping.weights')).toBe(0);
26
+ await checkpoints.advance('shipping.weights', 0, 4);
27
+ await checkpoints.advance('shipping.weights', 4, 9);
28
+ const stale = await failureOf(() => checkpoints.advance('shipping.weights', 4, 12));
29
+ const fresh = await failureOf(() => checkpoints.advance('shipping.labels', 3, 5));
30
+ this.expect([codeOf(stale), codeOf(fresh)]).toEqual([CONCURRENCY_CONFLICT, CONCURRENCY_CONFLICT]);
31
+ this.expect(await checkpoints.position('shipping.weights')).toBe(9);
32
+ this.expect(await checkpoints.position('shipping.labels')).toBe(0);
33
+ });
34
+ this.it('lets one of two runs starting from 0 move the checkpoint', async () => {
35
+ const { checkpoints } = this.subject;
36
+ const outcomes = await Promise.all([
37
+ failureOf(() => checkpoints.advance('shipping.weights', 0, 3)),
38
+ failureOf(() => checkpoints.advance('shipping.weights', 0, 3)),
39
+ ]);
40
+ this.expect(outcomes.filter((failure) => failure === undefined).length).toBe(1);
41
+ });
42
+ }
43
+ destroysKeys() {
44
+ this.it('gives a subject one key until it is erased, then a new one that the old id never finds', async () => {
45
+ const { subjectKeys } = this.subject;
46
+ const first = await subjectKeys.keyFor('patient-1');
47
+ this.expect(await subjectKeys.keyFor('patient-1')).toEqual(first);
48
+ this.expect(await subjectKeys.find(first.id)).toEqual(first);
49
+ this.expect(Buffer.from(first.material, 'base64').length).toBe(32);
50
+ this.expect(await subjectKeys.erase('patient-1')).toBe(true);
51
+ this.expect(await subjectKeys.find(first.id)).toBe(undefined);
52
+ this.expect(await subjectKeys.erase('patient-1')).toBe(false);
53
+ this.expect((await subjectKeys.keyFor('patient-1')).id === first.id).toBe(false);
54
+ });
55
+ }
56
+ }
57
+ function codeOf(failure) {
58
+ return typeof failure === 'object' && failure !== null && 'code' in failure ? failure.code : undefined;
59
+ }
60
+ //# sourceMappingURL=companion-stores-suite.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"companion-stores-suite.js","sourceRoot":"","sources":["../../../src/contracts/event-store/companion-stores-suite.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ import type { DomainEvent } from '@ddd-ts-kit/kernel';
2
+ export declare class ConsignmentRegistered implements DomainEvent {
3
+ readonly aggregateId: string;
4
+ readonly occurredAt: Date;
5
+ readonly name = "shipping.consignment.registered";
6
+ constructor(aggregateId: string, occurredAt: Date);
7
+ }
8
+ //# sourceMappingURL=consignment-registered.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"consignment-registered.d.ts","sourceRoot":"","sources":["../../../src/contracts/event-store/consignment-registered.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEtD,qBAAa,qBAAsB,YAAW,WAAW;IAIrD,QAAQ,CAAC,WAAW,EAAE,MAAM;IAC5B,QAAQ,CAAC,UAAU,EAAE,IAAI;IAJ3B,QAAQ,CAAC,IAAI,qCAAqC;IAElD,YACW,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,IAAI,EACvB;CACL"}
@@ -0,0 +1,10 @@
1
+ export class ConsignmentRegistered {
2
+ aggregateId;
3
+ occurredAt;
4
+ name = 'shipping.consignment.registered';
5
+ constructor(aggregateId, occurredAt) {
6
+ this.aggregateId = aggregateId;
7
+ this.occurredAt = occurredAt;
8
+ }
9
+ }
10
+ //# sourceMappingURL=consignment-registered.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"consignment-registered.js","sourceRoot":"","sources":["../../../src/contracts/event-store/consignment-registered.ts"],"names":[],"mappings":"AAEA,MAAM,OAAO,qBAAqB;IAIrB,WAAW;IACX,UAAU;IAJZ,IAAI,GAAG,iCAAiC,CAAC;IAElD,YACW,WAAmB,EACnB,UAAgB;2BADhB,WAAW;0BACX,UAAU;IAClB,CAAC;CACL"}
@@ -0,0 +1,9 @@
1
+ import type { DomainEvent } from '@ddd-ts-kit/kernel';
2
+ export declare class ConsignmentWeighed implements DomainEvent {
3
+ readonly aggregateId: string;
4
+ readonly occurredAt: Date;
5
+ readonly grams: number;
6
+ readonly name = "shipping.consignment.weighed";
7
+ constructor(aggregateId: string, occurredAt: Date, grams: number);
8
+ }
9
+ //# sourceMappingURL=consignment-weighed.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"consignment-weighed.d.ts","sourceRoot":"","sources":["../../../src/contracts/event-store/consignment-weighed.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEtD,qBAAa,kBAAmB,YAAW,WAAW;IAIlD,QAAQ,CAAC,WAAW,EAAE,MAAM;IAC5B,QAAQ,CAAC,UAAU,EAAE,IAAI;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM;IALxB,QAAQ,CAAC,IAAI,kCAAkC;IAE/C,YACW,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,IAAI,EAChB,KAAK,EAAE,MAAM,EACpB;CACL"}
@@ -0,0 +1,12 @@
1
+ export class ConsignmentWeighed {
2
+ aggregateId;
3
+ occurredAt;
4
+ grams;
5
+ name = 'shipping.consignment.weighed';
6
+ constructor(aggregateId, occurredAt, grams) {
7
+ this.aggregateId = aggregateId;
8
+ this.occurredAt = occurredAt;
9
+ this.grams = grams;
10
+ }
11
+ }
12
+ //# sourceMappingURL=consignment-weighed.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"consignment-weighed.js","sourceRoot":"","sources":["../../../src/contracts/event-store/consignment-weighed.ts"],"names":[],"mappings":"AAEA,MAAM,OAAO,kBAAkB;IAIlB,WAAW;IACX,UAAU;IACV,KAAK;IALP,IAAI,GAAG,8BAA8B,CAAC;IAE/C,YACW,WAAmB,EACnB,UAAgB,EAChB,KAAa;2BAFb,WAAW;0BACX,UAAU;qBACV,KAAK;IACb,CAAC;CACL"}
@@ -0,0 +1,16 @@
1
+ import { EventSourcedAggregate, type AggregateHistory, type Appliers } from '@ddd-ts-kit/kernel';
2
+ import { ConsignmentRegistered } from './consignment-registered.js';
3
+ import { ConsignmentWeighed } from './consignment-weighed.js';
4
+ export type ConsignmentEvent = ConsignmentRegistered | ConsignmentWeighed;
5
+ /** The event-sourced aggregate of the contract: born registered, weighed any number of times. */
6
+ export declare class Consignment extends EventSourcedAggregate<ConsignmentEvent> {
7
+ private grams;
8
+ private constructor();
9
+ static register(id: string): Consignment;
10
+ static rehydrate(id: string, history: AggregateHistory<ConsignmentEvent>): Consignment;
11
+ weigh(grams: number): this;
12
+ get weight(): number;
13
+ protected appliers(): Appliers<ConsignmentEvent>;
14
+ private applyWeighed;
15
+ }
16
+ //# sourceMappingURL=consignment.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"consignment.d.ts","sourceRoot":"","sources":["../../../src/contracts/event-store/consignment.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,KAAK,gBAAgB,EAAE,KAAK,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AACjG,OAAO,EAAE,qBAAqB,EAAE,MAAM,6BAA6B,CAAC;AACpE,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAE9D,MAAM,MAAM,gBAAgB,GAAG,qBAAqB,GAAG,kBAAkB,CAAC;AAI1E,iGAAiG;AACjG,qBAAa,WAAY,SAAQ,qBAAqB,CAAC,gBAAgB,CAAC;IACtE,OAAO,CAAC,KAAK,CAAK;IAElB,OAAO,eAEN;IAED,MAAM,CAAC,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,WAAW,CAMvC;IAED,MAAM,CAAC,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,gBAAgB,CAAC,gBAAgB,CAAC,GAAG,WAAW,CAErF;IAED,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAIzB;IAED,IAAI,MAAM,IAAI,MAAM,CAEnB;IAED,SAAS,CAAC,QAAQ,IAAI,QAAQ,CAAC,gBAAgB,CAAC,CAK/C;IAED,OAAO,CAAC,YAAY;CAGrB"}
@@ -0,0 +1,36 @@
1
+ import { EventSourcedAggregate } from '@ddd-ts-kit/kernel';
2
+ import { ConsignmentRegistered } from './consignment-registered.js';
3
+ import { ConsignmentWeighed } from './consignment-weighed.js';
4
+ const AT = new Date('2026-03-01T10:00:00.000Z');
5
+ /** The event-sourced aggregate of the contract: born registered, weighed any number of times. */
6
+ export class Consignment extends EventSourcedAggregate {
7
+ grams = 0;
8
+ constructor(id) {
9
+ super(id);
10
+ }
11
+ static register(id) {
12
+ const consignment = new Consignment(id);
13
+ consignment.record(new ConsignmentRegistered(id, AT));
14
+ return consignment;
15
+ }
16
+ static rehydrate(id, history) {
17
+ return new Consignment(id).replay(history);
18
+ }
19
+ weigh(grams) {
20
+ this.record(new ConsignmentWeighed(this.id, AT, grams));
21
+ return this;
22
+ }
23
+ get weight() {
24
+ return this.grams;
25
+ }
26
+ appliers() {
27
+ return {
28
+ 'shipping.consignment.registered': () => undefined,
29
+ 'shipping.consignment.weighed': (event) => this.applyWeighed(event),
30
+ };
31
+ }
32
+ applyWeighed(event) {
33
+ this.grams = event.grams;
34
+ }
35
+ }
36
+ //# sourceMappingURL=consignment.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"consignment.js","sourceRoot":"","sources":["../../../src/contracts/event-store/consignment.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAwC,MAAM,oBAAoB,CAAC;AACjG,OAAO,EAAE,qBAAqB,EAAE,MAAM,6BAA6B,CAAC;AACpE,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAI9D,MAAM,EAAE,GAAG,IAAI,IAAI,CAAC,0BAA0B,CAAC,CAAC;AAEhD,iGAAiG;AACjG,MAAM,OAAO,WAAY,SAAQ,qBAAuC;IAC9D,KAAK,GAAG,CAAC,CAAC;IAElB,YAAoB,EAAU;QAC5B,KAAK,CAAC,EAAE,CAAC,CAAC;IACZ,CAAC;IAED,MAAM,CAAC,QAAQ,CAAC,EAAU;QACxB,MAAM,WAAW,GAAG,IAAI,WAAW,CAAC,EAAE,CAAC,CAAC;QAExC,WAAW,CAAC,MAAM,CAAC,IAAI,qBAAqB,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;QAEtD,OAAO,WAAW,CAAC;IACrB,CAAC;IAED,MAAM,CAAC,SAAS,CAAC,EAAU,EAAE,OAA2C;QACtE,OAAO,IAAI,WAAW,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAC7C,CAAC;IAED,KAAK,CAAC,KAAa;QACjB,IAAI,CAAC,MAAM,CAAC,IAAI,kBAAkB,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,EAAE,KAAK,CAAC,CAAC,CAAC;QAExD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,MAAM;QACR,OAAO,IAAI,CAAC,KAAK,CAAC;IACpB,CAAC;IAES,QAAQ;QAChB,OAAO;YACL,iCAAiC,EAAE,GAAG,EAAE,CAAC,SAAS;YAClD,8BAA8B,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC;SACpE,CAAC;IACJ,CAAC;IAEO,YAAY,CAAC,KAAyB;QAC5C,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC;IAC3B,CAAC;CACF"}
@@ -0,0 +1,10 @@
1
+ import { type EventStore } from '@ddd-ts-kit/kernel';
2
+ import { Consignment } from './consignment.js';
3
+ /** The repository adapter of the contract: it delegates to `EventSourcedRepository`, and knows nothing of events. */
4
+ export declare class Consignments {
5
+ private readonly streams;
6
+ constructor(store: EventStore);
7
+ findById(id: string): Promise<Consignment | undefined>;
8
+ save(consignment: Consignment): Promise<void>;
9
+ }
10
+ //# sourceMappingURL=consignments.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"consignments.d.ts","sourceRoot":"","sources":["../../../src/contracts/event-store/consignments.ts"],"names":[],"mappings":"AAAA,OAAO,EAA8D,KAAK,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACjH,OAAO,EAAE,WAAW,EAAyB,MAAM,kBAAkB,CAAC;AAItE,qHAAqH;AACrH,qBAAa,YAAY;IACvB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAwD;IAEhF,YAAY,KAAK,EAAE,UAAU,EAmB5B;IAED,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,SAAS,CAAC,CAErD;IAED,IAAI,CAAC,WAAW,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAE5C;CACF"}
@@ -0,0 +1,34 @@
1
+ import { EventSerializer, EventSourcedRepository, defineStoredEvent } from '@ddd-ts-kit/kernel';
2
+ import { Consignment } from './consignment.js';
3
+ import { ConsignmentRegistered } from './consignment-registered.js';
4
+ import { ConsignmentWeighed } from './consignment-weighed.js';
5
+ /** The repository adapter of the contract: it delegates to `EventSourcedRepository`, and knows nothing of events. */
6
+ export class Consignments {
7
+ streams;
8
+ constructor(store) {
9
+ this.streams = new EventSourcedRepository({
10
+ store,
11
+ category: 'shipping.consignment',
12
+ serializer: new EventSerializer({
13
+ 'shipping.consignment.registered': defineStoredEvent(ConsignmentRegistered, {
14
+ version: 1,
15
+ encode: () => ({}),
16
+ decode: (_data, { aggregateId, occurredAt }) => new ConsignmentRegistered(aggregateId, occurredAt),
17
+ }),
18
+ 'shipping.consignment.weighed': defineStoredEvent(ConsignmentWeighed, {
19
+ version: 1,
20
+ encode: (event) => ({ grams: event.grams }),
21
+ decode: (data, { aggregateId, occurredAt }) => new ConsignmentWeighed(aggregateId, occurredAt, data.number('grams')),
22
+ }),
23
+ }),
24
+ rehydrate: (id, history) => Consignment.rehydrate(id, history),
25
+ });
26
+ }
27
+ findById(id) {
28
+ return this.streams.findById(id);
29
+ }
30
+ save(consignment) {
31
+ return this.streams.save(consignment);
32
+ }
33
+ }
34
+ //# sourceMappingURL=consignments.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"consignments.js","sourceRoot":"","sources":["../../../src/contracts/event-store/consignments.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,sBAAsB,EAAE,iBAAiB,EAAmB,MAAM,oBAAoB,CAAC;AACjH,OAAO,EAAE,WAAW,EAAyB,MAAM,kBAAkB,CAAC;AACtE,OAAO,EAAE,qBAAqB,EAAE,MAAM,6BAA6B,CAAC;AACpE,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAE9D,qHAAqH;AACrH,MAAM,OAAO,YAAY;IACN,OAAO,CAAwD;IAEhF,YAAY,KAAiB;QAC3B,IAAI,CAAC,OAAO,GAAG,IAAI,sBAAsB,CAAC;YACxC,KAAK;YACL,QAAQ,EAAE,sBAAsB;YAChC,UAAU,EAAE,IAAI,eAAe,CAAmB;gBAChD,iCAAiC,EAAE,iBAAiB,CAAC,qBAAqB,EAAE;oBAC1E,OAAO,EAAE,CAAC;oBACV,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC;oBAClB,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE,WAAW,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC,IAAI,qBAAqB,CAAC,WAAW,EAAE,UAAU,CAAC;iBACnG,CAAC;gBACF,8BAA8B,EAAE,iBAAiB,CAAC,kBAAkB,EAAE;oBACpE,OAAO,EAAE,CAAC;oBACV,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,CAAC;oBAC3C,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,WAAW,EAAE,UAAU,EAAE,EAAE,EAAE,CAC5C,IAAI,kBAAkB,CAAC,WAAW,EAAE,UAAU,EAAE,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;iBACxE,CAAC;aACH,CAAC;YACF,SAAS,EAAE,CAAC,EAAE,EAAE,OAAO,EAAE,EAAE,CAAC,WAAW,CAAC,SAAS,CAAC,EAAE,EAAE,OAAO,CAAC;SAC/D,CAAC,CAAC;IACL,CAAC;IAED,QAAQ,CAAC,EAAU;QACjB,OAAO,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;IACnC,CAAC;IAED,IAAI,CAAC,WAAwB;QAC3B,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IACxC,CAAC;CACF"}
@@ -0,0 +1,4 @@
1
+ import type { EventToAppend } from '@ddd-ts-kit/kernel';
2
+ /** An event to append, told apart by its id, with data that exercises the JSON round trip. */
3
+ export declare function eventOf(id: string, data?: EventToAppend['data']): EventToAppend;
4
+ //# sourceMappingURL=event-of.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-of.d.ts","sourceRoot":"","sources":["../../../src/contracts/event-store/event-of.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAIxD,8FAA8F;AAC9F,wBAAgB,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,GAAE,aAAa,CAAC,MAAM,CAAiB,GAAG,aAAa,CAS9F"}
@@ -0,0 +1,13 @@
1
+ const AT = new Date('2026-03-01T10:00:00.000Z');
2
+ /** An event to append, told apart by its id, with data that exercises the JSON round trip. */
3
+ export function eventOf(id, data = { label: id }) {
4
+ return {
5
+ id,
6
+ type: 'shipping.consignment.weighed',
7
+ schemaVersion: 1,
8
+ data,
9
+ metadata: { aggregateId: 'c1', correlationId: `corr-${id}` },
10
+ occurredAt: AT,
11
+ };
12
+ }
13
+ //# sourceMappingURL=event-of.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-of.js","sourceRoot":"","sources":["../../../src/contracts/event-store/event-of.ts"],"names":[],"mappings":"AAEA,MAAM,EAAE,GAAG,IAAI,IAAI,CAAC,0BAA0B,CAAC,CAAC;AAEhD,8FAA8F;AAC9F,MAAM,UAAU,OAAO,CAAC,EAAU,EAAE,IAAI,GAA0B,EAAE,KAAK,EAAE,EAAE,EAAE;IAC7E,OAAO;QACL,EAAE;QACF,IAAI,EAAE,8BAA8B;QACpC,aAAa,EAAE,CAAC;QAChB,IAAI;QACJ,QAAQ,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,aAAa,EAAE,QAAQ,EAAE,EAAE,EAAE;QAC5D,UAAU,EAAE,EAAE;KACf,CAAC;AACJ,CAAC"}
@@ -0,0 +1,11 @@
1
+ import type { EventStore, UnitOfWork } from '@ddd-ts-kit/kernel';
2
+ import type { Awaitable } from '../awaitable.js';
3
+ import type { OutboxStoreUnderContract } from '../outbox-store-contract.js';
4
+ /** An event store and the outbox of the same database, both bound to one unit of work, all empty. */
5
+ export interface EventStoreUnderContract {
6
+ readonly unitOfWork: UnitOfWork;
7
+ readonly store: EventStore;
8
+ readonly outbox: Pick<OutboxStoreUnderContract, 'append' | 'claimBatch' | 'stats'>;
9
+ close?(): Awaitable<void>;
10
+ }
11
+ //# sourceMappingURL=event-store-under-contract.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-store-under-contract.d.ts","sourceRoot":"","sources":["../../../src/contracts/event-store/event-store-under-contract.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACjE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,6BAA6B,CAAC;AAE5E,qGAAqG;AACrG,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC;IAChC,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;IAC3B,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAC,wBAAwB,EAAE,QAAQ,GAAG,YAAY,GAAG,OAAO,CAAC,CAAC;IACnF,KAAK,CAAC,IAAI,SAAS,CAAC,IAAI,CAAC,CAAC;CAC3B"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=event-store-under-contract.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-store-under-contract.js","sourceRoot":"","sources":["../../../src/contracts/event-store/event-store-under-contract.ts"],"names":[],"mappings":""}
@@ -0,0 +1,18 @@
1
+ import { ContractSuite } from '../contract-suite.js';
2
+ import type { EventStoreUnderContract } from './event-store-under-contract.js';
3
+ /**
4
+ * No double write: the events of an aggregate and the integration events published for them are
5
+ * written by one transaction. The store is fed by the save; the publisher, a handler of the domain
6
+ * events run before the commit, feeds the outbox: both commit, or neither does.
7
+ */
8
+ export declare class OneTransactionSuite extends ContractSuite<EventStoreUnderContract> {
9
+ protected tests(): void;
10
+ private commitsTogether;
11
+ private publishesNothingRefused;
12
+ private published;
13
+ /** The repository of the composition root: events leave with the save, and the publisher writes to the outbox before the commit. */
14
+ private publishing;
15
+ private integrationOf;
16
+ private relayed;
17
+ }
18
+ //# sourceMappingURL=one-transaction-suite.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"one-transaction-suite.d.ts","sourceRoot":"","sources":["../../../src/contracts/event-store/one-transaction-suite.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAIrD,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,iCAAiC,CAAC;AAM/E;;;;GAIG;AACH,qBAAa,mBAAoB,SAAQ,aAAa,CAAC,uBAAuB,CAAC;IAC7E,SAAS,CAAC,KAAK,IAAI,IAAI,CAOtB;IAED,OAAO,CAAC,eAAe;IA+BvB,OAAO,CAAC,uBAAuB;IAoB/B,OAAO,CAAC,SAAS,CAAK;IAEtB,oIAAoI;IACpI,OAAO,CAAC,UAAU;IAYlB,OAAO,CAAC,aAAa;YAYP,OAAO;CAKtB"}
@@ -0,0 +1,92 @@
1
+ import { InMemoryDomainEventDispatcher, dispatchingOnSave, } from '@ddd-ts-kit/kernel';
2
+ import { ContractSuite } from '../contract-suite.js';
3
+ import { failureOf } from '../failure-of.js';
4
+ import { Consignment } from './consignment.js';
5
+ import { Consignments } from './consignments.js';
6
+ const LATER = new Date('2100-01-01T00:00:00.000Z');
7
+ class TruckLost extends Error {
8
+ }
9
+ /**
10
+ * No double write: the events of an aggregate and the integration events published for them are
11
+ * written by one transaction. The store is fed by the save; the publisher, a handler of the domain
12
+ * events run before the commit, feeds the outbox: both commit, or neither does.
13
+ */
14
+ export class OneTransactionSuite extends ContractSuite {
15
+ tests() {
16
+ this.afterEach(async () => {
17
+ await this.subject.close?.();
18
+ });
19
+ this.commitsTogether();
20
+ this.publishesNothingRefused();
21
+ }
22
+ commitsTogether() {
23
+ this.it('commits the stream and the outbox records published for its events together', async () => {
24
+ const consignments = this.publishing();
25
+ await this.subject.unitOfWork.run(() => consignments.save(Consignment.register('c1').weigh(300)));
26
+ this.expect((await this.subject.store.readStream('shipping.consignment-c1')).length).toBe(2);
27
+ this.expect(await this.relayed()).toEqual([
28
+ 'shipping.consignment.registered c1',
29
+ 'shipping.consignment.weighed c1',
30
+ ]);
31
+ });
32
+ this.it('leaves nothing in the outbox for an append that was rolled back', async () => {
33
+ const consignments = this.publishing();
34
+ const failure = await failureOf(() => this.subject.unitOfWork.run(async () => {
35
+ await consignments.save(Consignment.register('c1'));
36
+ throw new TruckLost();
37
+ }));
38
+ this.expect(failure instanceof TruckLost).toBe(true);
39
+ this.expect(await this.subject.store.readStream('shipping.consignment-c1')).toEqual([]);
40
+ this.expect((await this.subject.outbox.stats()).pending).toBe(0);
41
+ this.expect(await this.relayed()).toEqual([]);
42
+ });
43
+ }
44
+ publishesNothingRefused() {
45
+ this.it('publishes nothing for an append refused by a concurrency conflict', async () => {
46
+ const consignments = this.publishing();
47
+ await this.subject.unitOfWork.run(() => consignments.save(Consignment.register('c1')));
48
+ const stale = await loaded(consignments, 'c1');
49
+ const winner = await loaded(consignments, 'c1');
50
+ await this.subject.unitOfWork.run(() => consignments.save(winner.weigh(100)));
51
+ const refused = await failureOf(() => this.subject.unitOfWork.run(() => consignments.save(stale.weigh(200))));
52
+ this.expect(refused === undefined).toBe(false);
53
+ this.expect((await this.subject.store.readStream('shipping.consignment-c1')).length).toBe(2);
54
+ this.expect((await this.relayed()).length).toBe(2);
55
+ });
56
+ }
57
+ published = 0;
58
+ /** The repository of the composition root: events leave with the save, and the publisher writes to the outbox before the commit. */
59
+ publishing() {
60
+ const dispatcher = new InMemoryDomainEventDispatcher();
61
+ const publish = async (event) => this.subject.outbox.append([this.integrationOf(event)]);
62
+ dispatcher.on('shipping.consignment.registered', publish, { phase: 'before-commit' });
63
+ dispatcher.on('shipping.consignment.weighed', publish, { phase: 'before-commit' });
64
+ return dispatchingOnSave(new Consignments(this.subject.store), () => dispatcher);
65
+ }
66
+ integrationOf(event) {
67
+ this.published += 1;
68
+ return {
69
+ id: `evt-${this.published}`,
70
+ type: event.name,
71
+ version: 1,
72
+ occurredAt: event.occurredAt.toISOString(),
73
+ payload: { consignmentId: event.aggregateId },
74
+ };
75
+ }
76
+ async relayed() {
77
+ return (await this.subject.outbox.claimBatch(100, LATER)).map(({ event }) => `${event.type} ${idOf(event.payload)}`);
78
+ }
79
+ }
80
+ async function loaded(consignments, id) {
81
+ const consignment = await consignments.findById(id);
82
+ if (consignment === undefined) {
83
+ throw new Error(`Consignment ${id} was saved and is not found`);
84
+ }
85
+ return consignment;
86
+ }
87
+ function idOf(payload) {
88
+ return typeof payload === 'object' && payload !== null && 'consignmentId' in payload
89
+ ? String(payload.consignmentId)
90
+ : '';
91
+ }
92
+ //# sourceMappingURL=one-transaction-suite.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"one-transaction-suite.js","sourceRoot":"","sources":["../../../src/contracts/event-store/one-transaction-suite.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import type { EventStore } from '@ddd-ts-kit/kernel';
2
+ import { ContractSuite } from '../contract-suite.js';
3
+ /** The whole store: read in the order of the appends, from a position, page by page, for the subscriptions. */
4
+ export declare class StoreSuite extends ContractSuite<EventStore> {
5
+ protected tests(): void;
6
+ private readsInOrder;
7
+ private givesConcurrentAppendsTheirOwnPositions;
8
+ private readsFromAPosition;
9
+ }
10
+ //# sourceMappingURL=store-suite.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store-suite.d.ts","sourceRoot":"","sources":["../../../src/contracts/event-store/store-suite.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAGrD,+GAA+G;AAC/G,qBAAa,UAAW,SAAQ,aAAa,CAAC,UAAU,CAAC;IACvD,SAAS,CAAC,KAAK,IAAI,IAAI,CAItB;IAED,OAAO,CAAC,YAAY;IAoBpB,OAAO,CAAC,uCAAuC;IAqB/C,OAAO,CAAC,kBAAkB;CAY3B"}
@@ -0,0 +1,44 @@
1
+ import { ContractSuite } from '../contract-suite.js';
2
+ import { eventOf } from './event-of.js';
3
+ /** The whole store: read in the order of the appends, from a position, page by page, for the subscriptions. */
4
+ export class StoreSuite extends ContractSuite {
5
+ tests() {
6
+ this.readsInOrder();
7
+ this.givesConcurrentAppendsTheirOwnPositions();
8
+ this.readsFromAPosition();
9
+ }
10
+ readsInOrder() {
11
+ this.it('reads every stream in the order the events were appended, positions rising from 1', async () => {
12
+ await this.subject.append('consignment-c1', 0, [eventOf('a1')]);
13
+ await this.subject.append('consignment-c2', 0, [eventOf('b1'), eventOf('b2')]);
14
+ await this.subject.append('consignment-c1', 1, [eventOf('a2')]);
15
+ const all = await this.subject.readAll(0, 10);
16
+ this.expect(all.map(({ id }) => id)).toEqual(['a1', 'b1', 'b2', 'a2']);
17
+ this.expect(all.map(({ position }) => position)).toEqual([1, 2, 3, 4]);
18
+ });
19
+ this.it('says at which position the store is: 0 when empty, then the position of the last event', async () => {
20
+ const empty = await this.subject.head();
21
+ const appended = await this.subject.append('consignment-c1', 0, [eventOf('a1'), eventOf('a2')]);
22
+ this.expect([empty, appended.position, await this.subject.head()]).toEqual([0, 2, 2]);
23
+ });
24
+ }
25
+ givesConcurrentAppendsTheirOwnPositions() {
26
+ this.it('gives concurrent appends to several streams positions of their own, without a gap, each stream in order', async () => {
27
+ await Promise.all(['c1', 'c2', 'c3', 'c4', 'c5'].map((id) => this.subject.append(`consignment-${id}`, 0, [eventOf(`${id}-a`), eventOf(`${id}-b`)])));
28
+ const all = await this.subject.readAll(0, 100);
29
+ this.expect(all.map(({ position }) => position)).toEqual([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
30
+ this.expect(all.every((event, index) => event.version === 1 || all[index - 1]?.stream === event.stream)).toBe(true);
31
+ });
32
+ }
33
+ readsFromAPosition() {
34
+ this.it('reads after a position, no more than the limit, then nothing past the last one', async () => {
35
+ await this.subject.append('consignment-c1', 0, [eventOf('a1'), eventOf('a2'), eventOf('a3'), eventOf('a4')]);
36
+ const page = await this.subject.readAll(1, 2);
37
+ const rest = await this.subject.readAll(3, 10);
38
+ this.expect(page.map(({ id }) => id)).toEqual(['a2', 'a3']);
39
+ this.expect(rest.map(({ id }) => id)).toEqual(['a4']);
40
+ this.expect(await this.subject.readAll(4, 10)).toEqual([]);
41
+ });
42
+ }
43
+ }
44
+ //# sourceMappingURL=store-suite.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store-suite.js","sourceRoot":"","sources":["../../../src/contracts/event-store/store-suite.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import { type EventStore } from '@ddd-ts-kit/kernel';
2
+ import { ContractSuite } from '../contract-suite.js';
3
+ /** One stream: appended at the version it was read at, read back in order, refused when somebody appended first. */
4
+ export declare class StreamSuite extends ContractSuite<EventStore> {
5
+ protected tests(): void;
6
+ private appendsAndReads;
7
+ private readsWhatWasAppended;
8
+ private refusesStaleVersions;
9
+ private keepsStreamsApart;
10
+ }
11
+ //# sourceMappingURL=stream-suite.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stream-suite.d.ts","sourceRoot":"","sources":["../../../src/contracts/event-store/stream-suite.ts"],"names":[],"mappings":"AAAA,OAAO,EAAwB,KAAK,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAC3E,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAIrD,oHAAoH;AACpH,qBAAa,WAAY,SAAQ,aAAa,CAAC,UAAU,CAAC;IACxD,SAAS,CAAC,KAAK,IAAI,IAAI,CAKtB;IAED,OAAO,CAAC,eAAe;IAqCvB,OAAO,CAAC,oBAAoB;IAyB5B,OAAO,CAAC,oBAAoB;IA4B5B,OAAO,CAAC,iBAAiB;CAW1B"}