@shirudo/ddd-kit 3.0.0-rc.12 → 3.0.0-rc.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -8
- package/dist/chunks/kit-errors.d.ts +30 -31
- package/dist/chunks/kit-errors.js +56 -57
- package/dist/chunks/kit-errors.js.map +1 -1
- package/dist/chunks/read-stream-pages.js +142 -1368
- package/dist/chunks/read-stream-pages.js.map +1 -1
- package/dist/chunks/snapshot-store.d.ts +150 -146
- package/dist/chunks/value-object.js +1275 -0
- package/dist/chunks/value-object.js.map +1 -0
- package/dist/index.d.ts +133 -413
- package/dist/index.js +252 -897
- package/dist/index.js.map +1 -1
- package/dist/money.d.ts +3 -3
- package/dist/money.js +3 -3
- package/dist/money.js.map +1 -1
- package/dist/state-machine.d.ts +227 -0
- package/dist/state-machine.js +673 -0
- package/dist/state-machine.js.map +1 -0
- package/dist/testing.d.ts +4 -4
- package/dist/testing.js +47 -20
- package/dist/testing.js.map +1 -1
- package/package.json +5 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { f as DomainError,
|
|
1
|
+
import { f as DomainError, st as ReplayRejectedError } from "./kit-errors.js";
|
|
2
2
|
import { Result } from "@shirudo/result";
|
|
3
3
|
//#region src/internal/json-value.d.ts
|
|
4
4
|
/** A primitive value represented without loss by JSON. */
|
|
@@ -193,15 +193,16 @@ type ClockFactory = () => Date;
|
|
|
193
193
|
/**
|
|
194
194
|
* Factory function producing a fresh, unique event identifier for each call.
|
|
195
195
|
*
|
|
196
|
-
* The library ships a default that
|
|
197
|
-
* (works on Node 19+, modern browsers in secure
|
|
198
|
-
* Cloudflare Workers, Vercel Edge, and any runtime that
|
|
199
|
-
* Crypto).
|
|
200
|
-
*
|
|
201
|
-
*
|
|
202
|
-
*
|
|
203
|
-
*
|
|
204
|
-
* KSUID, or another collision-safe format without mutating module
|
|
196
|
+
* The library ships a default that creates a time-ordered **UUID v7** from
|
|
197
|
+
* Web Crypto random bits (works on Node 19+, modern browsers in secure
|
|
198
|
+
* contexts, Deno, Bun, Cloudflare Workers, Vercel Edge, and any runtime that
|
|
199
|
+
* implements Web Crypto). A B-tree index on the eventId column stays
|
|
200
|
+
* clustered. The id is no ordering authority: ids from several processes
|
|
201
|
+
* interleave within one millisecond, and clock skew can invert them. Order
|
|
202
|
+
* events by aggregate version or stream position. Supply another generator
|
|
203
|
+
* to {@link createDomainEventFactory} to
|
|
204
|
+
* use ULID, KSUID, or another collision-safe format without mutating module
|
|
205
|
+
* state.
|
|
205
206
|
*/
|
|
206
207
|
type EventIdFactory = () => string;
|
|
207
208
|
/**
|
|
@@ -250,7 +251,7 @@ interface EventMetadata {
|
|
|
250
251
|
* Events are immutable and carry information about what occurred.
|
|
251
252
|
*
|
|
252
253
|
* **Events are PLAIN DATA objects**, constructed via `createDomainEvent`
|
|
253
|
-
* (or the aggregate's `createEvent` plus application-shell
|
|
254
|
+
* (or the aggregate's `createEvent` plus application-shell stamping)
|
|
254
255
|
* and deeply frozen. Class-based
|
|
255
256
|
* event objects that satisfy this shape structurally via prototype
|
|
256
257
|
* members are unsupported.
|
|
@@ -266,8 +267,8 @@ interface DomainEvent<T extends string, P = void> {
|
|
|
266
267
|
/**
|
|
267
268
|
* Unique identifier for this specific event instance. Used by idempotent
|
|
268
269
|
* consumers, outbox dispatch tracking, and as the target of
|
|
269
|
-
* `metadata.causationId`. Convenience constructors default to
|
|
270
|
-
*
|
|
270
|
+
* `metadata.causationId`. Convenience constructors default to a UUID v7;
|
|
271
|
+
* strict construction requires the caller to supply it.
|
|
271
272
|
*/
|
|
272
273
|
readonly eventId: string;
|
|
273
274
|
/**
|
|
@@ -291,7 +292,7 @@ interface DomainEvent<T extends string, P = void> {
|
|
|
291
292
|
*/
|
|
292
293
|
readonly payload: P;
|
|
293
294
|
/**
|
|
294
|
-
* Timestamp when the
|
|
295
|
+
* Timestamp when the application shell stamped the accepted fact.
|
|
295
296
|
* Put business-relevant time in the payload under a domain name.
|
|
296
297
|
*/
|
|
297
298
|
readonly occurredAt: Date;
|
|
@@ -321,29 +322,29 @@ interface DomainEvent<T extends string, P = void> {
|
|
|
321
322
|
*/
|
|
322
323
|
type AnyDomainEvent = DomainEvent<string, unknown>;
|
|
323
324
|
/**
|
|
324
|
-
* A domain event accepted by an aggregate but not yet given its
|
|
325
|
-
*
|
|
325
|
+
* A domain event accepted by an aggregate but not yet given its event id,
|
|
326
|
+
* stamp time, or delivery metadata.
|
|
326
327
|
*
|
|
327
328
|
* The aggregate owns the event type, payload, source aggregate identity,
|
|
328
329
|
* and payload schema version because those values describe the business
|
|
329
330
|
* fact it produced.
|
|
330
331
|
* The application shell later turns this value into a {@link DomainEvent}.
|
|
331
332
|
*/
|
|
332
|
-
interface
|
|
333
|
+
interface UnstampedDomainEvent<T extends string, P = void> {
|
|
333
334
|
readonly type: T;
|
|
334
335
|
readonly aggregateId?: string;
|
|
335
336
|
readonly aggregateType?: string;
|
|
336
337
|
readonly payload: P;
|
|
337
338
|
readonly schemaVersion: number;
|
|
338
339
|
}
|
|
339
|
-
/** Upper-bound alias for any
|
|
340
|
-
type
|
|
341
|
-
/** Derives the
|
|
342
|
-
type
|
|
343
|
-
/** An aggregate may hold unstamped decisions and already
|
|
344
|
-
type PendingDomainEvent<TEvent extends AnyDomainEvent> = TEvent |
|
|
345
|
-
/** Producer-owned options for an
|
|
346
|
-
interface
|
|
340
|
+
/** Upper-bound alias for any unstamped domain-event shape. */
|
|
341
|
+
type AnyUnstampedDomainEvent = UnstampedDomainEvent<string, unknown>;
|
|
342
|
+
/** Derives the unstamped shape represented by a concrete event or event union. */
|
|
343
|
+
type UnstampedDomainEventOf<TEvent extends AnyDomainEvent> = TEvent extends DomainEvent<infer TType, infer TPayload> ? UnstampedDomainEvent<TType, TPayload> : never;
|
|
344
|
+
/** An aggregate may hold unstamped decisions and already stamped events together. */
|
|
345
|
+
type PendingDomainEvent<TEvent extends AnyDomainEvent> = TEvent | UnstampedDomainEventOf<TEvent>;
|
|
346
|
+
/** Producer-owned options for an unstamped event. */
|
|
347
|
+
interface CreateUnstampedDomainEventOptions {
|
|
347
348
|
readonly aggregateId?: string;
|
|
348
349
|
readonly aggregateType?: string;
|
|
349
350
|
readonly schemaVersion?: number;
|
|
@@ -355,7 +356,7 @@ interface CreateDomainEventOptions {
|
|
|
355
356
|
/**
|
|
356
357
|
* Override for the auto-generated `eventId`. Pass an existing id (for
|
|
357
358
|
* replay, tests, or deterministic event sourcing) instead of letting the
|
|
358
|
-
* factory
|
|
359
|
+
* factory generate a UUID v7.
|
|
359
360
|
*/
|
|
360
361
|
eventId?: string;
|
|
361
362
|
/**
|
|
@@ -379,7 +380,7 @@ interface CreateDomainEventOptions {
|
|
|
379
380
|
*/
|
|
380
381
|
metadata?: EventMetadata;
|
|
381
382
|
}
|
|
382
|
-
/** Technical
|
|
383
|
+
/** Technical stamp data attached by the application shell. */
|
|
383
384
|
interface DomainEventStamp {
|
|
384
385
|
/** Stable identity for this event instance. */
|
|
385
386
|
readonly eventId: string;
|
|
@@ -389,7 +390,7 @@ interface DomainEventStamp {
|
|
|
389
390
|
readonly metadata?: EventMetadata;
|
|
390
391
|
}
|
|
391
392
|
/** Full strict-construction options, including producer-owned event fields. */
|
|
392
|
-
interface
|
|
393
|
+
interface CreateStampedDomainEventOptions extends DomainEventStamp {
|
|
393
394
|
readonly aggregateId?: string;
|
|
394
395
|
readonly aggregateType?: string;
|
|
395
396
|
readonly schemaVersion?: number;
|
|
@@ -402,16 +403,16 @@ interface CreateDomainEventStampOptions {
|
|
|
402
403
|
}
|
|
403
404
|
/** Dependencies captured by one immutable domain-event factory instance. */
|
|
404
405
|
interface DomainEventFactoryOptions {
|
|
405
|
-
/** Event-id generator. Defaults to Web Crypto
|
|
406
|
+
/** Event-id generator. Defaults to a UUID v7 from Web Crypto random bits. */
|
|
406
407
|
readonly eventIdFactory?: EventIdFactory;
|
|
407
408
|
/** Event-recording clock. Defaults to `() => new Date()`. */
|
|
408
409
|
readonly clock?: ClockFactory;
|
|
409
410
|
/**
|
|
410
|
-
* Origin stamped on every event this factory
|
|
411
|
+
* Origin stamped on every event this factory builds, unless the call site
|
|
411
412
|
* names one itself.
|
|
412
413
|
*
|
|
413
414
|
* A plain value, not a factory like the two above. Those produce a new
|
|
414
|
-
* value for each event. An origin identifies the system that
|
|
415
|
+
* value for each event. An origin identifies the system that builds them
|
|
415
416
|
* and does not change between two of them.
|
|
416
417
|
*/
|
|
417
418
|
readonly source?: string;
|
|
@@ -423,7 +424,7 @@ interface DomainEventFactoryOptions {
|
|
|
423
424
|
*/
|
|
424
425
|
interface DomainEventFactory {
|
|
425
426
|
/**
|
|
426
|
-
* Creates immutable technical
|
|
427
|
+
* Creates immutable technical stamp data in the application shell.
|
|
427
428
|
*/
|
|
428
429
|
readonly createStamp: (options?: CreateDomainEventStampOptions) => DomainEventStamp;
|
|
429
430
|
readonly create: {
|
|
@@ -442,7 +443,7 @@ interface DomainEventFactory {
|
|
|
442
443
|
* The supplied functions are read once and captured by value. The returned
|
|
443
444
|
* object is frozen, so another request, test, or library cannot replace its
|
|
444
445
|
* policy. Its {@link DomainEventFactory.createStamp} method is the
|
|
445
|
-
* application-shell bridge that
|
|
446
|
+
* application-shell bridge that stamps an accepted aggregate decision.
|
|
446
447
|
* Passing the factory through `AggregateConfig`
|
|
447
448
|
* enables the explicitly named convenience methods, whose defaults read time
|
|
448
449
|
* and randomness.
|
|
@@ -453,8 +454,7 @@ interface DomainEventFactory {
|
|
|
453
454
|
* eventIdFactory: () => uuidv7(),
|
|
454
455
|
* clock: () => new Date(),
|
|
455
456
|
* });
|
|
456
|
-
*
|
|
457
|
-
* recordPendingEvents(order, domainEvents);
|
|
457
|
+
* const uow = new UnitOfWork({ ...deps, eventStampFactory: domainEvents });
|
|
458
458
|
* ```
|
|
459
459
|
*/
|
|
460
460
|
declare function createDomainEventFactory(options?: DomainEventFactoryOptions): DomainEventFactory;
|
|
@@ -464,21 +464,6 @@ declare function createDomainEventFactory(options?: DomainEventFactoryOptions):
|
|
|
464
464
|
* with {@link createDomainEventFactory} for custom policy.
|
|
465
465
|
*/
|
|
466
466
|
declare const defaultDomainEventFactory: DomainEventFactory;
|
|
467
|
-
/**
|
|
468
|
-
* Creates an uncommitted domain event: the event that an aggregate method
|
|
469
|
-
* returns before the application shell records it. The payload and the
|
|
470
|
-
* metadata follow the input ownership rule of {@link createDomainEvent}.
|
|
471
|
-
*/
|
|
472
|
-
declare function createUncommittedDomainEvent<T extends string>(type: T, payload?: undefined, options?: CreateUncommittedDomainEventOptions): UncommittedDomainEvent<T, void>;
|
|
473
|
-
declare function createUncommittedDomainEvent<T extends string, P>(type: T, payload: P, options?: CreateUncommittedDomainEventOptions): UncommittedDomainEvent<T, P>;
|
|
474
|
-
/**
|
|
475
|
-
* Attaches shell-owned recording data to an accepted aggregate decision.
|
|
476
|
-
*
|
|
477
|
-
* The decision supplies the domain type, payload, source aggregate
|
|
478
|
-
* identity, and payload schema version. The stamp supplies only event
|
|
479
|
-
* identity, recording time, and trace metadata.
|
|
480
|
-
*/
|
|
481
|
-
declare function recordDomainEvent<T extends string, P>(event: UncommittedDomainEvent<T, P>, stamp: DomainEventStamp): DomainEvent<T, P>;
|
|
482
467
|
/**
|
|
483
468
|
* Creates a domain event with default values.
|
|
484
469
|
* Sets occurredAt to current date and schemaVersion to 1 if not provided.
|
|
@@ -486,7 +471,7 @@ declare function recordDomainEvent<T extends string, P>(event: UncommittedDomain
|
|
|
486
471
|
* **Input ownership.** The event is deeply frozen, and `payload` and
|
|
487
472
|
* `metadata` are deep-cloned first, so the caller's own objects are never
|
|
488
473
|
* frozen in place and later mutation of them does not bleed into the event
|
|
489
|
-
* (same contract as `
|
|
474
|
+
* (same contract as `valueObject()`). The event data rule checks the data before the
|
|
490
475
|
* copy and the copy after it. So the copy loses no data without an error,
|
|
491
476
|
* and no getter of the data runs. The in-memory event store applies the
|
|
492
477
|
* same rule on append. The checks catch accidents, not a hostile `Proxy`: a
|
|
@@ -510,8 +495,8 @@ declare function recordDomainEvent<T extends string, P>(event: UncommittedDomain
|
|
|
510
495
|
* route by. The commit boundary validates that both fields are present
|
|
511
496
|
* and throws if they are missing, so a direct `createDomainEvent(...)`
|
|
512
497
|
* call inside an aggregate that forgets the options is caught at
|
|
513
|
-
* runtime.
|
|
514
|
-
* shell before repository persistence or outbox
|
|
498
|
+
* runtime. Stamp pending decisions in the application
|
|
499
|
+
* shell before repository persistence or outbox collection.
|
|
515
500
|
*
|
|
516
501
|
* Use `createDomainEvent(...)` directly for events that don't belong to
|
|
517
502
|
* an aggregate: system events, integration events, configuration events,
|
|
@@ -532,17 +517,17 @@ declare function recordDomainEvent<T extends string, P>(event: UncommittedDomain
|
|
|
532
517
|
declare function createDomainEvent<T extends string>(type: T, payload?: undefined, options?: CreateDomainEventOptions): DomainEvent<T, void>;
|
|
533
518
|
declare function createDomainEvent<T extends string, P>(type: T, payload: P, options?: CreateDomainEventOptions): DomainEvent<T, P>;
|
|
534
519
|
/**
|
|
535
|
-
* Creates
|
|
520
|
+
* Creates a kit-built, stamped domain event exclusively from explicit envelope
|
|
536
521
|
* facts. Unlike {@link createDomainEvent}, it has no clock or event-id fallback
|
|
537
522
|
* and is useful when replay, migration, or a caller-owned boundary already has
|
|
538
523
|
* the final identity and occurrence time.
|
|
539
524
|
*
|
|
540
|
-
* Aggregate behavior normally creates an {@link
|
|
525
|
+
* Aggregate behavior normally creates an {@link UnstampedDomainEvent} through
|
|
541
526
|
* its protected `createEvent` helper. The application shell later records that
|
|
542
527
|
* pending fact with caller-owned time and identity.
|
|
543
528
|
*/
|
|
544
|
-
declare function
|
|
545
|
-
declare function
|
|
529
|
+
declare function createStampedDomainEvent<T extends string>(type: T, payload: undefined, options: CreateStampedDomainEventOptions): DomainEvent<T, void>;
|
|
530
|
+
declare function createStampedDomainEvent<T extends string, P>(type: T, payload: P, options: CreateStampedDomainEventOptions): DomainEvent<T, P>;
|
|
546
531
|
/**
|
|
547
532
|
* Copies metadata from a source event to a new event.
|
|
548
533
|
* Useful for maintaining correlation chains in event-driven architectures.
|
|
@@ -952,7 +937,7 @@ type Id<Tag extends string> = string & {
|
|
|
952
937
|
* The kit makes no attempt to dedupe or detect collisions: a collision
|
|
953
938
|
* silently overwrites earlier rows (under unique-key constraints) or
|
|
954
939
|
* silently aliases two different entities (without them). Safe choices:
|
|
955
|
-
* `crypto.randomUUID()` (UUIDv4
|
|
940
|
+
* UUIDv7 (the default for events), `crypto.randomUUID()` (UUIDv4), ULID,
|
|
956
941
|
* KSUID: all collision-resistant by design. Unsafe choices: `Date.now()`
|
|
957
942
|
* alone (duplicates within the same millisecond), a process-local
|
|
958
943
|
* counter without persistence (resets to 1 on restart, collides with
|
|
@@ -1065,7 +1050,7 @@ interface ReplayableAggregate<TId extends Id<string>, TEvent extends AnyDomainEv
|
|
|
1065
1050
|
* decisions, or a fold records one
|
|
1066
1051
|
* @throws MissingFoldError when no fold is declared for an event type
|
|
1067
1052
|
* @throws FoldReturnedNoStateError when a fold returns `undefined`
|
|
1068
|
-
* @throws
|
|
1053
|
+
* @throws PrototypePollutionError when the folded state carries an own
|
|
1069
1054
|
* `__proto__` key
|
|
1070
1055
|
*/
|
|
1071
1056
|
replayHistory(history: ReadonlyArray<TEvent>): Result<void, DomainError>;
|
|
@@ -1411,6 +1396,43 @@ interface TransactionScope<TCtx> {
|
|
|
1411
1396
|
transactional<T>(fn: (ctx: TCtx) => Promise<T>, options?: TransactionalOptions): Promise<T>;
|
|
1412
1397
|
}
|
|
1413
1398
|
//#endregion
|
|
1399
|
+
//#region src/application/unit-of-work/stamp-pending-events.d.ts
|
|
1400
|
+
/** Minimal shell role accepted by {@link stampPendingEvents}. */
|
|
1401
|
+
type DomainEventStampFactory = Pick<DomainEventFactory, "createStamp">;
|
|
1402
|
+
/** Per-decision stamp provider for metadata that depends on the event. */
|
|
1403
|
+
type DomainEventStampProvider<TEvent extends AnyDomainEvent> = (event: UnstampedDomainEventOf<TEvent>, index: number) => DomainEventStamp;
|
|
1404
|
+
/**
|
|
1405
|
+
* Stamp options that every decision of one stamping shares: a stamp time
|
|
1406
|
+
* and metadata such as the correlation id of the request. An `eventId` is per
|
|
1407
|
+
* fact, so the factory creates it for each decision.
|
|
1408
|
+
*/
|
|
1409
|
+
type SharedDomainEventStampOptions = Omit<CreateDomainEventStampOptions, "eventId">;
|
|
1410
|
+
/**
|
|
1411
|
+
* Stamps every still-unstamped event accepted by an aggregate.
|
|
1412
|
+
*
|
|
1413
|
+
* The commit stamps every still-unstamped event when it registers the
|
|
1414
|
+
* aggregate, so a use case does not need this function. Call it first when
|
|
1415
|
+
* the metadata depends on the concrete decision, for an import, or for a test
|
|
1416
|
+
* that needs fixed ids. The commit keeps the stamps that this function set.
|
|
1417
|
+
*
|
|
1418
|
+
* The function is a command that also returns the stamped batch, a
|
|
1419
|
+
* deliberate exception to command-query separation: the caller hands the
|
|
1420
|
+
* batch on to persistence and needs no second read of `pendingEvents`.
|
|
1421
|
+
*
|
|
1422
|
+
* Stamping is atomic with respect to the aggregate's pending list: if stamp
|
|
1423
|
+
* creation or validation fails, every decision remains unstamped. A
|
|
1424
|
+
* successful second call returns the same event objects and does not read the
|
|
1425
|
+
* factory again, so an instance that a retried attempt registers again keeps
|
|
1426
|
+
* its event identities.
|
|
1427
|
+
*
|
|
1428
|
+
* Pass a `DomainEventFactory` (only its `createStamp` role is required) for one
|
|
1429
|
+
* uniform stamping policy. Add `stampOptions` for metadata that every
|
|
1430
|
+
* decision of the batch shares, such as the correlation id of the request.
|
|
1431
|
+
* Pass a callback instead when metadata depends on the concrete decision.
|
|
1432
|
+
*/
|
|
1433
|
+
declare function stampPendingEvents<TId extends Id<string>, TEvent extends AnyDomainEvent>(aggregate: Aggregate<TId, TEvent>, factory: DomainEventStampFactory, stampOptions?: SharedDomainEventStampOptions): ReadonlyArray<TEvent>;
|
|
1434
|
+
declare function stampPendingEvents<TId extends Id<string>, TEvent extends AnyDomainEvent>(aggregate: Aggregate<TId, TEvent>, createStamp: DomainEventStampProvider<TEvent>): ReadonlyArray<TEvent>;
|
|
1435
|
+
//#endregion
|
|
1414
1436
|
//#region src/application/cqrs/handler.d.ts
|
|
1415
1437
|
/** Dependencies for {@link withCommit}. */
|
|
1416
1438
|
interface WithCommitDeps<Evt extends AnyDomainEvent, TCtx> {
|
|
@@ -1474,12 +1496,25 @@ interface WithCommitDeps<Evt extends AnyDomainEvent, TCtx> {
|
|
|
1474
1496
|
* unless the scope honors the signal.
|
|
1475
1497
|
*/
|
|
1476
1498
|
signal?: AbortSignal;
|
|
1499
|
+
/**
|
|
1500
|
+
* Stamps every pending event that is still unstamped when its aggregate is
|
|
1501
|
+
* registered: the event id, the stamp time, and the metadata. Defaults to
|
|
1502
|
+
* `createDomainEventFactory()`, a UUID v7 from Web Crypto random bits and
|
|
1503
|
+
* the system clock. An event that is already stamped, for example by an
|
|
1504
|
+
* explicit `stampPendingEvents` call, keeps its stamp.
|
|
1505
|
+
*/
|
|
1506
|
+
eventStampFactory?: DomainEventStampFactory;
|
|
1507
|
+
/**
|
|
1508
|
+
* Stamp options that every event stamped in this commit shares, for
|
|
1509
|
+
* example the correlation id of the request.
|
|
1510
|
+
*/
|
|
1511
|
+
stampOptions?: SharedDomainEventStampOptions;
|
|
1477
1512
|
}
|
|
1478
1513
|
declare const aggregateCommitTokenBrand: unique symbol;
|
|
1479
1514
|
/**
|
|
1480
|
-
* Opaque receipt that one aggregate was explicitly
|
|
1481
|
-
* {@link withCommit} invocation. Tokens are
|
|
1482
|
-
* {@link
|
|
1515
|
+
* Opaque receipt that one aggregate was explicitly registered in the current
|
|
1516
|
+
* {@link withCommit} invocation. Tokens are issued only by the invocation's
|
|
1517
|
+
* {@link CommitRegistration} capability and are bound to that invocation at
|
|
1483
1518
|
* runtime; a forged token or one retained from an earlier call is rejected
|
|
1484
1519
|
* inside the transaction.
|
|
1485
1520
|
*/
|
|
@@ -1487,26 +1522,26 @@ interface AggregateCommitToken<Evt extends AnyDomainEvent = AnyDomainEvent> {
|
|
|
1487
1522
|
readonly [aggregateCommitTokenBrand]: Evt;
|
|
1488
1523
|
}
|
|
1489
1524
|
/**
|
|
1490
|
-
* Invocation-scoped
|
|
1491
|
-
* callback. Call `
|
|
1525
|
+
* Invocation-scoped registration capability handed to a {@link withCommit}
|
|
1526
|
+
* callback. Call `registerSaved` only for an aggregate participating in the
|
|
1492
1527
|
* repository write, and return every resulting token in `commits`. Omitting
|
|
1493
|
-
* any token rejects the transaction:
|
|
1494
|
-
* its event
|
|
1528
|
+
* any token rejects the transaction: a registered write may not commit without
|
|
1529
|
+
* its event collection and post-commit acknowledgement. Registrable instances
|
|
1495
1530
|
* must extend `StateStoredAggregate` or `EventSourcedAggregate`; structural
|
|
1496
1531
|
* `Aggregate` lookalikes have no internal lifecycle capability and fail
|
|
1497
1532
|
* before commit.
|
|
1498
1533
|
*/
|
|
1499
|
-
interface
|
|
1500
|
-
|
|
1534
|
+
interface CommitRegistration<Evt extends AnyDomainEvent> {
|
|
1535
|
+
registerSaved(aggregate: Aggregate<Id<string>, Evt>, options?: CommitRegistrationOptions): AggregateCommitToken<Evt>;
|
|
1501
1536
|
/**
|
|
1502
|
-
*
|
|
1503
|
-
* Its events are
|
|
1537
|
+
* Register an aggregate whose row the current transaction removes.
|
|
1538
|
+
* Its events are collected and discarded after commit, but the saved-only
|
|
1504
1539
|
* application `onPersisted` observer is not called.
|
|
1505
1540
|
*/
|
|
1506
|
-
|
|
1541
|
+
registerRemoved(aggregate: Aggregate<Id<string>, Evt>, options?: CommitRegistrationOptions): AggregateCommitToken<Evt>;
|
|
1507
1542
|
}
|
|
1508
|
-
/** OCC baseline associated with one exact commit
|
|
1509
|
-
interface
|
|
1543
|
+
/** OCC baseline associated with one exact commit registration. */
|
|
1544
|
+
interface CommitRegistrationOptions {
|
|
1510
1545
|
/** Absent for a new aggregate; captured at load for update or removal. */
|
|
1511
1546
|
readonly expectedVersion?: Version;
|
|
1512
1547
|
}
|
|
@@ -1514,8 +1549,8 @@ interface CommitEnrollmentOptions {
|
|
|
1514
1549
|
interface WithCommitWorkResult<Evt extends AnyDomainEvent, R> {
|
|
1515
1550
|
result: R;
|
|
1516
1551
|
/**
|
|
1517
|
-
* Commit tokens returned by the invocation's
|
|
1518
|
-
* Every token
|
|
1552
|
+
* Commit tokens returned by the invocation's registration capability.
|
|
1553
|
+
* Every token issued during the callback must appear at least once.
|
|
1519
1554
|
* Naked aggregates are intentionally not accepted: touching an aggregate
|
|
1520
1555
|
* does not prove that its repository write participated in the transaction.
|
|
1521
1556
|
*/
|
|
@@ -1524,29 +1559,29 @@ interface WithCommitWorkResult<Evt extends AnyDomainEvent, R> {
|
|
|
1524
1559
|
/**
|
|
1525
1560
|
* Helper for executing a write Use Case inside a transaction scope.
|
|
1526
1561
|
*
|
|
1527
|
-
* The use-case callback receives an invocation-scoped
|
|
1562
|
+
* The use-case callback receives an invocation-scoped registration capability
|
|
1528
1563
|
* and returns opaque commit tokens for the repository writes that completed
|
|
1529
|
-
* in the transaction. `withCommit` owns the post-commit lifecycle (
|
|
1564
|
+
* in the transaction. `withCommit` owns the post-commit lifecycle (collection,
|
|
1530
1565
|
* outbox, mark-persisted, publish). A naked aggregate is not commit evidence:
|
|
1531
1566
|
* merely touching or constructing one must never make it look persisted.
|
|
1532
1567
|
*
|
|
1533
|
-
* **Trust boundary.** A token proves invocation-local
|
|
1568
|
+
* **Trust boundary.** A token proves invocation-local registration, not that the
|
|
1534
1569
|
* kit inspected a database write; a generic transaction helper cannot observe
|
|
1535
|
-
* adapter internals. Repository code must
|
|
1570
|
+
* adapter internals. Repository code must register only writes participating in
|
|
1536
1571
|
* this transaction. `UnitOfWork` centralizes that rule in repository methods.
|
|
1537
1572
|
* The opaque, scoped token prevents accidental aggregate smuggling and stale
|
|
1538
1573
|
* reuse; it is not a security boundary against code that deliberately lies to
|
|
1539
1574
|
* its own persistence capability.
|
|
1540
1575
|
*
|
|
1541
1576
|
* Order of operations:
|
|
1542
|
-
* 1. `fn(ctx,
|
|
1577
|
+
* 1. `fn(ctx, registration)` runs inside `scope.transactional(...)`; domain
|
|
1543
1578
|
* mutations + repo writes happen here. After a repository write has
|
|
1544
|
-
*
|
|
1579
|
+
* registered an aggregate, the callback includes that opaque token in its
|
|
1545
1580
|
* `commits` result. Tokens are invocation-bound: forged or stale tokens
|
|
1546
|
-
* fail before
|
|
1581
|
+
* fail before collection. `ctx` is whatever transaction handle the `scope`
|
|
1547
1582
|
* exposes (Drizzle `tx`, Prisma `tx`, Mongo session, or `undefined` for
|
|
1548
1583
|
* context-free scopes).
|
|
1549
|
-
* 2. **Still inside the transaction**, `withCommit`
|
|
1584
|
+
* 2. **Still inside the transaction**, `withCommit` collects every
|
|
1550
1585
|
* aggregate's `pendingEvents` and writes them via `outbox.add` (so
|
|
1551
1586
|
* events persist atomically with the state change). Skipped when no
|
|
1552
1587
|
* events were recorded. Each bare domain event is composed into an
|
|
@@ -1556,7 +1591,7 @@ interface WithCommitWorkResult<Evt extends AnyDomainEvent, R> {
|
|
|
1556
1591
|
* resulting `CommittedDomainEvent`. The domain event itself is never
|
|
1557
1592
|
* stamped or copied.
|
|
1558
1593
|
*
|
|
1559
|
-
* **
|
|
1594
|
+
* **Collection order.** Events are concatenated in the order
|
|
1560
1595
|
* tokens appear in the returned `commits` array, then in
|
|
1561
1596
|
* each aggregate's `pendingEvents` order (insertion order via
|
|
1562
1597
|
* `apply` / `commit` / `addDomainEvent`). So tokens for `[a, b]`
|
|
@@ -1580,7 +1615,7 @@ interface WithCommitWorkResult<Evt extends AnyDomainEvent, R> {
|
|
|
1580
1615
|
* across aggregates at delivery time.
|
|
1581
1616
|
* 3. The transaction commits.
|
|
1582
1617
|
* 4. **After** the commit, a non-exported capability acknowledges every
|
|
1583
|
-
* saved
|
|
1618
|
+
* saved registration and discards pending events for deleted registrations.
|
|
1584
1619
|
* Only after the complete commit set is clean does the optional
|
|
1585
1620
|
* application-shell `onPersisted(aggregate, version, context)` observer run for
|
|
1586
1621
|
* saved aggregates. Deleted rows never trigger that observer.
|
|
@@ -1610,16 +1645,16 @@ interface WithCommitWorkResult<Evt extends AnyDomainEvent, R> {
|
|
|
1610
1645
|
* If the transaction rolls back, no acknowledgement occurs: the aggregate
|
|
1611
1646
|
* keeps its pending events, so the caller can retry or discard the instance.
|
|
1612
1647
|
*
|
|
1613
|
-
*
|
|
1648
|
+
* Registration captures an exact version and event batch. Re-registering the same
|
|
1614
1649
|
* aggregate after it changes rejects. `UnitOfWork` additionally seals the
|
|
1615
|
-
* adapter persistence
|
|
1616
|
-
* direct `withCommit` use, make domain decisions first, write, and
|
|
1650
|
+
* adapter persistence capture and rejects later mutation before flush. For
|
|
1651
|
+
* direct `withCommit` use, make domain decisions first, write, and register last.
|
|
1617
1652
|
*
|
|
1618
|
-
* **Duplicate
|
|
1653
|
+
* **Duplicate registration is idempotent by reference.** Registering the same
|
|
1619
1654
|
* instance repeatedly returns the same token, and a repeated token in
|
|
1620
|
-
* `commits` is
|
|
1655
|
+
* `commits` is collected once. A repeat call that omits `expectedVersion`
|
|
1621
1656
|
* makes no OCC assertion; only a supplied value that contradicts the
|
|
1622
|
-
*
|
|
1657
|
+
* registration-time baseline rejects. Each event lands in the outbox exactly once
|
|
1623
1658
|
* and post-commit acknowledgement runs exactly once. Two
|
|
1624
1659
|
* *different* instances with the same logical id cannot be detected
|
|
1625
1660
|
* at this layer; that is a Repository contract violation (failure to
|
|
@@ -1630,17 +1665,17 @@ interface WithCommitWorkResult<Evt extends AnyDomainEvent, R> {
|
|
|
1630
1665
|
*
|
|
1631
1666
|
* @example Tx-bound repos (Drizzle, Prisma, Mongo, …)
|
|
1632
1667
|
* ```typescript
|
|
1633
|
-
* const result = await withCommit({ outbox, bus, scope }, async (tx,
|
|
1668
|
+
* const result = await withCommit({ outbox, bus, scope }, async (tx, registration) => {
|
|
1634
1669
|
* const orderRepository = makeOrderRepository(tx); // your factory binds tx to the repo
|
|
1635
1670
|
* const order = await orderRepository.getById(orderId);
|
|
1636
1671
|
* order.confirm();
|
|
1637
1672
|
* await persistOrder(tx, order); // low-level adapter write
|
|
1638
|
-
* const commit =
|
|
1673
|
+
* const commit = registration.registerSaved(order); // attest the repository write
|
|
1639
1674
|
* return { result: order.id, commits: [commit] };
|
|
1640
1675
|
* });
|
|
1641
1676
|
* ```
|
|
1642
1677
|
*/
|
|
1643
|
-
declare function withCommit<Evt extends AnyDomainEvent, R, TCtx>(deps: WithCommitDeps<Evt, TCtx>, fn: (ctx: TCtx,
|
|
1678
|
+
declare function withCommit<Evt extends AnyDomainEvent, R, TCtx>(deps: WithCommitDeps<Evt, TCtx>, fn: (ctx: TCtx, registration: CommitRegistration<Evt>) => Promise<WithCommitWorkResult<Evt, R>>): Promise<R>;
|
|
1644
1679
|
//#endregion
|
|
1645
1680
|
//#region src/application/deadlines/deadline-store.d.ts
|
|
1646
1681
|
/**
|
|
@@ -1816,7 +1851,7 @@ interface IdempotencyLease {
|
|
|
1816
1851
|
/** Delay after which the wrapper should renew this lease. */
|
|
1817
1852
|
readonly renewAfterMs: number;
|
|
1818
1853
|
}
|
|
1819
|
-
/** Store-
|
|
1854
|
+
/** Store-issued ownership receipt for one successful claim. */
|
|
1820
1855
|
interface IdempotencyClaimHandle {
|
|
1821
1856
|
readonly key: string;
|
|
1822
1857
|
/** Unique across ownership generations for this key; treat as opaque. */
|
|
@@ -1875,7 +1910,7 @@ type IdempotencyClaim = {
|
|
|
1875
1910
|
*
|
|
1876
1911
|
* A NON-transactional store (the in-memory reference on its own, a separate
|
|
1877
1912
|
* durable store) cannot see commits or rollbacks. Every fresh claim
|
|
1878
|
-
* therefore returns a store-
|
|
1913
|
+
* therefore returns a store-issued token and bounded lease. The wrapper
|
|
1879
1914
|
* renews it while the transaction runs; `complete`, `renew`, `confirm`,
|
|
1880
1915
|
* `abandon`, and `reconcile` compare the token so a stale owner cannot
|
|
1881
1916
|
* mutate a successor claim. An expired PENDING claim may be replaced. An
|
|
@@ -2035,12 +2070,12 @@ interface WithIdempotentCommitDeps<Evt extends AnyDomainEvent, TCtx> extends Wit
|
|
|
2035
2070
|
* 2. A fresh claim carries an opaque ownership token. For a leased store the
|
|
2036
2071
|
* wrapper renews it at `renewAfterMs` until the transaction callback is
|
|
2037
2072
|
* ready to commit. A renewal failure rejects before commit and releases
|
|
2038
|
-
* the claim. `fn(ctx,
|
|
2073
|
+
* the claim. `fn(ctx, registration, execution)` receives the same token so a
|
|
2039
2074
|
* source-side marker can make later reconciliation conclusive.
|
|
2040
2075
|
* 3. `store.complete(ctx, claim, fn's result)` stages or completes the outcome
|
|
2041
|
-
* in the same transaction as aggregate writes and outbox. The
|
|
2076
|
+
* in the same transaction as aggregate writes and outbox. The registration
|
|
2042
2077
|
* capability is sealed and its token array copied before `complete` can
|
|
2043
|
-
* yield, so leaked callback state cannot change the
|
|
2078
|
+
* yield, so leaked callback state cannot change the collection receipt.
|
|
2044
2079
|
* 4. After commit, `store.confirm(claim)` finalizes a leased store's staged
|
|
2045
2080
|
* outcome; it is a no-op for transactional stores. A failure cannot reject
|
|
2046
2081
|
* an already committed write, so it is sent to `onIdempotencyError` and the
|
|
@@ -2063,7 +2098,7 @@ interface WithIdempotentCommitDeps<Evt extends AnyDomainEvent, TCtx> extends Wit
|
|
|
2063
2098
|
* production default. Leases make the non-transactional family recoverable;
|
|
2064
2099
|
* they do not manufacture an atomic exactly-once boundary across two stores.
|
|
2065
2100
|
*/
|
|
2066
|
-
declare function withIdempotentCommit<Evt extends AnyDomainEvent, R, TCtx>(deps: WithIdempotentCommitDeps<Evt, TCtx>, request: IdempotentCommitRequest, fn: (ctx: TCtx,
|
|
2101
|
+
declare function withIdempotentCommit<Evt extends AnyDomainEvent, R, TCtx>(deps: WithIdempotentCommitDeps<Evt, TCtx>, request: IdempotentCommitRequest, fn: (ctx: TCtx, registration: CommitRegistration<Evt>, execution: IdempotentExecution) => Promise<WithCommitWorkResult<Evt, R>>): Promise<IdempotentCommitResult<R>>;
|
|
2067
2102
|
//#endregion
|
|
2068
2103
|
//#region src/application/projections/ports.d.ts
|
|
2069
2104
|
/**
|
|
@@ -2248,7 +2283,7 @@ type AggregateClass<TAgg> = Function & {
|
|
|
2248
2283
|
* `AggregatePersistence` implementations: two `findById(id)` calls in the same
|
|
2249
2284
|
* unit of work MUST return the same instance, because commit-token
|
|
2250
2285
|
* write registration dedupes by JavaScript object identity. Two instances for
|
|
2251
|
-
* one logical aggregate can otherwise produce two tokens, two
|
|
2286
|
+
* one logical aggregate can otherwise produce two tokens, two collections,
|
|
2252
2287
|
* and two post-commit lifecycle calls.
|
|
2253
2288
|
*
|
|
2254
2289
|
* Storage is two-level (per-type stores created lazily), so
|
|
@@ -2309,7 +2344,7 @@ declare class IdentityMap {
|
|
|
2309
2344
|
* - Registering a DIFFERENT instance for an occupied type+id throws:
|
|
2310
2345
|
* that is precisely the identity-map violation this class exists
|
|
2311
2346
|
* to prevent (the repository hydrated twice instead of checking
|
|
2312
|
-
* {@link get} first), and letting it pass would double-
|
|
2347
|
+
* {@link get} first), and letting it pass would double-collect
|
|
2313
2348
|
* events downstream.
|
|
2314
2349
|
* - Registering a type+id that was {@link delete}d in this unit of
|
|
2315
2350
|
* work throws `AggregateDeletedError`: deletion is final within
|
|
@@ -2322,7 +2357,7 @@ declare class IdentityMap {
|
|
|
2322
2357
|
* Registered instances that have recorded MORE pending events than they
|
|
2323
2358
|
* carried when first registered (loaded). Used by the unit of work's
|
|
2324
2359
|
* end-of-run guard: an aggregate that gained events after load but was
|
|
2325
|
-
* never
|
|
2360
|
+
* never registered would silently drop them. A read-only load, or a
|
|
2326
2361
|
* reconstitution that already carried events, shows no increase and is
|
|
2327
2362
|
* not reported.
|
|
2328
2363
|
*/
|
|
@@ -2354,16 +2389,16 @@ declare class IdentityMap {
|
|
|
2354
2389
|
/** Whether a baseline represents an existing row or a pending insert. */
|
|
2355
2390
|
type PersistenceLifecycle = "loaded" | "new";
|
|
2356
2391
|
/**
|
|
2357
|
-
* Adapter-owned
|
|
2392
|
+
* Adapter-owned capture and change derivation for one aggregate type.
|
|
2358
2393
|
*
|
|
2359
2394
|
* The domain model does not implement this contract. A repository adapter
|
|
2360
|
-
* chooses what it persists, how
|
|
2395
|
+
* chooses what it persists, how it captures the aggregate at load, and
|
|
2361
2396
|
* whether a change set is a partial diff or a full replacement.
|
|
2362
2397
|
*/
|
|
2363
2398
|
interface PersistenceModel<TAggregate, TBaseline, TChangeSet> {
|
|
2364
2399
|
/**
|
|
2365
|
-
* Captures the
|
|
2366
|
-
* Return a
|
|
2400
|
+
* Captures the aggregate for the adapter at the current moment.
|
|
2401
|
+
* Return a copied value or an immutable value object: the Unit of Work
|
|
2367
2402
|
* retains it as a baseline and cannot make an arbitrary adapter type safe.
|
|
2368
2403
|
*
|
|
2369
2404
|
* Capture must be deterministic for an unchanged aggregate: the Unit of
|
|
@@ -2382,7 +2417,7 @@ interface PersistenceModel<TAggregate, TBaseline, TChangeSet> {
|
|
|
2382
2417
|
*/
|
|
2383
2418
|
capture(aggregate: TAggregate): TBaseline;
|
|
2384
2419
|
/**
|
|
2385
|
-
* Adapter-owned equality for two captures
|
|
2420
|
+
* Adapter-owned equality for two captures.
|
|
2386
2421
|
* Optional: the default is the package's structural deep equality (Set
|
|
2387
2422
|
* members and Map keys by reference). Supply it when the capture shape
|
|
2388
2423
|
* needs domain-specific comparison, for example rebuilt value-object Set
|
|
@@ -2401,46 +2436,11 @@ interface PersistenceModel<TAggregate, TBaseline, TChangeSet> {
|
|
|
2401
2436
|
/** Tells orchestration whether the derived state write is empty. */
|
|
2402
2437
|
isEmpty(changes: TChangeSet): boolean;
|
|
2403
2438
|
}
|
|
2404
|
-
declare const persistenceBaselineBrand: unique symbol;
|
|
2405
|
-
/**
|
|
2406
|
-
* Opaque, typed receipt for an adapter-owned persistence baseline.
|
|
2407
|
-
*
|
|
2408
|
-
* It intentionally exposes no data. The Unit of Work may retain the token and
|
|
2409
|
-
* ask the owning adapter capability to derive changes, but cannot branch on or
|
|
2410
|
-
* couple itself to the baseline's shape.
|
|
2411
|
-
*/
|
|
2412
|
-
interface PersistenceBaseline<TAggregate, TChangeSet> {
|
|
2413
|
-
readonly [persistenceBaselineBrand]: (aggregate: TAggregate) => TChangeSet;
|
|
2414
|
-
}
|
|
2415
2439
|
/** A derived adapter change set plus its adapter-defined emptiness result. */
|
|
2416
2440
|
interface PersistenceChanges<TChangeSet> {
|
|
2417
2441
|
readonly value: TChangeSet;
|
|
2418
2442
|
readonly empty: boolean;
|
|
2419
2443
|
}
|
|
2420
|
-
/** Captures a baseline for an aggregate restored by a repository adapter. */
|
|
2421
|
-
declare function capturePersistenceBaseline<TAggregate, TBaseline, TChangeSet>(model: PersistenceModel<TAggregate, TBaseline, TChangeSet>, aggregate: TAggregate): PersistenceBaseline<TAggregate, TChangeSet>;
|
|
2422
|
-
/** Creates the explicit no-row baseline for a newly added aggregate. */
|
|
2423
|
-
declare function insertPersistenceBaseline<TAggregate, TBaseline, TChangeSet>(model: PersistenceModel<TAggregate, TBaseline, TChangeSet>): PersistenceBaseline<TAggregate, TChangeSet>;
|
|
2424
|
-
/**
|
|
2425
|
-
* Captures the aggregate's current adapter projection using the capability
|
|
2426
|
-
* carried by an existing baseline. Used to seal persistence-last registration.
|
|
2427
|
-
*/
|
|
2428
|
-
declare function recapturePersistenceBaseline<TAggregate, TChangeSet>(baseline: PersistenceBaseline<TAggregate, TChangeSet>, aggregate: TAggregate): PersistenceBaseline<TAggregate, TChangeSet>;
|
|
2429
|
-
/**
|
|
2430
|
-
* Recaptures the adapter projection and reports whether it drifted from the
|
|
2431
|
-
* baseline's stored capture, using the model's `captureEquals` when supplied
|
|
2432
|
-
* and structural deep equality otherwise.
|
|
2433
|
-
*
|
|
2434
|
-
* This, not `changes()`/`isEmpty()`, is the mutation detector: the
|
|
2435
|
-
* `PersistenceModel` contract explicitly permits a full-replacement change
|
|
2436
|
-
* set whose `isEmpty` is never true, so a non-empty change set proves
|
|
2437
|
-
* nothing about mutation. Comparing capture to capture asks the honest
|
|
2438
|
-
* question independent of the model's diffing strategy. A `"new"` lifecycle
|
|
2439
|
-
* baseline has no stored capture and never reports drift.
|
|
2440
|
-
*/
|
|
2441
|
-
declare function persistenceProjectionDrifted<TAggregate, TChangeSet>(baseline: PersistenceBaseline<TAggregate, TChangeSet>, aggregate: TAggregate): boolean;
|
|
2442
|
-
/** Derives a typed adapter change set without exposing the stored baseline. */
|
|
2443
|
-
declare function derivePersistenceChanges<TAggregate, TChangeSet>(baseline: PersistenceBaseline<TAggregate, TChangeSet>, aggregate: TAggregate): PersistenceChanges<TChangeSet>;
|
|
2444
2444
|
//#endregion
|
|
2445
2445
|
//#region src/application/unit-of-work/persistence-contract.d.ts
|
|
2446
2446
|
/** The explicit persistence intent registered for one tracked aggregate. */
|
|
@@ -2454,7 +2454,7 @@ type UnitOfWorkIdentityMap = Pick<IdentityMap, "get" | "has" | "isDeleted">;
|
|
|
2454
2454
|
* restored aggregate.
|
|
2455
2455
|
* Write methods exposed to application code are replaced by Unit-of-Work-owned
|
|
2456
2456
|
* `add`, `update`, and `remove` registrations, so an adapter implementation of
|
|
2457
|
-
* those methods cannot perform durable I/O early or skip event
|
|
2457
|
+
* those methods cannot perform durable I/O early or skip event collection.
|
|
2458
2458
|
*
|
|
2459
2459
|
* Contract for repository implementations:
|
|
2460
2460
|
* - `findById(id)` checks `identityMap.get` BEFORE hydrating, treats
|
|
@@ -2717,6 +2717,10 @@ interface EventStore<Evt extends AnyDomainEvent> extends EventStreamReader<Evt>
|
|
|
2717
2717
|
* proves the duplicate/gap rejection. The repository then calls
|
|
2718
2718
|
* `replayHistory`, whose replay guard rejects any event carrying an
|
|
2719
2719
|
* aggregate type or id that contradicts this stream key.
|
|
2720
|
+
* 7. **Stamped events only:** reject an event without an `eventId` with
|
|
2721
|
+
* a `TypeError`, before any write. A direct `withCommit` callback can
|
|
2722
|
+
* append before its registration stamps the events; this check makes
|
|
2723
|
+
* that mistake fail instead of storing ids that the outbox never sees.
|
|
2720
2724
|
*
|
|
2721
2725
|
* An empty `events` array is a no-op; implementations resolve without
|
|
2722
2726
|
* touching the store (an ES repository skips `append` for aggregates
|
|
@@ -2840,7 +2844,7 @@ declare function reconstituteAggregateFromStreamPages<TAggregate extends Replaya
|
|
|
2840
2844
|
* `createSnapshotStoreContractTests` from `@shirudo/ddd-kit/testing`):
|
|
2841
2845
|
* the snapshot round-trips verbatim (`state` as plain data,
|
|
2842
2846
|
* `version`, `snapshotAt` with millisecond fidelity, `schemaVersion`
|
|
2843
|
-
* including its absence), loads return
|
|
2847
|
+
* including its absence), loads return copies (never live
|
|
2844
2848
|
* internal state), and keys are isolated per aggregate type AND id
|
|
2845
2849
|
* (one table may serve every aggregate type).
|
|
2846
2850
|
*
|
|
@@ -2875,5 +2879,5 @@ interface SnapshotStore<TState = unknown> {
|
|
|
2875
2879
|
delete(identity: AggregateIdentity): Promise<void>;
|
|
2876
2880
|
}
|
|
2877
2881
|
//#endregion
|
|
2878
|
-
export {
|
|
2882
|
+
export { PublishOptions as $, JsonPrimitive as $t, IdempotentCommitRequest as A, CreateStampedDomainEventOptions as At, CommitRegistrationOptions as B, UnstampedDomainEventOf as Bt, IdempotencyClaim as C, CommittedDomainEvent as Ct, IdempotencyReconciliation as D, AnyUnstampedDomainEvent as Dt, IdempotencyOperationErrorContext as E, AnyDomainEvent as Et, DeadLetterDeadline as F, DomainEventStamp as Ft, DomainEventStampProvider as G, defaultDomainEventFactory as Gt, WithCommitWorkResult as H, createDomainEvent as Ht, DeadlineStore as I, EventIdFactory as It, TransactionScope as J, AggregateIdentity as Jt, SharedDomainEventStampOptions as K, mergeMetadata as Kt, DueDeadline as L, EventMetadata as Lt, IdempotentExecution as M, DomainEvent as Mt, WithIdempotentCommitDeps as N, DomainEventFactory as Nt, IdempotencyReconciliationDecision as O, CreateDomainEventOptions as Ot, withIdempotentCommit as P, DomainEventFactoryOptions as Pt, OnceOptions as Q, JsonObject as Qt, AggregateCommitToken as R, PendingDomainEvent as Rt, isPositionAfter as S, CommitPosition as St, IdempotencyLease as T, EventCommitCandidatePosition as Tt, withCommit as U, createDomainEventFactory as Ut, WithCommitDeps as V, copyMetadata as Vt, DomainEventStampFactory as W, createStampedDomainEvent as Wt, EventBus as X, CommandHandler as Xt, TransactionalOptions as Y, Command as Yt, EventHandler as Z, PublishedCommand as Zt, IdentityMap as _, DispatchTrackingOutbox as _t, EventStoreAppendOptions as a, toVersion as at, ProjectionCheckpointStore as b, OutboxWriter as bt, StreamReadResult as c, CommandCommitOriginCandidate as ct, RepositoryTracking as d, CommandOutboxCommitCandidate as dt, JsonValue as en, Aggregate as et, UnitOfWorkIdentityMap as f, CommandOutboxMapper as ft, AggregateClass as g, DeadLetterRecord as gt, PersistenceModel as h, routeEventsToCommandOutbox as ht, EventStore as i, sameVersion as it, IdempotentCommitResult as j, CreateUnstampedDomainEventOptions as jt, IdempotencyStore as k, CreateDomainEventStampOptions as kt, AggregatePersistenceWrite as l, CommandMessageContent as lt, PersistenceLifecycle as m, DurableCommandMessage as mt, ReplayableStreamPages as n, ReplayableAggregate as nt, EventStreamReader as o, Id as ot, PersistenceChanges as p, CommandOutboxWriter as pt, stampPendingEvents as q, ClockFactory as qt, reconstituteAggregateFromStreamPages as r, Version as rt, ReadStreamOptions as s, IdGenerator as st, SnapshotStore as t, AggregateSnapshot as tt, AggregateWriteIntent as u, CommandMessageRelationships as ut, Projection as v, Outbox as vt, IdempotencyClaimHandle as w, EventCommitCandidate as wt, ProjectionPosition as x, ExecutionContext as xt, ProjectionCheckpoint as y, OutboxRecord as yt, CommitRegistration as z, UnstampedDomainEvent as zt };
|
|
2879
2883
|
//# sourceMappingURL=snapshot-store.d.ts.map
|