@ddd-ts-kit/testing 0.9.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 (70) hide show
  1. package/README.md +18 -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.d.ts +3 -0
  51. package/dist/contracts.d.ts.map +1 -1
  52. package/dist/contracts.js +2 -0
  53. package/dist/contracts.js.map +1 -1
  54. package/dist/event-sourcing/expect-snapshot-equivalence.d.ts +14 -0
  55. package/dist/event-sourcing/expect-snapshot-equivalence.d.ts.map +1 -0
  56. package/dist/event-sourcing/expect-snapshot-equivalence.js +48 -0
  57. package/dist/event-sourcing/expect-snapshot-equivalence.js.map +1 -0
  58. package/dist/event-sourcing/given-events.d.ts +12 -0
  59. package/dist/event-sourcing/given-events.d.ts.map +1 -0
  60. package/dist/event-sourcing/given-events.js +16 -0
  61. package/dist/event-sourcing/given-events.js.map +1 -0
  62. package/dist/event-sourcing/snapshot-equivalence.d.ts +12 -0
  63. package/dist/event-sourcing/snapshot-equivalence.d.ts.map +1 -0
  64. package/dist/event-sourcing/snapshot-equivalence.js +2 -0
  65. package/dist/event-sourcing/snapshot-equivalence.js.map +1 -0
  66. package/dist/index.d.ts +3 -0
  67. package/dist/index.d.ts.map +1 -1
  68. package/dist/index.js +2 -0
  69. package/dist/index.js.map +1 -1
  70. 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,6 +452,8 @@ 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 |
@@ -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"}
@@ -0,0 +1,91 @@
1
+ import { CONCURRENCY_CONFLICT } from '@ddd-ts-kit/kernel';
2
+ import { ContractSuite } from '../contract-suite.js';
3
+ import { failureOf } from '../failure-of.js';
4
+ import { eventOf } from './event-of.js';
5
+ /** One stream: appended at the version it was read at, read back in order, refused when somebody appended first. */
6
+ export class StreamSuite extends ContractSuite {
7
+ tests() {
8
+ this.appendsAndReads();
9
+ this.readsWhatWasAppended();
10
+ this.refusesStaleVersions();
11
+ this.keepsStreamsApart();
12
+ }
13
+ appendsAndReads() {
14
+ this.it('creates a stream at version 0 and gives its events back in order, numbered from 1', async () => {
15
+ const appended = await this.subject.append('consignment-c1', 0, [eventOf('e1'), eventOf('e2')]);
16
+ const read = await this.subject.readStream('consignment-c1');
17
+ this.expect(appended.version).toBe(2);
18
+ this.expect(read.map(({ id, version, stream }) => ({ id, version, stream }))).toEqual([
19
+ { id: 'e1', version: 1, stream: 'consignment-c1' },
20
+ { id: 'e2', version: 2, stream: 'consignment-c1' },
21
+ ]);
22
+ });
23
+ this.it('gives back the type, the version of the shape, the data, the metadata and the instant as appended', async () => {
24
+ const data = {
25
+ label: 'é ✓',
26
+ weight: 12.5,
27
+ fragile: true,
28
+ none: null,
29
+ items: [{ sku: 'a' }],
30
+ nested: { depth: 2 },
31
+ };
32
+ await this.subject.append('consignment-c1', 0, [{ ...eventOf('e1', data), schemaVersion: 3 }]);
33
+ const [read] = await this.subject.readStream('consignment-c1');
34
+ this.expect(read?.type).toBe('shipping.consignment.weighed');
35
+ this.expect(read?.schemaVersion).toBe(3);
36
+ this.expect(read?.data).toEqual(data);
37
+ this.expect(read?.metadata).toEqual({ aggregateId: 'c1', correlationId: 'corr-e1' });
38
+ this.expect(read?.occurredAt.toISOString()).toBe('2026-03-01T10:00:00.000Z');
39
+ });
40
+ }
41
+ readsWhatWasAppended() {
42
+ this.it('appends to a stream at the version it has, and reads it after a version', async () => {
43
+ await this.subject.append('consignment-c1', 0, [eventOf('e1')]);
44
+ await this.subject.append('consignment-c1', 1, [eventOf('e2'), eventOf('e3')]);
45
+ const after = await this.subject.readStream('consignment-c1', 1);
46
+ this.expect(after.map(({ id, version }) => `${id}@${version}`)).toEqual(['e2@2', 'e3@3']);
47
+ });
48
+ this.it('appends nothing at the version the stream has, and refuses nothing at another one', async () => {
49
+ await this.subject.append('consignment-c1', 0, [eventOf('e1')]);
50
+ const unchanged = await this.subject.append('consignment-c1', 1, []);
51
+ const refused = await failureOf(() => this.subject.append('consignment-c1', 0, []));
52
+ this.expect(unchanged).toEqual({ version: 1, position: 1 });
53
+ this.expect(codeOf(refused)).toBe(CONCURRENCY_CONFLICT);
54
+ });
55
+ this.it('reads an unknown stream as empty', async () => {
56
+ this.expect(await this.subject.readStream('consignment-unknown')).toEqual([]);
57
+ });
58
+ }
59
+ refusesStaleVersions() {
60
+ this.it('refuses with a concurrency conflict an append at a version the stream no longer has, and keeps none of it', async () => {
61
+ await this.subject.append('consignment-c1', 0, [eventOf('e1')]);
62
+ const behind = await failureOf(() => this.subject.append('consignment-c1', 0, [eventOf('e2')]));
63
+ const ahead = await failureOf(() => this.subject.append('consignment-c1', 2, [eventOf('e3')]));
64
+ this.expect([codeOf(behind), codeOf(ahead)]).toEqual([CONCURRENCY_CONFLICT, CONCURRENCY_CONFLICT]);
65
+ this.expect((await this.subject.readStream('consignment-c1')).map(({ id }) => id)).toEqual(['e1']);
66
+ });
67
+ this.it('lets one of two appends at the same version through, and refuses the other', async () => {
68
+ await this.subject.append('consignment-c1', 0, [eventOf('e1')]);
69
+ const outcomes = await Promise.all([
70
+ failureOf(() => this.subject.append('consignment-c1', 1, [eventOf('left')])),
71
+ failureOf(() => this.subject.append('consignment-c1', 1, [eventOf('right')])),
72
+ ]);
73
+ this.expect(outcomes.filter((failure) => failure === undefined).length).toBe(1);
74
+ this.expect(outcomes.map(codeOf).filter((code) => code === CONCURRENCY_CONFLICT).length).toBe(1);
75
+ this.expect((await this.subject.readStream('consignment-c1')).length).toBe(2);
76
+ });
77
+ }
78
+ keepsStreamsApart() {
79
+ this.it('numbers each stream on its own', async () => {
80
+ await this.subject.append('consignment-c1', 0, [eventOf('a1'), eventOf('a2')]);
81
+ await this.subject.append('consignment-c2', 0, [eventOf('b1')]);
82
+ const second = await this.subject.readStream('consignment-c2');
83
+ this.expect(second.map(({ id, version }) => `${id}@${version}`)).toEqual(['b1@1']);
84
+ this.expect((await this.subject.readStream('consignment-c1')).length).toBe(2);
85
+ });
86
+ }
87
+ }
88
+ function codeOf(failure) {
89
+ return typeof failure === 'object' && failure !== null && 'code' in failure ? failure.code : undefined;
90
+ }
91
+ //# sourceMappingURL=stream-suite.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stream-suite.js","sourceRoot":"","sources":["../../../src/contracts/event-store/stream-suite.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ import type { EventSourcingStores, EventStore } from '@ddd-ts-kit/kernel';
2
+ import type { Awaitable } from './awaitable.js';
3
+ import type { ContractRunner } from './contract-runner.js';
4
+ export interface EventStoreContractOptions {
5
+ readonly name: string;
6
+ /** A fresh, empty store; called before each test. */
7
+ createStore(): Awaitable<EventStore>;
8
+ /** The snapshot, checkpoint and key stores that come with it, fresh and empty; their suite runs when given. */
9
+ readonly createCompanions?: () => Awaitable<Pick<EventSourcingStores, 'snapshots' | 'checkpoints' | 'subjectKeys'>>;
10
+ }
11
+ /**
12
+ * What every adapter of the kernel `EventStore` port guarantees, the in-memory one included:
13
+ * an append at the version the stream still has, a concurrency conflict otherwise and nothing
14
+ * kept of it, each stream in its order, the whole store in the order of the appends with a
15
+ * position, and a read from a position. With `createCompanions`, the stores that come with it:
16
+ * snapshots never replaced by an older one, checkpoints moved from where they stand, keys of data
17
+ * subjects destroyed by an erasure.
18
+ */
19
+ export declare function eventStoreContract(runner: ContractRunner, options: EventStoreContractOptions): void;
20
+ //# sourceMappingURL=event-store-contract.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-store-contract.d.ts","sourceRoot":"","sources":["../../src/contracts/event-store-contract.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAC1E,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAK3D,MAAM,WAAW,yBAAyB;IACxC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,qDAAqD;IACrD,WAAW,IAAI,SAAS,CAAC,UAAU,CAAC,CAAC;IACrC,+GAA+G;IAC/G,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,SAAS,CAAC,IAAI,CAAC,mBAAmB,EAAE,WAAW,GAAG,aAAa,GAAG,aAAa,CAAC,CAAC,CAAC;CACrH;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,cAAc,EAAE,OAAO,EAAE,yBAAyB,GAAG,IAAI,CAanG"}
@@ -0,0 +1,21 @@
1
+ import { CompanionStoresSuite } from './event-store/companion-stores-suite.js';
2
+ import { StoreSuite } from './event-store/store-suite.js';
3
+ import { StreamSuite } from './event-store/stream-suite.js';
4
+ /**
5
+ * What every adapter of the kernel `EventStore` port guarantees, the in-memory one included:
6
+ * an append at the version the stream still has, a concurrency conflict otherwise and nothing
7
+ * kept of it, each stream in its order, the whole store in the order of the appends with a
8
+ * position, and a read from a position. With `createCompanions`, the stores that come with it:
9
+ * snapshots never replaced by an older one, checkpoints moved from where they stand, keys of data
10
+ * subjects destroyed by an erasure.
11
+ */
12
+ export function eventStoreContract(runner, options) {
13
+ const create = () => options.createStore();
14
+ new StreamSuite(runner, create).describe(`${options.name} (event store contract: streams)`);
15
+ new StoreSuite(runner, create).describe(`${options.name} (event store contract: the whole store)`);
16
+ const { createCompanions } = options;
17
+ if (createCompanions !== undefined) {
18
+ new CompanionStoresSuite(runner, () => createCompanions()).describe(`${options.name} (event store contract: snapshots, checkpoints, keys)`);
19
+ }
20
+ }
21
+ //# sourceMappingURL=event-store-contract.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-store-contract.js","sourceRoot":"","sources":["../../src/contracts/event-store-contract.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,oBAAoB,EAAE,MAAM,yCAAyC,CAAC;AAC/E,OAAO,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAC1D,OAAO,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAC;AAU5D;;;;;;;GAOG;AACH,MAAM,UAAU,kBAAkB,CAAC,MAAsB,EAAE,OAAkC;IAC3F,MAAM,MAAM,GAAG,GAA0B,EAAE,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC;IAElE,IAAI,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,GAAG,OAAO,CAAC,IAAI,kCAAkC,CAAC,CAAC;IAC5F,IAAI,UAAU,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,GAAG,OAAO,CAAC,IAAI,0CAA0C,CAAC,CAAC;IAEnG,MAAM,EAAE,gBAAgB,EAAE,GAAG,OAAO,CAAC;IAErC,IAAI,gBAAgB,KAAK,SAAS,EAAE,CAAC;QACnC,IAAI,oBAAoB,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,gBAAgB,EAAE,CAAC,CAAC,QAAQ,CACjE,GAAG,OAAO,CAAC,IAAI,uDAAuD,CACvE,CAAC;IACJ,CAAC;AACH,CAAC"}
@@ -0,0 +1,15 @@
1
+ import type { Awaitable } from './awaitable.js';
2
+ import type { ContractRunner } from './contract-runner.js';
3
+ import type { EventStoreUnderContract } from './event-store/event-store-under-contract.js';
4
+ export interface EventStoreUnitOfWorkContractOptions {
5
+ readonly name: string;
6
+ /** An empty event store and an empty outbox of one database, bound to one unit of work; called before each test. */
7
+ createSubject(): Awaitable<EventStoreUnderContract>;
8
+ }
9
+ /**
10
+ * No double write for an event-sourced aggregate: what its save appends to its stream and what the
11
+ * publisher of its events writes to the outbox commit in one transaction, so nothing is published
12
+ * for an append that was rolled back or refused. Held by every transactional event store.
13
+ */
14
+ export declare function eventStoreUnitOfWorkContract(runner: ContractRunner, options: EventStoreUnitOfWorkContractOptions): void;
15
+ //# sourceMappingURL=event-store-unit-of-work-contract.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-store-unit-of-work-contract.d.ts","sourceRoot":"","sources":["../../src/contracts/event-store-unit-of-work-contract.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,6CAA6C,CAAC;AAG3F,MAAM,WAAW,mCAAmC;IAClD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,oHAAoH;IACpH,aAAa,IAAI,SAAS,CAAC,uBAAuB,CAAC,CAAC;CACrD;AAED;;;;GAIG;AACH,wBAAgB,4BAA4B,CAC1C,MAAM,EAAE,cAAc,EACtB,OAAO,EAAE,mCAAmC,GAC3C,IAAI,CAIN"}
@@ -0,0 +1,10 @@
1
+ import { OneTransactionSuite } from './event-store/one-transaction-suite.js';
2
+ /**
3
+ * No double write for an event-sourced aggregate: what its save appends to its stream and what the
4
+ * publisher of its events writes to the outbox commit in one transaction, so nothing is published
5
+ * for an append that was rolled back or refused. Held by every transactional event store.
6
+ */
7
+ export function eventStoreUnitOfWorkContract(runner, options) {
8
+ new OneTransactionSuite(runner, () => options.createSubject()).describe(`${options.name} (event store contract: one transaction with the outbox)`);
9
+ }
10
+ //# sourceMappingURL=event-store-unit-of-work-contract.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-store-unit-of-work-contract.js","sourceRoot":"","sources":["../../src/contracts/event-store-unit-of-work-contract.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,mBAAmB,EAAE,MAAM,wCAAwC,CAAC;AAQ7E;;;;GAIG;AACH,MAAM,UAAU,4BAA4B,CAC1C,MAAsB,EACtB,OAA4C;IAE5C,IAAI,mBAAmB,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,aAAa,EAAE,CAAC,CAAC,QAAQ,CACrE,GAAG,OAAO,CAAC,IAAI,0DAA0D,CAC1E,CAAC;AACJ,CAAC"}
@@ -15,6 +15,9 @@ export { followWithFetch } from './contracts/file-storage/follow-with-fetch.js';
15
15
  export type { FollowedResponse } from './contracts/file-storage/followed-response.js';
16
16
  export type { SignedRequest } from './contracts/file-storage/signed-request.js';
17
17
  export { jobSchedulerContract, type JobSchedulerContractOptions, type JobSchedulerUnderContract, } from './contracts/job-scheduler-contract.js';
18
+ export { eventStoreContract, type EventStoreContractOptions } from './contracts/event-store-contract.js';
19
+ export type { EventStoreUnderContract } from './contracts/event-store/event-store-under-contract.js';
20
+ export { eventStoreUnitOfWorkContract, type EventStoreUnitOfWorkContractOptions, } from './contracts/event-store-unit-of-work-contract.js';
18
21
  export { lockContract, type LockContractOptions } from './contracts/lock-contract.js';
19
22
  export { loggerContract, type LoggerContractOptions } from './contracts/logger-contract.js';
20
23
  export type { CreateLogger } from './contracts/logger/create-logger.js';
@@ -1 +1 @@
1
- {"version":3,"file":"contracts.d.ts","sourceRoot":"","sources":["../src/contracts.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,KAAK,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AACzF,YAAY,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AACrE,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAC9D,OAAO,EACL,gBAAgB,EAChB,KAAK,uBAAuB,EAC5B,KAAK,sBAAsB,GAC5B,MAAM,kCAAkC,CAAC;AAC1C,YAAY,EAAE,YAAY,EAAE,MAAM,uCAAuC,CAAC;AAC1E,OAAO,EAAE,0BAA0B,EAAE,MAAM,sDAAsD,CAAC;AAClG,YAAY,EAAE,mBAAmB,EAAE,MAAM,+CAA+C,CAAC;AACzF,OAAO,EAAE,oBAAoB,EAAE,MAAM,gDAAgD,CAAC;AACtF,OAAO,EACL,gBAAgB,EAChB,KAAK,uBAAuB,EAC5B,KAAK,qBAAqB,GAC3B,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EAAE,mBAAmB,EAAE,MAAM,sCAAsC,CAAC;AAC3E,YAAY,EAAE,0BAA0B,EAAE,MAAM,2DAA2D,CAAC;AAC5G,OAAO,EAAE,YAAY,EAAE,MAAM,2CAA2C,CAAC;AACzE,OAAO,EAAE,eAAe,EAAE,MAAM,+CAA+C,CAAC;AAChF,YAAY,EAAE,gBAAgB,EAAE,MAAM,+CAA+C,CAAC;AACtF,YAAY,EAAE,aAAa,EAAE,MAAM,4CAA4C,CAAC;AAChF,OAAO,EACL,oBAAoB,EACpB,KAAK,2BAA2B,EAChC,KAAK,yBAAyB,GAC/B,MAAM,uCAAuC,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,KAAK,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AACtF,OAAO,EAAE,cAAc,EAAE,KAAK,qBAAqB,EAAE,MAAM,gCAAgC,CAAC;AAC5F,YAAY,EAAE,YAAY,EAAE,MAAM,qCAAqC,CAAC;AACxE,YAAY,EAAE,UAAU,EAAE,MAAM,mCAAmC,CAAC;AACpE,YAAY,EAAE,mBAAmB,EAAE,MAAM,6CAA6C,CAAC;AACvF,YAAY,EAAE,mBAAmB,EAAE,MAAM,6CAA6C,CAAC;AACvF,OAAO,EACL,mBAAmB,EACnB,KAAK,0BAA0B,EAC/B,KAAK,wBAAwB,GAC9B,MAAM,sCAAsC,CAAC;AAC9C,OAAO,EACL,2BAA2B,EAC3B,KAAK,kCAAkC,GACxC,MAAM,+CAA+C,CAAC;AACvD,OAAO,EAAE,mBAAmB,EAAE,KAAK,0BAA0B,EAAE,MAAM,sCAAsC,CAAC;AAC5G,OAAO,EAAE,sBAAsB,EAAE,KAAK,6BAA6B,EAAE,MAAM,0CAA0C,CAAC;AACtH,YAAY,EAAE,2BAA2B,EAAE,MAAM,2DAA2D,CAAC;AAC7G,OAAO,EAAE,aAAa,EAAE,MAAM,2CAA2C,CAAC;AAC1E,OAAO,EAAE,kBAAkB,EAAE,KAAK,yBAAyB,EAAE,MAAM,oCAAoC,CAAC;AACxG,OAAO,EACL,uBAAuB,EACvB,KAAK,8BAA8B,GACpC,MAAM,0CAA0C,CAAC;AAClD,OAAO,EAAE,kBAAkB,EAAE,KAAK,yBAAyB,EAAE,MAAM,sCAAsC,CAAC;AAC1G,YAAY,EAAE,uBAAuB,EAAE,MAAM,yDAAyD,CAAC"}
1
+ {"version":3,"file":"contracts.d.ts","sourceRoot":"","sources":["../src/contracts.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,KAAK,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AACzF,YAAY,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AACrE,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAC9D,OAAO,EACL,gBAAgB,EAChB,KAAK,uBAAuB,EAC5B,KAAK,sBAAsB,GAC5B,MAAM,kCAAkC,CAAC;AAC1C,YAAY,EAAE,YAAY,EAAE,MAAM,uCAAuC,CAAC;AAC1E,OAAO,EAAE,0BAA0B,EAAE,MAAM,sDAAsD,CAAC;AAClG,YAAY,EAAE,mBAAmB,EAAE,MAAM,+CAA+C,CAAC;AACzF,OAAO,EAAE,oBAAoB,EAAE,MAAM,gDAAgD,CAAC;AACtF,OAAO,EACL,gBAAgB,EAChB,KAAK,uBAAuB,EAC5B,KAAK,qBAAqB,GAC3B,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EAAE,mBAAmB,EAAE,MAAM,sCAAsC,CAAC;AAC3E,YAAY,EAAE,0BAA0B,EAAE,MAAM,2DAA2D,CAAC;AAC5G,OAAO,EAAE,YAAY,EAAE,MAAM,2CAA2C,CAAC;AACzE,OAAO,EAAE,eAAe,EAAE,MAAM,+CAA+C,CAAC;AAChF,YAAY,EAAE,gBAAgB,EAAE,MAAM,+CAA+C,CAAC;AACtF,YAAY,EAAE,aAAa,EAAE,MAAM,4CAA4C,CAAC;AAChF,OAAO,EACL,oBAAoB,EACpB,KAAK,2BAA2B,EAChC,KAAK,yBAAyB,GAC/B,MAAM,uCAAuC,CAAC;AAC/C,OAAO,EAAE,kBAAkB,EAAE,KAAK,yBAAyB,EAAE,MAAM,qCAAqC,CAAC;AACzG,YAAY,EAAE,uBAAuB,EAAE,MAAM,uDAAuD,CAAC;AACrG,OAAO,EACL,4BAA4B,EAC5B,KAAK,mCAAmC,GACzC,MAAM,kDAAkD,CAAC;AAC1D,OAAO,EAAE,YAAY,EAAE,KAAK,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AACtF,OAAO,EAAE,cAAc,EAAE,KAAK,qBAAqB,EAAE,MAAM,gCAAgC,CAAC;AAC5F,YAAY,EAAE,YAAY,EAAE,MAAM,qCAAqC,CAAC;AACxE,YAAY,EAAE,UAAU,EAAE,MAAM,mCAAmC,CAAC;AACpE,YAAY,EAAE,mBAAmB,EAAE,MAAM,6CAA6C,CAAC;AACvF,YAAY,EAAE,mBAAmB,EAAE,MAAM,6CAA6C,CAAC;AACvF,OAAO,EACL,mBAAmB,EACnB,KAAK,0BAA0B,EAC/B,KAAK,wBAAwB,GAC9B,MAAM,sCAAsC,CAAC;AAC9C,OAAO,EACL,2BAA2B,EAC3B,KAAK,kCAAkC,GACxC,MAAM,+CAA+C,CAAC;AACvD,OAAO,EAAE,mBAAmB,EAAE,KAAK,0BAA0B,EAAE,MAAM,sCAAsC,CAAC;AAC5G,OAAO,EAAE,sBAAsB,EAAE,KAAK,6BAA6B,EAAE,MAAM,0CAA0C,CAAC;AACtH,YAAY,EAAE,2BAA2B,EAAE,MAAM,2DAA2D,CAAC;AAC7G,OAAO,EAAE,aAAa,EAAE,MAAM,2CAA2C,CAAC;AAC1E,OAAO,EAAE,kBAAkB,EAAE,KAAK,yBAAyB,EAAE,MAAM,oCAAoC,CAAC;AACxG,OAAO,EACL,uBAAuB,EACvB,KAAK,8BAA8B,GACpC,MAAM,0CAA0C,CAAC;AAClD,OAAO,EAAE,kBAAkB,EAAE,KAAK,yBAAyB,EAAE,MAAM,sCAAsC,CAAC;AAC1G,YAAY,EAAE,uBAAuB,EAAE,MAAM,yDAAyD,CAAC"}
package/dist/contracts.js CHANGED
@@ -8,6 +8,8 @@ export { fileStorageContract } from './contracts/file-storage-contract.js';
8
8
  export { followServed } from './contracts/file-storage/follow-served.js';
9
9
  export { followWithFetch } from './contracts/file-storage/follow-with-fetch.js';
10
10
  export { jobSchedulerContract, } from './contracts/job-scheduler-contract.js';
11
+ export { eventStoreContract } from './contracts/event-store-contract.js';
12
+ export { eventStoreUnitOfWorkContract, } from './contracts/event-store-unit-of-work-contract.js';
11
13
  export { lockContract } from './contracts/lock-contract.js';
12
14
  export { loggerContract } from './contracts/logger-contract.js';
13
15
  export { outboxStoreContract, } from './contracts/outbox-store-contract.js';
@@ -1 +1 @@
1
- {"version":3,"file":"contracts.js","sourceRoot":"","sources":["../src/contracts.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAA6B,MAAM,+BAA+B,CAAC;AAEzF,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAC9D,OAAO,EACL,gBAAgB,GAGjB,MAAM,kCAAkC,CAAC;AAE1C,OAAO,EAAE,0BAA0B,EAAE,MAAM,sDAAsD,CAAC;AAElG,OAAO,EAAE,oBAAoB,EAAE,MAAM,gDAAgD,CAAC;AACtF,OAAO,EACL,gBAAgB,GAGjB,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EAAE,mBAAmB,EAAE,MAAM,sCAAsC,CAAC;AAE3E,OAAO,EAAE,YAAY,EAAE,MAAM,2CAA2C,CAAC;AACzE,OAAO,EAAE,eAAe,EAAE,MAAM,+CAA+C,CAAC;AAGhF,OAAO,EACL,oBAAoB,GAGrB,MAAM,uCAAuC,CAAC;AAC/C,OAAO,EAAE,YAAY,EAA4B,MAAM,8BAA8B,CAAC;AACtF,OAAO,EAAE,cAAc,EAA8B,MAAM,gCAAgC,CAAC;AAK5F,OAAO,EACL,mBAAmB,GAGpB,MAAM,sCAAsC,CAAC;AAC9C,OAAO,EACL,2BAA2B,GAE5B,MAAM,+CAA+C,CAAC;AACvD,OAAO,EAAE,mBAAmB,EAAmC,MAAM,sCAAsC,CAAC;AAC5G,OAAO,EAAE,sBAAsB,EAAsC,MAAM,0CAA0C,CAAC;AAEtH,OAAO,EAAE,aAAa,EAAE,MAAM,2CAA2C,CAAC;AAC1E,OAAO,EAAE,kBAAkB,EAAkC,MAAM,oCAAoC,CAAC;AACxG,OAAO,EACL,uBAAuB,GAExB,MAAM,0CAA0C,CAAC;AAClD,OAAO,EAAE,kBAAkB,EAAkC,MAAM,sCAAsC,CAAC"}
1
+ {"version":3,"file":"contracts.js","sourceRoot":"","sources":["../src/contracts.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAA6B,MAAM,+BAA+B,CAAC;AAEzF,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAC9D,OAAO,EACL,gBAAgB,GAGjB,MAAM,kCAAkC,CAAC;AAE1C,OAAO,EAAE,0BAA0B,EAAE,MAAM,sDAAsD,CAAC;AAElG,OAAO,EAAE,oBAAoB,EAAE,MAAM,gDAAgD,CAAC;AACtF,OAAO,EACL,gBAAgB,GAGjB,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EAAE,mBAAmB,EAAE,MAAM,sCAAsC,CAAC;AAE3E,OAAO,EAAE,YAAY,EAAE,MAAM,2CAA2C,CAAC;AACzE,OAAO,EAAE,eAAe,EAAE,MAAM,+CAA+C,CAAC;AAGhF,OAAO,EACL,oBAAoB,GAGrB,MAAM,uCAAuC,CAAC;AAC/C,OAAO,EAAE,kBAAkB,EAAkC,MAAM,qCAAqC,CAAC;AAEzG,OAAO,EACL,4BAA4B,GAE7B,MAAM,kDAAkD,CAAC;AAC1D,OAAO,EAAE,YAAY,EAA4B,MAAM,8BAA8B,CAAC;AACtF,OAAO,EAAE,cAAc,EAA8B,MAAM,gCAAgC,CAAC;AAK5F,OAAO,EACL,mBAAmB,GAGpB,MAAM,sCAAsC,CAAC;AAC9C,OAAO,EACL,2BAA2B,GAE5B,MAAM,+CAA+C,CAAC;AACvD,OAAO,EAAE,mBAAmB,EAAmC,MAAM,sCAAsC,CAAC;AAC5G,OAAO,EAAE,sBAAsB,EAAsC,MAAM,0CAA0C,CAAC;AAEtH,OAAO,EAAE,aAAa,EAAE,MAAM,2CAA2C,CAAC;AAC1E,OAAO,EAAE,kBAAkB,EAAkC,MAAM,oCAAoC,CAAC;AACxG,OAAO,EACL,uBAAuB,GAExB,MAAM,0CAA0C,CAAC;AAClD,OAAO,EAAE,kBAAkB,EAAkC,MAAM,sCAAsC,CAAC"}
@@ -0,0 +1,14 @@
1
+ import { type DomainEvent } from '@ddd-ts-kit/kernel';
2
+ import type { SnapshotEquivalence } from './snapshot-equivalence.js';
3
+ /**
4
+ * Proves that the snapshots of an aggregate give the state a full replay gives. For every version
5
+ * of the history, the aggregate replayed up to it is encoded as its snapshot policy would store it,
6
+ * decoded, and rebuilt from that snapshot and the events after it: its state and its version must
7
+ * equal those of the aggregate replayed from the first event. Throws an AssertionError at the
8
+ * first version that differs. A personal value is read back as it was given, as a cipher would
9
+ * open it.
10
+ */
11
+ export declare function expectSnapshotEquivalence<A extends {
12
+ readonly version: number;
13
+ }, E extends DomainEvent, S>(proof: SnapshotEquivalence<A, E, S>): void;
14
+ //# sourceMappingURL=expect-snapshot-equivalence.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"expect-snapshot-equivalence.d.ts","sourceRoot":"","sources":["../../src/event-sourcing/expect-snapshot-equivalence.ts"],"names":[],"mappings":"AAEA,OAAO,EAKL,KAAK,WAAW,EAGjB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAErE;;;;;;;GAOG;AACH,wBAAgB,yBAAyB,CAAC,CAAC,SAAS;IAAE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CAAE,EAAE,CAAC,SAAS,WAAW,EAAE,CAAC,EACxG,KAAK,EAAE,mBAAmB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,GAClC,IAAI,CAiBN"}
@@ -0,0 +1,48 @@
1
+ import { AssertionError } from 'node:assert';
2
+ import { isDeepStrictEqual } from 'node:util';
3
+ import { StoredEventData, isStoredData, isStoredList, storedDataOf, } from '@ddd-ts-kit/kernel';
4
+ /**
5
+ * Proves that the snapshots of an aggregate give the state a full replay gives. For every version
6
+ * of the history, the aggregate replayed up to it is encoded as its snapshot policy would store it,
7
+ * decoded, and rebuilt from that snapshot and the events after it: its state and its version must
8
+ * equal those of the aggregate replayed from the first event. Throws an AssertionError at the
9
+ * first version that differs. A personal value is read back as it was given, as a cipher would
10
+ * open it.
11
+ */
12
+ export function expectSnapshotEquivalence(proof) {
13
+ const { events } = proof;
14
+ const id = events[0]?.aggregateId ?? '';
15
+ const replayed = proof.rehydrate(id, { events });
16
+ for (let at = 1; at <= events.length; at += 1) {
17
+ const restored = fromSnapshotAt(proof, id, at);
18
+ if (restored.version !== replayed.version || !isDeepStrictEqual(proof.state(restored), proof.state(replayed))) {
19
+ throw new AssertionError({
20
+ message: `Rebuilt from a snapshot taken after event ${at} of ${events.length}, the aggregate differs from its full replay.`,
21
+ actual: { version: restored.version, state: proof.state(restored) },
22
+ expected: { version: replayed.version, state: proof.state(replayed) },
23
+ operator: 'expectSnapshotEquivalence',
24
+ });
25
+ }
26
+ }
27
+ }
28
+ function fromSnapshotAt(proof, id, at) {
29
+ const { events, policy } = proof;
30
+ const kept = opened(storedDataOf(policy.encode(proof.rehydrate(id, { events: events.slice(0, at) }))));
31
+ const state = policy.decode(new StoredEventData(kept, `the snapshot after event ${at}`));
32
+ return proof.rehydrate(id, { snapshot: { version: at, state }, events: events.slice(at) });
33
+ }
34
+ /** The data as a store would give it back: a copy, each personal value in place of its marker. */
35
+ function opened(data) {
36
+ return Object.fromEntries(Object.entries(data).map(([key, value]) => [key, openedValue(value)]));
37
+ }
38
+ function openedValue(value) {
39
+ if (isStoredList(value)) {
40
+ return value.map(openedValue);
41
+ }
42
+ if (!isStoredData(value)) {
43
+ return value;
44
+ }
45
+ const personal = value['$personal'];
46
+ return isStoredData(personal) && typeof personal['value'] === 'string' ? personal['value'] : opened(value);
47
+ }
48
+ //# sourceMappingURL=expect-snapshot-equivalence.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"expect-snapshot-equivalence.js","sourceRoot":"","sources":["../../src/event-sourcing/expect-snapshot-equivalence.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,EACL,eAAe,EACf,YAAY,EACZ,YAAY,EACZ,YAAY,GAIb,MAAM,oBAAoB,CAAC;AAG5B;;;;;;;GAOG;AACH,MAAM,UAAU,yBAAyB,CACvC,KAAmC;IAEnC,MAAM,EAAE,MAAM,EAAE,GAAG,KAAK,CAAC;IACzB,MAAM,EAAE,GAAG,MAAM,CAAC,CAAC,CAAC,EAAE,WAAW,IAAI,EAAE,CAAC;IACxC,MAAM,QAAQ,GAAG,KAAK,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;IAEjD,KAAK,IAAI,EAAE,GAAG,CAAC,EAAE,EAAE,IAAI,MAAM,CAAC,MAAM,EAAE,EAAE,IAAI,CAAC,EAAE,CAAC;QAC9C,MAAM,QAAQ,GAAG,cAAc,CAAC,KAAK,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;QAE/C,IAAI,QAAQ,CAAC,OAAO,KAAK,QAAQ,CAAC,OAAO,IAAI,CAAC,iBAAiB,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC;YAC9G,MAAM,IAAI,cAAc,CAAC;gBACvB,OAAO,EAAE,6CAA6C,EAAE,OAAO,MAAM,CAAC,MAAM,+CAA+C;gBAC3H,MAAM,EAAE,EAAE,OAAO,EAAE,QAAQ,CAAC,OAAO,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE;gBACnE,QAAQ,EAAE,EAAE,OAAO,EAAE,QAAQ,CAAC,OAAO,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE;gBACrE,QAAQ,EAAE,2BAA2B;aACtC,CAAC,CAAC;QACL,CAAC;IACH,CAAC;AACH,CAAC;AAED,SAAS,cAAc,CACrB,KAAmC,EACnC,EAAU,EACV,EAAU;IAEV,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,KAAK,CAAC;IACjC,MAAM,IAAI,GAAG,MAAM,CAAC,YAAY,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IACvG,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,eAAe,CAAC,IAAI,EAAE,4BAA4B,EAAE,EAAE,CAAC,CAAC,CAAC;IAEzF,OAAO,KAAK,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;AAC7F,CAAC;AAED,kGAAkG;AAClG,SAAS,MAAM,CAAC,IAAgB;IAC9B,OAAO,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,EAAE,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AACnG,CAAC;AAED,SAAS,WAAW,CAAC,KAAiB;IACpC,IAAI,YAAY,CAAC,KAAK,CAAC,EAAE,CAAC;QACxB,OAAO,KAAK,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;IAChC,CAAC;IAED,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,QAAQ,GAAG,KAAK,CAAC,WAAW,CAAC,CAAC;IAEpC,OAAO,YAAY,CAAC,QAAQ,CAAC,IAAI,OAAO,QAAQ,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAC7G,CAAC"}
@@ -0,0 +1,12 @@
1
+ import type { AggregateHistory, DomainEvent } from '@ddd-ts-kit/kernel';
2
+ import type { EventSource } from '../scenarios/event-source.js';
3
+ import { type Scenario } from '../scenarios/scenario.js';
4
+ /**
5
+ * Starts a scenario of an event-sourced aggregate from its history, without a database: the
6
+ * aggregate is rebuilt by replaying `events` through `rehydrate`, then `when` runs one command and
7
+ * `thenEvents` asserts what it recorded.
8
+ * `givenEvents((id, history) => Invoice.rehydrate(id, history), [issued]).when((invoice) => invoice.pay(now)).thenEvents([InvoicePaid])`.
9
+ * The id is the one the events carry; give it for an empty history.
10
+ */
11
+ export declare function givenEvents<A extends EventSource, E extends DomainEvent>(rehydrate: (id: string, history: AggregateHistory<E>) => A, events: readonly E[], id?: string): Scenario<A>;
12
+ //# sourceMappingURL=given-events.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"given-events.d.ts","sourceRoot":"","sources":["../../src/event-sourcing/given-events.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACxE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAChE,OAAO,EAAY,KAAK,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AAEnE;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,CAAC,SAAS,WAAW,EAAE,CAAC,SAAS,WAAW,EACtE,SAAS,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,gBAAgB,CAAC,CAAC,CAAC,KAAK,CAAC,EAC1D,MAAM,EAAE,SAAS,CAAC,EAAE,EACpB,EAAE,CAAC,EAAE,MAAM,GACV,QAAQ,CAAC,CAAC,CAAC,CAQb"}
@@ -0,0 +1,16 @@
1
+ import { scenario } from '../scenarios/scenario.js';
2
+ /**
3
+ * Starts a scenario of an event-sourced aggregate from its history, without a database: the
4
+ * aggregate is rebuilt by replaying `events` through `rehydrate`, then `when` runs one command and
5
+ * `thenEvents` asserts what it recorded.
6
+ * `givenEvents((id, history) => Invoice.rehydrate(id, history), [issued]).when((invoice) => invoice.pay(now)).thenEvents([InvoicePaid])`.
7
+ * The id is the one the events carry; give it for an empty history.
8
+ */
9
+ export function givenEvents(rehydrate, events, id) {
10
+ const identity = id ?? events[0]?.aggregateId;
11
+ if (identity === undefined) {
12
+ throw new TypeError('givenEvents needs the id of the aggregate when the history is empty');
13
+ }
14
+ return scenario(() => rehydrate(identity, { events }));
15
+ }
16
+ //# sourceMappingURL=given-events.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"given-events.js","sourceRoot":"","sources":["../../src/event-sourcing/given-events.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,QAAQ,EAAiB,MAAM,0BAA0B,CAAC;AAEnE;;;;;;GAMG;AACH,MAAM,UAAU,WAAW,CACzB,SAA0D,EAC1D,MAAoB,EACpB,EAAW;IAEX,MAAM,QAAQ,GAAG,EAAE,IAAI,MAAM,CAAC,CAAC,CAAC,EAAE,WAAW,CAAC;IAE9C,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC3B,MAAM,IAAI,SAAS,CAAC,qEAAqE,CAAC,CAAC;IAC7F,CAAC;IAED,OAAO,QAAQ,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,QAAQ,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC;AACzD,CAAC"}
@@ -0,0 +1,12 @@
1
+ import type { AggregateHistory, DomainEvent, SnapshotPolicy } from '@ddd-ts-kit/kernel';
2
+ /** What `expectSnapshotEquivalence` replays, both ways. */
3
+ export interface SnapshotEquivalence<A, E extends DomainEvent, S> {
4
+ /** A history long enough to cross the snapshot interval, in order. */
5
+ readonly events: readonly E[];
6
+ rehydrate(id: string, history: AggregateHistory<E, S>): A;
7
+ /** The snapshot policy of the repository: its `encode` and `decode` are what is proven. */
8
+ readonly policy: Pick<SnapshotPolicy<A, S>, 'encode' | 'decode'>;
9
+ /** What two aggregates must share: their state as a value. */
10
+ state(aggregate: A): unknown;
11
+ }
12
+ //# sourceMappingURL=snapshot-equivalence.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"snapshot-equivalence.d.ts","sourceRoot":"","sources":["../../src/event-sourcing/snapshot-equivalence.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAExF,2DAA2D;AAC3D,MAAM,WAAW,mBAAmB,CAAC,CAAC,EAAE,CAAC,SAAS,WAAW,EAAE,CAAC;IAC9D,sEAAsE;IACtE,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC,EAAE,CAAC;IAC9B,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,gBAAgB,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC;IAC1D,2FAA2F;IAC3F,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAC,cAAc,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAC,CAAC;IACjE,8DAA8D;IAC9D,KAAK,CAAC,SAAS,EAAE,CAAC,GAAG,OAAO,CAAC;CAC9B"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=snapshot-equivalence.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"snapshot-equivalence.js","sourceRoot":"","sources":["../../src/event-sourcing/snapshot-equivalence.ts"],"names":[],"mappings":""}
package/dist/index.d.ts CHANGED
@@ -15,6 +15,9 @@ export { scoped } from './execution/scoped.js';
15
15
  export { asTenant } from './execution/as-tenant.js';
16
16
  export { SessionBuilder } from './execution/session-builder.js';
17
17
  export { createTestBuses, type TestBuses, type TestBusesOptions } from './harness/create-test-buses.js';
18
+ export { expectSnapshotEquivalence } from './event-sourcing/expect-snapshot-equivalence.js';
19
+ export { givenEvents } from './event-sourcing/given-events.js';
20
+ export type { SnapshotEquivalence } from './event-sourcing/snapshot-equivalence.js';
18
21
  export { expectRefusal } from './refusals/expect-refusal.js';
19
22
  export type { ExpectedFacts } from './refusals/expected-facts.js';
20
23
  export { InMemoryRepository, type InMemoryRepositoryOptions } from './repositories/in-memory-repository.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC5E,YAAY,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AACzD,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAChD,YAAY,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAC7D,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAC/D,OAAO,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAC;AAC1C,YAAY,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAC3D,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AACpD,OAAO,EAAE,kBAAkB,EAAE,MAAM,qCAAqC,CAAC;AACzE,OAAO,EAAE,uBAAuB,EAAE,MAAM,0CAA0C,CAAC;AACnF,OAAO,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAC/C,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAChE,OAAO,EAAE,eAAe,EAAE,KAAK,SAAS,EAAE,KAAK,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AACxG,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAC7D,YAAY,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAClE,OAAO,EAAE,kBAAkB,EAAE,KAAK,yBAAyB,EAAE,MAAM,wCAAwC,CAAC;AAC5G,OAAO,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AACxD,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAC/D,YAAY,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AACjE,YAAY,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AACnE,YAAY,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AACjE,YAAY,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAC/D,OAAO,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAC7C,YAAY,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACtD,OAAO,EAAE,QAAQ,EAAE,KAAK,QAAQ,EAAE,MAAM,yBAAyB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC5E,YAAY,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AACzD,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAChD,YAAY,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAC7D,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAC/D,OAAO,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAC;AAC1C,YAAY,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAC3D,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AACpD,OAAO,EAAE,kBAAkB,EAAE,MAAM,qCAAqC,CAAC;AACzE,OAAO,EAAE,uBAAuB,EAAE,MAAM,0CAA0C,CAAC;AACnF,OAAO,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAC/C,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAChE,OAAO,EAAE,eAAe,EAAE,KAAK,SAAS,EAAE,KAAK,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AACxG,OAAO,EAAE,yBAAyB,EAAE,MAAM,iDAAiD,CAAC;AAC5F,OAAO,EAAE,WAAW,EAAE,MAAM,kCAAkC,CAAC;AAC/D,YAAY,EAAE,mBAAmB,EAAE,MAAM,0CAA0C,CAAC;AACpF,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAC7D,YAAY,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAClE,OAAO,EAAE,kBAAkB,EAAE,KAAK,yBAAyB,EAAE,MAAM,wCAAwC,CAAC;AAC5G,OAAO,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AACxD,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAC/D,YAAY,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AACjE,YAAY,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AACnE,YAAY,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AACjE,YAAY,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAC/D,OAAO,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAC7C,YAAY,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACtD,OAAO,EAAE,QAAQ,EAAE,KAAK,QAAQ,EAAE,MAAM,yBAAyB,CAAC"}
package/dist/index.js CHANGED
@@ -12,6 +12,8 @@ export { scoped } from './execution/scoped.js';
12
12
  export { asTenant } from './execution/as-tenant.js';
13
13
  export { SessionBuilder } from './execution/session-builder.js';
14
14
  export { createTestBuses } from './harness/create-test-buses.js';
15
+ export { expectSnapshotEquivalence } from './event-sourcing/expect-snapshot-equivalence.js';
16
+ export { givenEvents } from './event-sourcing/given-events.js';
15
17
  export { expectRefusal } from './refusals/expect-refusal.js';
16
18
  export { InMemoryRepository } from './repositories/in-memory-repository.js';
17
19
  export { snapshots } from './repositories/snapshots.js';
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAE5E,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAEhD,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAC7D,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAC/D,OAAO,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAC;AAE1C,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AACpD,OAAO,EAAE,kBAAkB,EAAE,MAAM,qCAAqC,CAAC;AACzE,OAAO,EAAE,uBAAuB,EAAE,MAAM,0CAA0C,CAAC;AACnF,OAAO,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAC/C,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAChE,OAAO,EAAE,eAAe,EAAyC,MAAM,gCAAgC,CAAC;AACxG,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAE7D,OAAO,EAAE,kBAAkB,EAAkC,MAAM,wCAAwC,CAAC;AAC5G,OAAO,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AACxD,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAK/D,OAAO,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAE7C,OAAO,EAAE,QAAQ,EAAiB,MAAM,yBAAyB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAE5E,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAEhD,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAC7D,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAC/D,OAAO,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAC;AAE1C,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AACpD,OAAO,EAAE,kBAAkB,EAAE,MAAM,qCAAqC,CAAC;AACzE,OAAO,EAAE,uBAAuB,EAAE,MAAM,0CAA0C,CAAC;AACnF,OAAO,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAC/C,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAChE,OAAO,EAAE,eAAe,EAAyC,MAAM,gCAAgC,CAAC;AACxG,OAAO,EAAE,yBAAyB,EAAE,MAAM,iDAAiD,CAAC;AAC5F,OAAO,EAAE,WAAW,EAAE,MAAM,kCAAkC,CAAC;AAE/D,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAE7D,OAAO,EAAE,kBAAkB,EAAkC,MAAM,wCAAwC,CAAC;AAC5G,OAAO,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AACxD,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAK/D,OAAO,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAE7C,OAAO,EAAE,QAAQ,EAAiB,MAAM,yBAAyB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ddd-ts-kit/testing",
3
- "version": "0.9.0",
3
+ "version": "0.10.0",
4
4
  "description": "Readable tests without mocks: test data builders, given/when/then scenarios and contract suites shared by fakes and real adapters.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -46,11 +46,11 @@
46
46
  "dist"
47
47
  ],
48
48
  "dependencies": {
49
- "@ddd-ts-kit/kernel": "0.9.0"
49
+ "@ddd-ts-kit/kernel": "0.10.0"
50
50
  },
51
51
  "devDependencies": {
52
- "@ddd-ts-kit/aspects": "0.9.0",
53
- "@ddd-ts-kit/events": "0.9.0",
52
+ "@ddd-ts-kit/aspects": "0.10.0",
53
+ "@ddd-ts-kit/events": "0.10.0",
54
54
  "@faker-js/faker": "^10.6.0"
55
55
  },
56
56
  "peerDependencies": {