@shirudo/ddd-kit 3.0.0-rc.10 → 3.0.0-rc.12

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/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { $ as ReentrantEventRecordingError, A as IdempotencyReconciliationRequiredErrorOptions, B as MisaddressedEventError, C as IdempotencyClaimLostErrorOptions, D as IdempotencyKeyReuseError, E as IdempotencyInFlightErrorOptions, F as InvalidIntegrationMessageError, G as NonProgressingEventStreamPageErrorOptions, H as MissingFoldError, I as InvalidVersionError, J as PendingEventLimitExceededErrorOptions, K as PendingEventBatchMismatchError, L as KitErrorCode, M as InMemoryCapacityExceededErrorOptions, N as InfrastructureError, O as IdempotencyKeyReuseErrorOptions, P as InvalidCommandMessageError, Q as ProjectionReceiptViolationError, R as KitErrorOptions, S as IdempotencyClaimLostError, T as IdempotencyInFlightError, U as MissingHandlerError, V as MissingEntityIdError, W as NonProgressingEventStreamPageError, X as ProjectionIdentityViolationError, Y as ProjectionGapError, Z as ProjectionOrderViolationError, _ as ErrorMapperFailedErrorOptions, a as CapabilityRegistryConflictError, at as SnapshotVersionNotRestoredError, b as ForeignEventError, c as ConcurrencyConflictReason, ct as UnmanagedInstanceError, d as DuplicateAggregateError, dt as UnregisteredHandlerError, et as ReplayHeadMismatchError, f as DuplicateAggregateErrorOptions, ft as UnregisteredHandlerErrorOptions, g as ErrorMapperFailedError, gt as isWiringErrorLike, h as DuplicateHandlerRegistrationErrorOptions, ht as isInfrastructureErrorLike, i as AggregateNotFoundErrorOptions, it as SnapshotSchemaMismatchErrorOptions, j as InMemoryCapacityExceededError, k as IdempotencyReconciliationRequiredError, l as DirectStateMutationError, lt as UnmintedEventError, m as DuplicateHandlerRegistrationError, mt as isDomainErrorLike, n as AggregateDeletedError, nt as SnapshotCorruptedError, o as ConcurrencyConflictError, ot as SnapshotVersionNotRestoredErrorOptions, p as DuplicateEventIdError, pt as UnreplayableAggregateError, q as PendingEventLimitExceededError, r as AggregateNotFoundError, rt as SnapshotSchemaMismatchError, s as ConcurrencyConflictErrorOptions, st as UnenrolledChangesError, t as AggregateAddressMismatchOptions, tt as ReplayHeadMismatchErrorOptions, u as DomainError, ut as UnprojectableEventError, v as EventHarvestError, w as IdempotencyCompletionWithoutClaimError, x as HostileStateKeyError, y as FoldReturnedNoStateError, z as KitWiringError } from "./chunks/kit-errors.js";
2
- import { $ as routeEventsToCommandOutbox, A as WithCommitWorkResult, At as defaultDomainEventFactory, B as ReplayableAggregate, Bt as JsonValue, C as DeadLetterDeadline, Ct as UncommittedDomainEvent, D as CommitEnrollment, Dt as createDomainEventFactory, E as AggregateCommitToken, Et as createDomainEvent, F as EventHandler, Ft as Command, G as IdGenerator, H as sameVersion, I as OnceOptions, It as CommandHandler, J as CommandMessageRelationships, K as CommandCommitOriginCandidate, L as PublishOptions, Lt as PublishedCommand, M as TransactionScope, Mt as recordDomainEvent, N as TransactionalOptions, Nt as ClockFactory, O as CommitEnrollmentOptions, Ot as createDomainEventFromFacts, P as EventBus, Pt as AggregateAddress, Q as DurableCommandMessage, R as Aggregate, Rt as JsonObject, S as withIdempotentCommit, St as PendingDomainEvent, T as DueDeadline, Tt as copyMetadata, U as toVersion, V as Version, W as Id, X as CommandOutboxMapper, Y as CommandOutboxCommitCandidate, Z as CommandOutboxWriter, _ as IdempotencyStore, _t as DomainEventFactory, a as StreamReadResult, at as ExecutionContext, b as IdempotentExecution, bt as EventIdFactory, c as ProjectionCheckpointStore, ct as EventCommitCandidate, d as IdempotencyClaim, dt as AnyUncommittedDomainEvent, et as DeadLetterRecord, f as IdempotencyClaimHandle, ft as CreateDomainEventFromFactsOptions, g as IdempotencyReconciliationDecision, gt as DomainEvent, h as IdempotencyReconciliation, ht as CreateUncommittedDomainEventOptions, i as ReadStreamOptions, it as OutboxWriter, j as withCommit, jt as mergeMetadata, k as WithCommitDeps, kt as createUncommittedDomainEvent, l as ProjectionPosition, lt as EventCommitCandidatePosition, m as IdempotencyOperationErrorContext, mt as CreateDomainEventStampOptions, n as EventStore, nt as Outbox, o as Projection, ot as CommitPosition, p as IdempotencyLease, pt as CreateDomainEventOptions, q as CommandMessageContent, r as EventStoreAppendOptions, rt as OutboxRecord, s as ProjectionCheckpoint, st as CommittedDomainEvent, t as SnapshotStore, tt as DispatchTrackingOutbox, u as isPositionAfter, ut as AnyDomainEvent, v as IdempotentCommitRequest, vt as DomainEventFactoryOptions, w as DeadlineStore, wt as UncommittedDomainEventOf, x as WithIdempotentCommitDeps, xt as EventMetadata, y as IdempotentCommitResult, yt as DomainEventStamp, z as AggregateSnapshot, zt as JsonPrimitive } from "./chunks/snapshot-store.js";
1
+ import { $ as PendingEventLimitExceededErrorOptions, A as IdempotencyInFlightErrorOptions, B as InvalidEventStreamPageErrorOptions, C as FoldReturnedNoStateError, Ct as UnreplayableAggregateError, D as IdempotencyClaimLostErrorOptions, Dt as isWiringErrorLike, E as IdempotencyClaimLostError, Et as isInfrastructureErrorLike, F as InMemoryCapacityExceededError, G as KitWiringError, H as InvalidVersionError, I as InMemoryCapacityExceededErrorOptions, J as MissingFoldError, K as MisattributedEventError, L as InfrastructureError, M as IdempotencyKeyReuseErrorOptions, N as IdempotencyReconciliationRequiredError, O as IdempotencyCompletionWithoutClaimError, P as IdempotencyReconciliationRequiredErrorOptions, Q as PendingEventLimitExceededError, R as InvalidCommandMessageError, S as EventStreamPageReason, St as UnregisteredHandlerErrorOptions, T as HostileStateKeyError, Tt as isDomainErrorLike, U as KitErrorCode, V as InvalidIntegrationMessageError, W as KitErrorOptions, X as PendingEventBatchMismatchError, Y as MissingHandlerError, Z as PendingEventBatchMismatchErrorOptions, _ as DuplicateHandlerRegistrationError, _t as UnenrolledChangesErrorOptions, a as AggregateNotFoundErrorOptions, at as ReentrantEventRecordingErrorOptions, b as ErrorMapperFailedErrorOptions, bt as UnprojectableEventError, c as ConcurrencyConflictErrorOptions, ct as ReplayTargetMismatchError, d as DirectStateMutationErrorOptions, dt as SnapshotCorruptedError, et as ProjectionGapError, f as DomainError, ft as SnapshotSchemaMismatchError, g as DuplicateEventIdErrorOptions, gt as UnenrolledChangesError, h as DuplicateEventIdError, ht as SnapshotVersionNotRestoredErrorOptions, i as AggregateNotFoundError, it as ReentrantEventRecordingError, j as IdempotencyKeyReuseError, k as IdempotencyInFlightError, l as ConcurrencyConflictReason, lt as ReplayTargetMismatchErrorOptions, m as DuplicateAggregateErrorOptions, mt as SnapshotVersionNotRestoredError, n as AggregateDeletedErrorOptions, nt as ProjectionOrderViolationError, o as CapabilityRegistryConflictError, ot as ReplayRejectedError, p as DuplicateAggregateError, pt as SnapshotSchemaMismatchErrorOptions, q as MissingEntityIdError, r as AggregateIdentityMismatchOptions, rt as ProjectionReceiptViolationError, s as ConcurrencyConflictError, st as ReplayRejectedErrorOptions, t as AggregateDeletedError, tt as ProjectionIdentityViolationError, u as DirectStateMutationError, ut as ReplayTargetMismatchReason, v as DuplicateHandlerRegistrationErrorOptions, vt as UnmanagedInstanceError, w as ForeignEventError, wt as UnreplayableAggregateErrorOptions, x as EventHarvestError, xt as UnregisteredHandlerError, y as ErrorMapperFailedError, yt as UnmintedEventError, z as InvalidEventStreamPageError } from "./chunks/kit-errors.js";
2
+ import { $ as EventHandler, $t as Command, A as IdempotencyClaimHandle, At as CreateDomainEventFromFactsOptions, B as withIdempotentCommit, Bt as PendingDomainEvent, C as IdentityMap, Ct as ExecutionContext, D as ProjectionPosition, Dt as EventCommitCandidatePosition, E as ProjectionCheckpointStore, Et as EventCommitCandidate, F as IdempotencyStore, Ft as DomainEventFactory, G as CommitEnrollment, Gt as createDomainEventFactory, H as DeadlineStore, Ht as UncommittedDomainEventOf, I as IdempotentCommitRequest, It as DomainEventFactoryOptions, J as WithCommitWorkResult, Jt as defaultDomainEventFactory, K as CommitEnrollmentOptions, Kt as createDomainEventFromFacts, L as IdempotentCommitResult, Lt as DomainEventStamp, M as IdempotencyOperationErrorContext, Mt as CreateDomainEventStampOptions, N as IdempotencyReconciliation, Nt as CreateUncommittedDomainEventOptions, O as isPositionAfter, Ot as AnyDomainEvent, P as IdempotencyReconciliationDecision, Pt as DomainEvent, Q as EventBus, Qt as AggregateIdentity, R as IdempotentExecution, Rt as EventIdFactory, S as AggregateClass, St as OutboxWriter, T as ProjectionCheckpoint, Tt as CommittedDomainEvent, U as DueDeadline, Ut as copyMetadata, V as DeadLetterDeadline, Vt as UncommittedDomainEvent, W as AggregateCommitToken, Wt as createDomainEvent, X as TransactionScope, Xt as recordDomainEvent, Y as withCommit, Yt as mergeMetadata, Z as TransactionalOptions, Zt as ClockFactory, _ as capturePersistenceBaseline, _t as routeEventsToCommandOutbox, a as EventStoreAppendOptions, at as Version, b as persistenceProjectionDrifted, bt as Outbox, c as StreamReadResult, ct as Id, d as RepositoryTracking, dt as CommandMessageContent, en as CommandHandler, et as OnceOptions, f as UnitOfWorkIdentityMap, ft as CommandMessageRelationships, g as PersistenceModel, gt as DurableCommandMessage, h as PersistenceLifecycle, ht as CommandOutboxWriter, i as EventStore, in as JsonValue, it as ReplayableAggregate, j as IdempotencyLease, jt as CreateDomainEventOptions, k as IdempotencyClaim, kt as AnyUncommittedDomainEvent, l as AggregatePersistenceWrite, lt as IdGenerator, m as PersistenceChanges, mt as CommandOutboxMapper, n as ReplayableStreamPages, nn as JsonObject, nt as Aggregate, o as EventStreamReader, ot as sameVersion, p as PersistenceBaseline, pt as CommandOutboxCommitCandidate, q as WithCommitDeps, qt as createUncommittedDomainEvent, r as reconstituteAggregateFromStreamPages, rn as JsonPrimitive, rt as AggregateSnapshot, s as ReadStreamOptions, st as toVersion, t as SnapshotStore, tn as PublishedCommand, tt as PublishOptions, u as AggregateWriteIntent, ut as CommandCommitOriginCandidate, v as derivePersistenceChanges, vt as DeadLetterRecord, w as Projection, wt as CommitPosition, x as recapturePersistenceBaseline, xt as OutboxRecord, y as insertPersistenceBaseline, yt as DispatchTrackingOutbox, z as WithIdempotentCommitDeps, zt as EventMetadata } from "./chunks/snapshot-store.js";
3
3
  import { Result } from "@shirudo/result";
4
4
  import { ValidationError } from "@shirudo/base-error";
5
5
  //#region src/application/cqrs/internal/bus-internals.d.ts
@@ -410,6 +410,32 @@ declare class QueryBus<TMap extends QueryTypeMap = QueryTypeMap, E = string> imp
410
410
  executeUnsafe<Q extends Query, R>(query: UntypedMapDispatch<TMap, Q>): Promise<R>;
411
411
  }
412
412
  //#endregion
413
+ //#region src/persistence/repository/in-memory-transaction.d.ts
414
+ /**
415
+ * The transaction of one registered store inside an
416
+ * `InMemoryTransactionScope`. The scope ends it once, with `commit` or
417
+ * `rollback`.
418
+ */
419
+ interface InMemoryTransaction {
420
+ /**
421
+ * Ends the transaction and keeps its writes. It must not throw. If a commit
422
+ * throws, the scope still commits the other stores and rejects with the
423
+ * first failure, so the writes stay partly committed.
424
+ */
425
+ commit(): void;
426
+ /** Ends the transaction and undoes its writes. */
427
+ rollback(): void;
428
+ }
429
+ /**
430
+ * An in-memory store that you can register with an
431
+ * `InMemoryTransactionScope`. The store prepares its rollback when a
432
+ * transaction begins. The scope never reads the state of a store.
433
+ */
434
+ interface InMemoryTransactionParticipant {
435
+ /** Begins a transaction. Only an `InMemoryTransactionScope` calls this method. */
436
+ beginTransaction(): InMemoryTransaction;
437
+ }
438
+ //#endregion
413
439
  //#region src/application/deadlines/adapters/in-memory-deadline-store.d.ts
414
440
  /** Construction options for {@link InMemoryDeadlineStore}. */
415
441
  interface InMemoryDeadlineStoreOptions {
@@ -428,23 +454,46 @@ interface InMemoryDeadlineStoreOptions {
428
454
  * limit rejects a new address before mutation; delivery state is never
429
455
  * silently evicted.
430
456
  *
431
- * **Not transaction-aware**, the same documented limitation as the
432
- * other in-memory references: a rolled-back `schedule` or `cancel`
433
- * stays applied here. The transactional half of the contract is the
434
- * SQL adapter's job; prove it with `createDeadlineStoreContractTests`
435
- * and its rollback capability.
457
+ * On its own, the store knows nothing about your `TransactionScope`
458
+ * rollbacks: a rolled-back `schedule` or `cancel` stays applied. Register
459
+ * the store with an `InMemoryTransactionScope` for tests that roll back or
460
+ * retry.
461
+ *
462
+ * A processor reads only committed deadlines. While a transaction is open,
463
+ * `due` skips a deadline that the transaction scheduled. For an address that
464
+ * the transaction rescheduled or cancelled, it returns the committed
465
+ * deadline as it was at the first write of the transaction. A failure report
466
+ * against that deadline counts its attempts. At the ceiling, `due` stops
467
+ * returning it until the transaction ends. A rollback also undoes an acknowledgement or a failure report
468
+ * that a processor made while the transaction was open. The processor then
469
+ * delivers that deadline again. For production, prove the transactional half
470
+ * of the contract with `createDeadlineStoreContractTests` and its rollback
471
+ * capability.
436
472
  *
437
473
  * Payloads are deep-copied on schedule and on delivery
438
474
  * (`structuredClone`), so neither side can mutate the other's copy.
439
475
  */
440
- declare class InMemoryDeadlineStore<TPayload = unknown> implements DeadlineStore<TPayload> {
476
+ declare class InMemoryDeadlineStore<TPayload = unknown> implements DeadlineStore<TPayload>, InMemoryTransactionParticipant {
441
477
  private readonly pending;
442
478
  /** Keyed by deliveryId: several incarnations of one address can be dead. */
443
479
  private readonly dead;
444
480
  private readonly maxDeliveryAttempts;
445
481
  private readonly maxRecords;
446
482
  private nextSequence;
483
+ /**
484
+ * The committed deadline of each address that the open transaction wrote,
485
+ * captured at its first write. `undefined` marks an address without one.
486
+ */
487
+ private committedVersions;
447
488
  constructor(options?: InMemoryDeadlineStoreOptions);
489
+ /**
490
+ * Records the state that a rollback of an `InMemoryTransactionScope`
491
+ * returns to: the pending and the dead-letter records. The rollback
492
+ * keeps the sequence counter, as a database sequence does, so a
493
+ * delivery id stays unique. Until the transaction ends, `due` returns the
494
+ * committed deadline of each address that the transaction writes.
495
+ */
496
+ beginTransaction(): InMemoryTransaction;
448
497
  schedule(deadline: {
449
498
  scope: string;
450
499
  key: string;
@@ -453,6 +502,15 @@ declare class InMemoryDeadlineStore<TPayload = unknown> implements DeadlineStore
453
502
  }): Promise<void>;
454
503
  cancel(scope: string, key: string): Promise<void>;
455
504
  due(now: Date, limit: number): Promise<ReadonlyArray<DueDeadline<TPayload>>>;
505
+ private recordCommittedVersion;
506
+ /**
507
+ * The pending deadlines that a processor may see. For an address that the
508
+ * open transaction wrote, it is the committed deadline, if any, and not
509
+ * the live record.
510
+ */
511
+ private committedPending;
512
+ /** The address of the committed deadline with this delivery id, if any. */
513
+ private committedVersionAddress;
456
514
  markDelivered(deliveryIds: ReadonlyArray<string>): Promise<void>;
457
515
  markFailed(deliveryId: string, error?: unknown): Promise<DeadLetterDeadline<TPayload> | undefined>;
458
516
  deadLetters(): Promise<ReadonlyArray<DeadLetterDeadline<TPayload>>>;
@@ -728,14 +786,26 @@ interface InMemoryIdempotencyStoreOptions {
728
786
  * process must configure the limit or use a durable adapter; exhaustion
729
787
  * rejects new keys before mutation and never forgets an idempotency decision.
730
788
  *
731
- * It is deliberately not transaction-aware. Claims and staged outcomes carry
732
- * bounded leases, while every mutation compares the store-minted token. An
733
- * expired pending claim may be replaced; an expired staged outcome cannot be
734
- * guessed away and instead returns `reconciliation-required`. Only an
735
- * authoritative `committed` / `not-committed` decision can settle it.
789
+ * On its own, the store is the reference for the leased family: it cannot
790
+ * see commits or rollbacks. Claims and staged outcomes carry bounded leases,
791
+ * while every mutation compares the store-minted token. An expired pending
792
+ * claim may be replaced; an expired staged outcome cannot be guessed away and
793
+ * instead returns `reconciliation-required`. Only an authoritative
794
+ * `committed` / `not-committed` decision can settle it.
795
+ *
796
+ * Register the store with an `InMemoryTransactionScope` for tests that roll
797
+ * back or retry. A rollback then undoes the writes of `claim` and `complete`,
798
+ * which the port runs inside the transaction. It returns each key that they
799
+ * wrote to its earlier entry. The lease operations `renew`, `confirm`,
800
+ * `abandon`, and `reconcile` stay out of band, as the port defines them. A
801
+ * rollback keeps their writes on every other key. A confirmation that
802
+ * arrives after the next transaction began therefore survives the rollback
803
+ * of that transaction.
736
804
  */
737
- declare class InMemoryIdempotencyStore<TCtx = unknown> implements IdempotencyStore<TCtx> {
805
+ declare class InMemoryIdempotencyStore<TCtx = unknown> implements IdempotencyStore<TCtx>, InMemoryTransactionParticipant {
738
806
  private readonly entries;
807
+ /** The entries that `claim` and `complete` replaced in the open transaction. */
808
+ private replacedInTransaction;
739
809
  private readonly clock;
740
810
  private readonly claimTokenFactory;
741
811
  private readonly leaseDurationMs;
@@ -743,6 +813,12 @@ declare class InMemoryIdempotencyStore<TCtx = unknown> implements IdempotencySto
743
813
  private readonly maxEntries;
744
814
  private tokenGeneration;
745
815
  constructor(options?: InMemoryIdempotencyStoreOptions);
816
+ /**
817
+ * Starts to record the entries that `claim` and `complete` replace. The
818
+ * rollback restores them in reverse order. It keeps the token generation,
819
+ * so a token from a rolled-back claim never names a later claim.
820
+ */
821
+ beginTransaction(): InMemoryTransaction;
746
822
  claim(_ctx: TCtx, key: string, fingerprint: string): Promise<IdempotencyClaim>;
747
823
  complete(_ctx: TCtx, claim: IdempotencyClaimHandle, outcome: unknown): Promise<void>;
748
824
  renew(claim: IdempotencyClaimHandle): Promise<IdempotencyLease | undefined>;
@@ -753,7 +829,15 @@ declare class InMemoryIdempotencyStore<TCtx = unknown> implements IdempotencySto
753
829
  get size(): number;
754
830
  /** Test hook: drops every record. */
755
831
  clear(): void;
832
+ /**
833
+ * Returns the claim that the stored entry of the key decides, or
834
+ * `undefined` when the store can create a pending claim. Throws for a
835
+ * reused key, a claim in flight, and a full store.
836
+ */
837
+ private decideFromStoredEntry;
838
+ private newTokenPart;
756
839
  private createPending;
840
+ private writeInTransaction;
757
841
  private lease;
758
842
  private nowMs;
759
843
  private claimLost;
@@ -761,7 +845,7 @@ declare class InMemoryIdempotencyStore<TCtx = unknown> implements IdempotencySto
761
845
  //#endregion
762
846
  //#region src/application/projections/adapters/in-memory-checkpoint-store.d.ts
763
847
  interface InMemoryProjectionCheckpointStoreOptions {
764
- /** Maximum checkpoints across all projection names and aggregate addresses. */
848
+ /** Maximum checkpoints across all projection names and aggregate identities. */
765
849
  readonly maxCheckpoints?: number;
766
850
  }
767
851
  /**
@@ -770,16 +854,19 @@ interface InMemoryProjectionCheckpointStoreOptions {
770
854
  * serves tests and in-memory read models.
771
855
  *
772
856
  * Its checkpoint-key locks serialize competing projectors only inside one
773
- * process and only when they share this store instance. It is **not
774
- * transaction-aware** (the `ctx` parameter is ignored): a rolled-back
775
- * projector batch does not roll back its checkpoints. Use it for tests and
776
- * disposable in-memory read models; production atomicity is the durable
777
- * adapter's contract, proved with `createProjectionCheckpointStoreContractTests`
778
- * and its rollback capability.
857
+ * process and only when they share this store instance. The store ignores
858
+ * the `ctx` parameter. On its own, it knows nothing about your
859
+ * `TransactionScope` rollbacks: a rolled-back projector batch keeps its
860
+ * checkpoints. Register the store with an `InMemoryTransactionScope` for
861
+ * tests that roll back or retry. While a transaction is open, `hasReached`
862
+ * answers from the checkpoints at the start of the transaction. Use it for
863
+ * tests and disposable in-memory read models; production atomicity is the
864
+ * durable adapter's contract, proved with
865
+ * `createProjectionCheckpointStoreContractTests` and its rollback capability.
779
866
  *
780
867
  * Without `maxCheckpoints`, checkpoint retention is unbounded and supported
781
868
  * only for finite-lifetime tests and demos. A configured limit rejects a new
782
- * address before mutation; existing watermarks remain updatable and are never
869
+ * identity before mutation; existing watermarks remain updatable and are never
783
870
  * evicted because forgetting one would change projection correctness.
784
871
  *
785
872
  * Do not nest `withCheckpointLocks` calls whose key sets overlap. This
@@ -787,18 +874,27 @@ interface InMemoryProjectionCheckpointStoreOptions {
787
874
  * on the key its caller still holds and therefore neither enters nor fails
788
875
  * loudly.
789
876
  */
790
- declare class InMemoryProjectionCheckpointStore implements ProjectionCheckpointStore<unknown> {
877
+ declare class InMemoryProjectionCheckpointStore implements ProjectionCheckpointStore<unknown>, InMemoryTransactionParticipant {
791
878
  /** projection name -> JSON [aggregateType, aggregateId] -> receipt */
792
879
  private readonly checkpoints;
793
880
  /** Full checkpoint key -> tail of the process-local exclusive-access queue. */
794
881
  private readonly lockTails;
795
882
  private readonly maxCheckpoints;
796
883
  private checkpointCount;
884
+ /** The checkpoints at the start of the open transaction. */
885
+ private committedCheckpoints;
797
886
  constructor(options?: InMemoryProjectionCheckpointStoreOptions);
798
- withCheckpointLocks<R>(_ctx: unknown, projection: string, addresses: ReadonlyArray<AggregateAddress>, work: () => Promise<R>): Promise<R>;
799
- load(_ctx: unknown, projection: string, address: AggregateAddress): Promise<ProjectionCheckpoint | undefined>;
800
- save(_ctx: unknown, projection: string, address: AggregateAddress, checkpoint: ProjectionCheckpoint): Promise<void>;
801
- hasReached(projection: string, address: AggregateAddress, position: ProjectionPosition): Promise<boolean>;
887
+ /**
888
+ * Records the state that a rollback of an `InMemoryTransactionScope`
889
+ * returns to: the checkpoints and their count. Until the transaction
890
+ * ends, `hasReached` reads these recorded checkpoints. The rollback
891
+ * keeps the checkpoint locks, because a caller still holds them.
892
+ */
893
+ beginTransaction(): InMemoryTransaction;
894
+ withCheckpointLocks<R>(_ctx: unknown, projection: string, identities: ReadonlyArray<AggregateIdentity>, work: () => Promise<R>): Promise<R>;
895
+ load(_ctx: unknown, projection: string, identity: AggregateIdentity): Promise<ProjectionCheckpoint | undefined>;
896
+ save(_ctx: unknown, projection: string, identity: AggregateIdentity, checkpoint: ProjectionCheckpoint): Promise<void>;
897
+ hasReached(projection: string, identity: AggregateIdentity, position: ProjectionPosition): Promise<boolean>;
802
898
  reset(_ctx: unknown, projection: string): Promise<void>;
803
899
  }
804
900
  //#endregion
@@ -1181,8 +1277,8 @@ interface ProjectionBatchResult {
1181
1277
  * Because checkpoints advance only across a verified chain, a position
1182
1278
  * at or behind the watermark is already traversed and can be skipped under
1183
1279
  * the source's one-logical-event-per-position contract.
1184
- * - **Feeds are complete per aggregate address.** Once a feed supplies one
1185
- * address, it must supply every committed envelope in that address's cursor
1280
+ * - **Feeds are complete per aggregate identity.** Once a feed supplies one
1281
+ * identity, it must supply every committed envelope in that aggregate's cursor
1186
1282
  * chain. Do not event-type-filter a projector subscription. Irrelevant event
1187
1283
  * types are explicit no-ops in `Projection.apply`; invoking the handler and
1188
1284
  * checkpointing their positions preserves continuity.
@@ -1201,13 +1297,13 @@ interface ProjectionBatchResult {
1201
1297
  * redeliveries.
1202
1298
  * - **Malformed envelopes reject loudly.** A missing/empty `eventId`, a
1203
1299
  * missing/invalid `position`, missing `source.aggregateId` /
1204
- * `source.aggregateType`, or an optional event address contradicting its
1300
+ * `source.aggregateType`, or an optional event identity contradicting its
1205
1301
  * authoritative envelope source fails the batch BEFORE anything is applied.
1206
1302
  * The domain event remains persistence-agnostic.
1207
1303
  * - **Competing instances serialize by checkpoint key.** The required
1208
1304
  * {@link ProjectionCheckpointStore.withCheckpointLocks} callback covers the
1209
- * complete load / apply / save critical section for every addressed
1210
- * aggregate. The adapter must lock a key even when its checkpoint row does
1305
+ * complete load / apply / save critical section for every aggregate of
1306
+ * the batch. The adapter must lock a key even when its checkpoint row does
1211
1307
  * not exist yet; a plain row lock is insufficient at genesis. Without that
1212
1308
  * adapter guarantee, only a hard single-projector deployment is safe.
1213
1309
  *
@@ -1231,7 +1327,7 @@ declare class Projector<Evt extends AnyDomainEvent, TCtx = unknown> {
1231
1327
  * per advanced aggregate. Rejects
1232
1328
  * (after rollback) when a handler throws or an envelope carries no
1233
1329
  * valid cursor; the caller's at-least-once redelivery retries the batch.
1234
- * The input must be a complete, ordered feed per aggregate address; an
1330
+ * The input must be a complete, ordered feed per aggregate identity; an
1235
1331
  * event-type-filtered subscription cannot satisfy the cursor contract.
1236
1332
  * An already-aborted signal rejects before validation or transaction setup.
1237
1333
  * In-flight cancellation is forwarded to the transaction scope rather than
@@ -1240,19 +1336,19 @@ declare class Projector<Evt extends AnyDomainEvent, TCtx = unknown> {
1240
1336
  project(events: ReadonlyArray<CommittedDomainEvent<Evt>>, options?: ProjectOptions): Promise<ProjectionBatchResult>;
1241
1337
  /**
1242
1338
  * The wait-for-version query: `true` when this projection has
1243
- * processed the addressed aggregate at least up to `position`. Pass the
1339
+ * processed the given aggregate at least up to `position`. Pass the
1244
1340
  * position of the last event the awaited commit emitted (see
1245
1341
  * {@link ProjectionCheckpointStore.hasReached} for why the full
1246
1342
  * cursor, not just the version).
1247
1343
  */
1248
- hasProcessed(address: AggregateAddress, position: ProjectionPosition): Promise<boolean>;
1344
+ hasProcessed(identity: AggregateIdentity, position: ProjectionPosition): Promise<boolean>;
1249
1345
  /**
1250
1346
  * Rebuild entry point: one transaction that clears this
1251
1347
  * projection's checkpoints and, when the projection provides
1252
1348
  * `truncate`, the read model with them. Replay the source through
1253
1349
  * {@link Projector.project} afterwards. Stop all live consumers for this
1254
1350
  * projection before reset and keep them stopped through catch-up replay;
1255
- * rebuild is not coordinated by the per-address delivery locks.
1351
+ * rebuild is not coordinated by the per-aggregate delivery locks.
1256
1352
  */
1257
1353
  reset(): Promise<void>;
1258
1354
  /**
@@ -1271,291 +1367,6 @@ declare class Projector<Evt extends AnyDomainEvent, TCtx = unknown> {
1271
1367
  toOutboxSink(): OutboxSink<Evt>;
1272
1368
  }
1273
1369
  //#endregion
1274
- //#region src/persistence/repository/identity-map.d.ts
1275
- /**
1276
- * A class reference used as the type key of the identity map. Keying
1277
- * on the CLASS (not a name string) makes collisions impossible by
1278
- * construction: `Restaurant` and `Booking` are different keys even if
1279
- * someone names two aggregates identically across modules, and there
1280
- * is no string-discipline to maintain.
1281
- *
1282
- * `Function & { prototype: TAgg }` carries this alone. The kit's aggregate
1283
- * convention is a **protected constructor** plus static factories, and
1284
- * TypeScript rejects assigning such a class to a construct-signature type, so
1285
- * the prototype witness is what accepts them. It infers `TAgg` as well.
1286
- * Measured: a construct signature beside it changes neither what the type
1287
- * accepts nor what it infers, and it was the last `any` in the published
1288
- * types.
1289
- */
1290
- type AggregateClass<TAgg> = Function & {
1291
- prototype: TAgg;
1292
- };
1293
- /**
1294
- * Per-unit-of-work Identity Map (Fowler, PoEAA): within one operation,
1295
- * one aggregate type+id maps to exactly ONE in-memory instance.
1296
- *
1297
- * This is the shipped implementation of the contract the
1298
- * Repository guide (`docs/guide/repository.md`) places on
1299
- * `AggregatePersistence` implementations: two `findById(id)` calls in the same
1300
- * unit of work MUST return the same instance, because commit-token
1301
- * write registration dedupes by JavaScript object identity. Two instances for
1302
- * one logical aggregate can otherwise produce two tokens, two harvests,
1303
- * and two post-commit lifecycle calls.
1304
- *
1305
- * Storage is two-level (per-type stores created lazily), so
1306
- * `Restaurant:123` and `Booking:123` can never collide: the type key
1307
- * is the aggregate CLASS, not the id alone and not a name string.
1308
- *
1309
- * Repository read-path contract:
1310
- *
1311
- * ```ts
1312
- * async findById(id: OrderId): Promise<Order | undefined> {
1313
- * const cached = this.tracking.identityMap.get(Order, id);
1314
- * if (cached) return cached;
1315
- * // Deleted in this unit of work = gone, even if the physical
1316
- * // delete is deferred and the row is still visible in the tx.
1317
- * if (this.tracking.identityMap.isDeleted(Order, id)) return undefined;
1318
- *
1319
- * const row = await this.loadRow(id);
1320
- * if (!row) return undefined;
1321
- * const order = Order.reconstitute(row.id, row.state, row.version);
1322
- * return this.tracking.trackLoaded(order);
1323
- * }
1324
- * ```
1325
- *
1326
- * Deletion is final within an operation: {@link delete} removes the
1327
- * entry AND records a tombstone, so a later {@link set} of the same
1328
- * type+id throws `AggregateDeletedError`: a second instance of a
1329
- * deleted aggregate can never sneak back into the unit of work, even
1330
- * through a repository whose row delete is deferred.
1331
- *
1332
- * Lifetime is ONE unit of work: the `UnitOfWork` creates a fresh map
1333
- * per `run()` and clears it on close. Never cache across operations;
1334
- * that would silently bypass optimistic concurrency control.
1335
- */
1336
- declare class IdentityMap {
1337
- private readonly _stores;
1338
- private readonly _deleted;
1339
- private _pendingAtRegistration;
1340
- /** The cached instance for type+id, or `undefined` (also after {@link delete}). */
1341
- get<TAgg>(type: AggregateClass<TAgg>, id: Id<string>): TAgg | undefined;
1342
- /** Whether an instance is registered for type+id (false after {@link delete}). */
1343
- has<TAgg>(type: AggregateClass<TAgg>, id: Id<string>): boolean;
1344
- /**
1345
- * Whether type+id was {@link delete}d in this unit of work. The
1346
- * read path checks this BEFORE hydrating and returns `null`, so
1347
- * "deleted in this operation" reads uniformly as not-found,
1348
- * regardless of whether the repository's physical delete already
1349
- * removed the row or is deferred within the transaction. Without
1350
- * the check, a read-only probe of a deleted aggregate would crash
1351
- * in {@link set} for deferred-write repositories and return `null`
1352
- * for immediate-write ones.
1353
- */
1354
- isDeleted<TAgg>(type: AggregateClass<TAgg>, id: Id<string>): boolean;
1355
- /**
1356
- * Registers the hydrated instance for type+id.
1357
- *
1358
- * - Re-registering the SAME instance is a no-op (idempotent).
1359
- * - Registering a DIFFERENT instance for an occupied type+id throws:
1360
- * that is precisely the identity-map violation this class exists
1361
- * to prevent (the repository hydrated twice instead of checking
1362
- * {@link get} first), and letting it pass would double-harvest
1363
- * events downstream.
1364
- * - Registering a type+id that was {@link delete}d in this unit of
1365
- * work throws `AggregateDeletedError`: deletion is final within
1366
- * the operation.
1367
- */
1368
- set<TAgg>(type: AggregateClass<TAgg>, id: Id<string>, aggregate: TAgg): void;
1369
- /**
1370
- * Registered instances that have recorded MORE pending events than they
1371
- * carried when first registered (loaded). Used by the unit of work's
1372
- * end-of-run guard: an aggregate that gained events after load but was
1373
- * never enrolled would silently drop them. A read-only load, or a
1374
- * reconstitution that already carried events, shows no increase and is
1375
- * not reported.
1376
- */
1377
- instancesWithNewPendingEvents(): unknown[];
1378
- /**
1379
- * Takes back a registration WITHOUT a tombstone: the entry is removed
1380
- * only when the stored instance IS the given one, and a later
1381
- * {@link set} of the same type+id stays legal. The Unit of Work calls
1382
- * this when a registration step fails after {@link set} already ran, so
1383
- * the failed instance cannot be served by `findById` as a phantom.
1384
- * This is rollback, not deletion; deletion finality belongs to
1385
- * {@link delete}.
1386
- */
1387
- discard<TAgg>(type: AggregateClass<TAgg>, id: Id<string>, aggregate: TAgg): void;
1388
- /**
1389
- * Removes the entry for type+id and records a tombstone: subsequent
1390
- * {@link get} / {@link has} report absence, and a subsequent
1391
- * {@link set} of the same type+id throws `AggregateDeletedError`.
1392
- * The Unit of Work calls this as part of `repository.remove(aggregate)`;
1393
- * repository adapters receive only the read-only
1394
- * identity-map view.
1395
- */
1396
- delete<TAgg>(type: AggregateClass<TAgg>, id: Id<string>): void;
1397
- /** Empties all stores and tombstones. Called by the unit of work on close. */
1398
- clear(): void;
1399
- }
1400
- //#endregion
1401
- //#region src/persistence/repository/persistence-model.d.ts
1402
- /** Whether a baseline represents an existing row or a pending insert. */
1403
- type PersistenceLifecycle = "loaded" | "new";
1404
- /**
1405
- * Adapter-owned projection and change derivation for one aggregate type.
1406
- *
1407
- * The domain model does not implement this contract. A repository adapter
1408
- * chooses what it persists, how that projection is captured at load, and
1409
- * whether a change set is a partial diff or a full replacement.
1410
- */
1411
- interface PersistenceModel<TAggregate, TBaseline, TChangeSet> {
1412
- /**
1413
- * Captures the adapter's persistence projection at the current moment.
1414
- * Return a detached value or an immutable value object: the Unit of Work
1415
- * retains it as a baseline and cannot make an arbitrary adapter type safe.
1416
- *
1417
- * Capture must be deterministic for an unchanged aggregate: the Unit of
1418
- * Work compares successive captures to detect mutation after write
1419
- * registration. A capture that embeds ambient values (clock reads,
1420
- * random ids) would make every commit look mutated. The default
1421
- * comparison is the package's structural deep equality, which matches
1422
- * `Set` members and `Map` keys by reference (JS `SameValueZero`
1423
- * semantics): a capture that re-materializes object Set members or Map
1424
- * keys on every call must supply {@link captureEquals}.
1425
- *
1426
- * A column that the store owns stays out of the capture, for example an
1427
- * `updatedAt` that the adapter stamps; `flush` writes it. A captured store
1428
- * column pushes a stale value back on the next write, or it marks every
1429
- * row as changed.
1430
- */
1431
- capture(aggregate: TAggregate): TBaseline;
1432
- /**
1433
- * Adapter-owned equality for two captures of the persistence projection.
1434
- * Optional: the default is the package's structural deep equality (Set
1435
- * members and Map keys by reference). Supply it when the capture shape
1436
- * needs domain-specific comparison, for example rebuilt value-object Set
1437
- * members compared by value.
1438
- */
1439
- readonly captureEquals?: (a: TBaseline, b: TBaseline) => boolean;
1440
- /**
1441
- * Derives the adapter's write payload from its own baseline.
1442
- *
1443
- * `baseline` is absent for a new aggregate. `lifecycle` disambiguates that
1444
- * case from an adapter whose loaded baseline type itself admits `undefined`.
1445
- * The returned payload must not share mutable references with the aggregate;
1446
- * it is the exact value later handed to `flush`.
1447
- */
1448
- changes(baseline: TBaseline | undefined, aggregate: TAggregate, lifecycle: PersistenceLifecycle): TChangeSet;
1449
- /** Tells orchestration whether the derived state write is empty. */
1450
- isEmpty(changes: TChangeSet): boolean;
1451
- }
1452
- declare const persistenceBaselineBrand: unique symbol;
1453
- /**
1454
- * Opaque, typed receipt for an adapter-owned persistence baseline.
1455
- *
1456
- * It intentionally exposes no data. The Unit of Work may retain the token and
1457
- * ask the owning adapter capability to derive changes, but cannot branch on or
1458
- * couple itself to the baseline's shape.
1459
- */
1460
- interface PersistenceBaseline<TAggregate, TChangeSet> {
1461
- readonly [persistenceBaselineBrand]: (aggregate: TAggregate) => TChangeSet;
1462
- }
1463
- /** A derived adapter change set plus its adapter-defined emptiness result. */
1464
- interface PersistenceChanges<TChangeSet> {
1465
- readonly value: TChangeSet;
1466
- readonly empty: boolean;
1467
- }
1468
- /** Captures a baseline for an aggregate restored by a repository adapter. */
1469
- declare function capturePersistenceBaseline<TAggregate, TBaseline, TChangeSet>(model: PersistenceModel<TAggregate, TBaseline, TChangeSet>, aggregate: TAggregate): PersistenceBaseline<TAggregate, TChangeSet>;
1470
- /** Creates the explicit no-row baseline for a newly added aggregate. */
1471
- declare function insertPersistenceBaseline<TAggregate, TBaseline, TChangeSet>(model: PersistenceModel<TAggregate, TBaseline, TChangeSet>): PersistenceBaseline<TAggregate, TChangeSet>;
1472
- /**
1473
- * Captures the aggregate's current adapter projection using the capability
1474
- * carried by an existing baseline. Used to seal persistence-last registration.
1475
- */
1476
- declare function recapturePersistenceBaseline<TAggregate, TChangeSet>(baseline: PersistenceBaseline<TAggregate, TChangeSet>, aggregate: TAggregate): PersistenceBaseline<TAggregate, TChangeSet>;
1477
- /**
1478
- * Recaptures the adapter projection and reports whether it drifted from the
1479
- * baseline's stored capture, using the model's `captureEquals` when supplied
1480
- * and structural deep equality otherwise.
1481
- *
1482
- * This, not `changes()`/`isEmpty()`, is the mutation detector: the
1483
- * `PersistenceModel` contract explicitly permits a full-replacement change
1484
- * set whose `isEmpty` is never true, so a non-empty change set proves
1485
- * nothing about mutation. Comparing capture to capture asks the honest
1486
- * question independent of the model's diffing strategy. A `"new"` lifecycle
1487
- * baseline has no stored capture and never reports drift.
1488
- */
1489
- declare function persistenceProjectionDrifted<TAggregate, TChangeSet>(baseline: PersistenceBaseline<TAggregate, TChangeSet>, aggregate: TAggregate): boolean;
1490
- /** Derives a typed adapter change set without exposing the stored baseline. */
1491
- declare function derivePersistenceChanges<TAggregate, TChangeSet>(baseline: PersistenceBaseline<TAggregate, TChangeSet>, aggregate: TAggregate): PersistenceChanges<TChangeSet>;
1492
- //#endregion
1493
- //#region src/application/unit-of-work/persistence-contract.d.ts
1494
- /** The explicit persistence intent registered for one tracked aggregate. */
1495
- type AggregateWriteIntent = "add" | "update" | "remove";
1496
- /** Read-only Identity Map operations available to repository adapters. */
1497
- type UnitOfWorkIdentityMap = Pick<IdentityMap, "get" | "has" | "isDeleted">;
1498
- /**
1499
- * Repository-specific tracking capability handed only to its adapter.
1500
- *
1501
- * Read paths call {@link RepositoryTracking.trackLoaded} before returning a
1502
- * restored aggregate.
1503
- * Write methods exposed to application code are replaced by Unit-of-Work-owned
1504
- * `add`, `update`, and `remove` registrations, so an adapter implementation of
1505
- * those methods cannot perform durable I/O early or skip event harvesting.
1506
- *
1507
- * Contract for repository implementations:
1508
- * - `findById(id)` checks `identityMap.get` BEFORE hydrating, treats
1509
- * `identityMap.isDeleted` as not-found (`undefined`), and returns
1510
- * `tracking.trackLoaded(aggregate)` after hydration. This captures the
1511
- * expected version before application code can mutate the instance.
1512
- * - Adapter objects do not need lifecycle methods; the facade installs the
1513
- * Unit-of-Work-owned `add`, `update` unless the definition is append-only,
1514
- * and `remove` with `physicalRemoval`. If a concrete adapter has a method
1515
- * named `add`, `update`, or `remove` anyway, the facade masks it, installed
1516
- * or not.
1517
- * - Other repository methods are reads. A custom method that performs a write
1518
- * would bypass the Unit of Work and violates the adapter contract.
1519
- */
1520
- interface RepositoryTracking<TAggregate extends Aggregate<Id<string>, AnyDomainEvent>> {
1521
- /**
1522
- * Registers an aggregate restored by a repository before returning it to
1523
- * application code. The Unit of Work identity-maps the instance and captures
1524
- * its current version as the optimistic-concurrency expectation.
1525
- */
1526
- trackLoaded(aggregate: TAggregate): TAggregate;
1527
- /**
1528
- * Read-only view of the per-operation Identity Map (Fowler): one aggregate type+id,
1529
- * one in-memory instance. Created fresh per `run()`, cleared on
1530
- * close; accessing it after close throws
1531
- * {@link TransactionClosedError}.
1532
- */
1533
- readonly identityMap: UnitOfWorkIdentityMap;
1534
- }
1535
- /**
1536
- * Immutable adapter input for one registered aggregate write.
1537
- *
1538
- * `expectedVersion` is captured when a loaded aggregate joins the Unit of
1539
- * Work and is absent for `add`. `version`, `changes`, and `events` describe
1540
- * the exact moment at which the application registered its write intent.
1541
- * Adapters must use the expected/current version pair for their OCC predicate
1542
- * and must not read mutable write state back from an aggregate reference.
1543
- *
1544
- * The predicate itself is adapter code. The compare-and-set must run in the
1545
- * store's own write statement. The kit does not know the store, so it cannot
1546
- * write that statement. The kit owns the version pair and
1547
- * {@link ConcurrencyConflictError}; the repository contract suite proves the
1548
- * predicate.
1549
- */
1550
- interface AggregatePersistenceWrite<TAggregate extends Aggregate<Id<string>, AnyDomainEvent>, TChangeSet> {
1551
- readonly intent: AggregateWriteIntent;
1552
- readonly aggregateId: TAggregate["id"];
1553
- readonly expectedVersion: Version | undefined;
1554
- readonly version: Version;
1555
- readonly changes: PersistenceChanges<TChangeSet>;
1556
- readonly events: TAggregate["pendingEvents"];
1557
- }
1558
- //#endregion
1559
1370
  //#region src/application/unit-of-work/errors.d.ts
1560
1371
  /**
1561
1372
  * Thrown when `UnitOfWork.run()` is called while the same instance is
@@ -1579,10 +1390,13 @@ declare class NestedUnitOfWorkError extends KitWiringError<"NESTED_UNIT_OF_WORK"
1579
1390
  constructor();
1580
1391
  }
1581
1392
  /**
1582
- * Thrown when the unit-of-work context is used after `run()` has
1583
- * settled: reading `context.repositories`, calling an adapter-held
1584
- * `tracking.trackLoaded`, or using a repository facade after the transaction
1585
- * has committed or rolled back.
1393
+ * Thrown when the unit-of-work context is used after the unit of work closed
1394
+ * it: reading `context.repositories`, calling an adapter-held
1395
+ * `tracking.trackLoaded`, or using a repository facade after the flush of its
1396
+ * attempt, while the transaction commits, or after it committed or rolled
1397
+ * back. An `add`, `update`, or `remove` between the start of the flush and the
1398
+ * last check before the commit fails the attempt with `AggregateTrackingError`
1399
+ * instead.
1586
1400
  *
1587
1401
  * Use-after-close is a programming bug (typically a leaked context
1588
1402
  * reference or a fire-and-forget promise outliving the callback), so
@@ -1599,11 +1413,27 @@ declare class TransactionClosedError extends KitWiringError<"TRANSACTION_CLOSED"
1599
1413
  readonly operation: string;
1600
1414
  constructor(operation: string);
1601
1415
  }
1416
+ /** Why a repository factory result cannot become a facade. */
1417
+ type InvalidRepositoryAdapterReason = "not_an_object" | "defines_lifecycle_operation";
1418
+ /** Constructor options for {@link InvalidRepositoryAdapterError}. */
1419
+ type InvalidRepositoryAdapterErrorOptions = {
1420
+ readonly repository: string;
1421
+ readonly reason: "not_an_object";
1422
+ /** The `typeof` of the value that the factory returned, or `null`. */
1423
+ readonly receivedType: string;
1424
+ } | {
1425
+ readonly repository: string;
1426
+ readonly reason: "defines_lifecycle_operation";
1427
+ /** The lifecycle member that the adapter defines. */
1428
+ readonly operation: AggregateWriteIntent;
1429
+ };
1602
1430
  /** A repository factory returned a value that cannot be wrapped as a facade. */
1603
1431
  declare class InvalidRepositoryAdapterError extends KitWiringError<"INVALID_REPOSITORY_ADAPTER"> {
1604
1432
  readonly repository: string;
1605
- readonly receivedType: string;
1606
- constructor(repository: string, receivedType: string);
1433
+ readonly reason: InvalidRepositoryAdapterReason;
1434
+ readonly receivedType: string | undefined;
1435
+ readonly operation: AggregateWriteIntent | undefined;
1436
+ constructor(options: InvalidRepositoryAdapterErrorOptions);
1607
1437
  }
1608
1438
  /** A Unit of Work received repository wiring that bypassed {@link defineRepository}. */
1609
1439
  declare class InvalidRepositoryDefinitionError extends KitWiringError<"INVALID_REPOSITORY_DEFINITION"> {
@@ -1612,34 +1442,38 @@ declare class InvalidRepositoryDefinitionError extends KitWiringError<"INVALID_R
1612
1442
  }
1613
1443
  /** A repository's persistence-error policy threw or returned a non-kit error. */
1614
1444
  declare class RepositoryErrorMappingFailedError extends KitWiringError<"REPOSITORY_ERROR_MAPPING_FAILED"> {
1615
- readonly aggregateId: string;
1445
+ readonly identity: AggregateIdentity;
1616
1446
  readonly intent: AggregateWriteIntent;
1617
1447
  readonly mapperCause: unknown;
1618
- constructor(options: {
1619
- readonly aggregateId: string;
1620
- readonly intent: AggregateWriteIntent;
1621
- readonly persistenceError: unknown;
1622
- readonly mapperError: unknown;
1623
- });
1448
+ constructor(options: RepositoryErrorMappingFailedErrorOptions);
1449
+ }
1450
+ /** Constructor options for {@link RepositoryErrorMappingFailedError}. */
1451
+ interface RepositoryErrorMappingFailedErrorOptions {
1452
+ /** The aggregate the error names. */
1453
+ readonly identity: AggregateIdentity;
1454
+ readonly intent: AggregateWriteIntent;
1455
+ /** The store failure the mapper was translating. */
1456
+ readonly persistenceError: unknown;
1457
+ /** The failure of the mapper itself. */
1458
+ readonly mapperError: unknown;
1624
1459
  }
1625
1460
  /** What is wrong with the store statements that build a flush. */
1626
- type FlushStatementReason = "statement_absent" | "no_row_count" | "no_expected_version" | "duplicate_check_failed";
1461
+ type FlushStatementReason = "statement_absent" | "no_row_count" | "no_expected_version" | "no_version" | "duplicate_check_failed";
1627
1462
  /**
1628
1463
  * A deterministic defect in the store statements that build a flush.
1629
1464
  *
1630
1465
  * This is a wiring error, not a persistence failure: the statements cannot
1631
1466
  * run the write the Unit of Work registered, and a retry repeats the same
1632
- * outcome. {@link versionedFlush} raises it during the commit phase, so the
1633
- * repository's `mapError` receives it like a store failure. A mapper must
1634
- * return an `InfrastructureError`. So the use case receives the mapper's own
1635
- * error, and the reason stays in the cause chain.
1467
+ * outcome. The commit phase hands it to the caller unchanged, never to the
1468
+ * repository's `mapError`, because a mapper returns an `InfrastructureError`
1469
+ * and would relabel the defect as a store failure.
1636
1470
  */
1637
1471
  declare class InvalidFlushStatementError extends KitWiringError<"INVALID_FLUSH_STATEMENT"> {
1638
- readonly aggregateType: string;
1639
- readonly aggregateId: string;
1640
- readonly intent: AggregateWriteIntent;
1472
+ readonly identity: InvalidFlushStatementErrorOptions["identity"];
1473
+ /** The write, or `null` when the code that found the defect does not know it. */
1474
+ readonly intent: AggregateWriteIntent | null;
1641
1475
  readonly reason: FlushStatementReason;
1642
- /** What the statement returned instead of a row count. */
1476
+ /** The value that the flush received in place of a valid one. */
1643
1477
  readonly received: string | undefined;
1644
1478
  /** The failure of `isDuplicate`, when the classifier itself threw. */
1645
1479
  readonly classifierCause: unknown;
@@ -1647,9 +1481,9 @@ declare class InvalidFlushStatementError extends KitWiringError<"INVALID_FLUSH_S
1647
1481
  }
1648
1482
  /** The fields that describe one defect of the flush statements. */
1649
1483
  interface InvalidFlushStatementErrorOptions {
1650
- readonly aggregateType: string;
1651
- readonly aggregateId: string;
1652
- readonly intent: AggregateWriteIntent;
1484
+ /** The aggregate the error names. */
1485
+ readonly identity: AggregateIdentity;
1486
+ readonly intent?: AggregateWriteIntent | null;
1653
1487
  readonly reason: FlushStatementReason;
1654
1488
  readonly received?: string;
1655
1489
  /** The store failure that the flush was handling, kept for diagnosis. */
@@ -1657,7 +1491,7 @@ interface InvalidFlushStatementErrorOptions {
1657
1491
  readonly classifierCause?: unknown;
1658
1492
  }
1659
1493
  /** Why an aggregate lifecycle registration was rejected. */
1660
- type AggregateTrackingReason = "not_loaded" | "loaded_as_new" | "different_repository" | "conflicting_intent" | "mutated_after_registration";
1494
+ type AggregateTrackingReason = "not_loaded" | "loaded_as_new" | "different_repository" | "conflicting_intent" | "mutated_after_registration" | "registered_during_flush" | "identity_already_tracked";
1661
1495
  /**
1662
1496
  * A deterministic violation of the Unit of Work's aggregate lifecycle.
1663
1497
  *
@@ -1666,13 +1500,23 @@ type AggregateTrackingReason = "not_loaded" | "loaded_as_new" | "different_repos
1666
1500
  * cannot execute truthfully. Retrying the same callback cannot repair it.
1667
1501
  */
1668
1502
  declare class AggregateTrackingError extends KitWiringError<"AGGREGATE_TRACKING"> {
1669
- readonly aggregateId: string;
1503
+ readonly identity: AggregateIdentity;
1670
1504
  readonly operation: AggregateWriteIntent | "load" | "commit";
1671
1505
  readonly reason: AggregateTrackingReason;
1672
- readonly registeredIntent?: AggregateWriteIntent | undefined;
1673
- constructor(aggregateId: string, operation: AggregateWriteIntent | "load" | "commit", reason: AggregateTrackingReason, registeredIntent?: AggregateWriteIntent | undefined, options?: {
1674
- readonly appendOnly?: boolean;
1675
- });
1506
+ readonly registeredIntent: AggregateWriteIntent | undefined;
1507
+ constructor(options: AggregateTrackingErrorOptions);
1508
+ }
1509
+ /** Constructor options for {@link AggregateTrackingError}. */
1510
+ interface AggregateTrackingErrorOptions {
1511
+ /** The aggregate the error names. */
1512
+ readonly identity: AggregateIdentity;
1513
+ /** The registration or phase that failed. */
1514
+ readonly operation: AggregateWriteIntent | "load" | "commit";
1515
+ readonly reason: AggregateTrackingReason;
1516
+ /** The intent registered before, for the reasons that name one. */
1517
+ readonly registeredIntent?: AggregateWriteIntent;
1518
+ /** Whether the repository of the aggregate is append-only. */
1519
+ readonly appendOnly?: boolean;
1676
1520
  }
1677
1521
  /**
1678
1522
  * The unit of work failed AFTER the work callback completed
@@ -1698,17 +1542,21 @@ declare class CommitError extends InfrastructureError<"COMMIT_FAILED"> {
1698
1542
  constructor(cause: unknown);
1699
1543
  }
1700
1544
  /**
1701
- * The work callback threw AND the transaction scope rejected with a
1702
- * DIFFERENT error that does not wrap the callback's error in its cause
1703
- * chain - the strongest available signal that the rollback itself
1704
- * failed. The callback's (primary) error is preserved as `cause`, so
1705
- * cause-chain helpers (`someChainRetryable`, `findInCauseChain`) still
1706
- * see a wrapped `ConcurrencyConflictError` & co.; the scope's error is
1707
- * carried in {@link rollbackCause}.
1708
- *
1709
- * Scopes that rethrow the original error (Drizzle, Prisma do) never
1710
- * produce this; scopes that WRAP the original are detected via the
1711
- * cause chain and passed through unchanged instead.
1545
+ * A step inside the transaction threw, and the transaction scope rejected
1546
+ * with a different error that does not wrap that failure in its cause chain.
1547
+ * This is the strongest available signal that the rollback itself failed.
1548
+ * The step is the work callback, or a step after it and before the commit,
1549
+ * for example the outbox write. The failure inside the transaction is the
1550
+ * `cause`, so cause-chain helpers (`someChainRetryable`, `findInCauseChain`)
1551
+ * still see a wrapped `ConcurrencyConflictError` & co. The scope's error is
1552
+ * in {@link rollbackCause}. A wiring error as that failure is the cause too,
1553
+ * so both facts stay visible.
1554
+ *
1555
+ * A scope that rethrows the failure (Drizzle and Prisma do) never produces
1556
+ * this. A scope that wraps the failure is detected through the cause chain.
1557
+ * A wrapped failure of the work passes through unchanged. A wrapped failure
1558
+ * after the work becomes a `CommitError`, or passes through when it is a
1559
+ * wiring error.
1712
1560
  */
1713
1561
  declare class RollbackError extends InfrastructureError<"ROLLBACK_FAILED"> {
1714
1562
  readonly rollbackCause: unknown;
@@ -1856,20 +1704,49 @@ type Then<TChecked, TNext> = unknown extends TChecked ? TNext : TChecked;
1856
1704
  type IsUnion<T, TEach = T> = T extends unknown ? [TEach] extends [T] ? false : true : never;
1857
1705
  /** @inline */
1858
1706
  type PortShapeConstraint<TRepositoryPort> = [Extract<TRepositoryPort, CallableValue>] extends [never] ? true extends IsUnion<TRepositoryPort> ? RepositoryPortViolation<"the port must be one object type, not a union"> : unknown : RepositoryPortViolation<"the port must be an object type, not a function">;
1707
+ /** @inline */
1708
+ type InstalledRegistration<TAggregate extends Aggregate<Id<string>, AnyDomainEvent>> = AggregateWriteRegistration<TAggregate> & PhysicalRemovalRegistration<TAggregate>;
1709
+ /**
1710
+ * Checks a lifecycle member that the port declares: it is required, it
1711
+ * accepts the definition's aggregate, and it returns what the installed
1712
+ * registration returns. An optional member is the trap of a port that
1713
+ * extends a type with `update?` or `remove?`, so it gets its own message.
1714
+ * The return check exists because TypeScript lets a member that returns a
1715
+ * promise or `this` stand in for one that returns void.
1716
+ * @inline
1717
+ */
1718
+ type MemberAcceptsAggregate<TRepositoryPort, TMember extends "add" | "update" | "remove", TAggregate extends Aggregate<Id<string>, AnyDomainEvent>> = undefined extends TRepositoryPort[TMember & keyof TRepositoryPort] ? RepositoryPortViolation<`the port's ${TMember} must not be optional`> : [TRepositoryPort] extends [Pick<InstalledRegistration<TAggregate>, TMember>] ? ReturnsWhatTheRegistrationReturns<ReturnType<Extract<TRepositoryPort[TMember & keyof TRepositoryPort], CallableValue>>, ReturnType<InstalledRegistration<TAggregate>[TMember]>> extends true ? unknown : RepositoryPortViolation<`the port's ${TMember} must return void`> : RepositoryPortViolation<`the port's ${TMember} must accept the definition's aggregate`>;
1719
+ /**
1720
+ * An `any` result would let a caller use a value that the installed
1721
+ * registration never returns, so it does not count as a match.
1722
+ * @inline
1723
+ */
1724
+ type ReturnsWhatTheRegistrationReturns<TDeclared, TInstalled> = 0 extends 1 & TDeclared ? false : [TDeclared] extends [TInstalled] ? true : false;
1859
1725
  /**
1860
- * Checks a lifecycle member that the port declares: it is required, and it
1861
- * accepts the definition's aggregate. An optional member is the trap of a
1862
- * port that extends a type with `update?` or `remove?`, so it gets its own
1863
- * message.
1726
+ * What an adapter type may say about `add`, `update`, and `remove`: nothing.
1727
+ * The Unit of Work installs them on the facade, and a raw adapter that can
1728
+ * write would bypass it wherever it leaves the facade. As a bound on the
1729
+ * adapter type, the rule also holds for a generic adapter and for each
1730
+ * member of a union.
1864
1731
  * @inline
1865
1732
  */
1866
- type MemberAcceptsAggregate<TRepositoryPort, TMember extends "add" | "update" | "remove", TAggregate extends Aggregate<Id<string>, AnyDomainEvent>> = undefined extends TRepositoryPort[TMember & keyof TRepositoryPort] ? RepositoryPortViolation<`the port's ${TMember} must not be optional`> : [TRepositoryPort] extends [Pick<AggregateWriteRegistration<TAggregate> & PhysicalRemovalRegistration<TAggregate>, TMember>] ? unknown : RepositoryPortViolation<`the port's ${TMember} must accept the definition's aggregate`>;
1733
+ type LifecycleFreeAdapter = {
1734
+ readonly add?: RepositoryPortViolation<"the adapter must not define add; the unit of work installs it">;
1735
+ readonly update?: RepositoryPortViolation<"the adapter must not define update; the unit of work installs it">;
1736
+ readonly remove?: RepositoryPortViolation<"the adapter must not define remove; the unit of work installs it">;
1737
+ };
1738
+ /**
1739
+ * The keys that a port declares by name. A string index signature makes every
1740
+ * name a key, which would count an undeclared `update` or `remove` as present.
1741
+ * @inline
1742
+ */
1743
+ type DeclaredKeys<T> = keyof { [TKey in keyof T as string extends TKey ? never : number extends TKey ? never : symbol extends TKey ? never : TKey]: T[TKey]; };
1867
1744
  /** @inline */
1868
- type AddConstraint<TRepositoryPort, TAggregate extends Aggregate<Id<string>, AnyDomainEvent>> = "add" extends keyof TRepositoryPort ? MemberAcceptsAggregate<TRepositoryPort, "add", TAggregate> : RepositoryPortViolation<"the port must declare add(aggregate): void">;
1745
+ type AddConstraint<TRepositoryPort, TAggregate extends Aggregate<Id<string>, AnyDomainEvent>> = "add" extends DeclaredKeys<TRepositoryPort> ? MemberAcceptsAggregate<TRepositoryPort, "add", TAggregate> : RepositoryPortViolation<"the port must declare add(aggregate): void">;
1869
1746
  /** @inline */
1870
- type UpdateConstraint<TRepositoryPort, TAggregate extends Aggregate<Id<string>, AnyDomainEvent>, TAppendOnly extends boolean> = "update" extends keyof TRepositoryPort ? boolean extends TAppendOnly ? RepositoryPortViolation<"the port declares update, so the definition must not set appendOnly"> : [TAppendOnly] extends [true] ? RepositoryPortViolation<"appendOnly is true, so the port must not declare update"> : MemberAcceptsAggregate<TRepositoryPort, "update", TAggregate> : [TAppendOnly] extends [true] ? unknown : RepositoryPortViolation<"the port declares no update, so the definition must set appendOnly: true">;
1747
+ type UpdateConstraint<TRepositoryPort, TAggregate extends Aggregate<Id<string>, AnyDomainEvent>, TAppendOnly extends boolean> = "update" extends DeclaredKeys<TRepositoryPort> ? boolean extends TAppendOnly ? RepositoryPortViolation<"the port declares update, so the definition must not set appendOnly"> : [TAppendOnly] extends [true] ? RepositoryPortViolation<"appendOnly is true, so the port must not declare update"> : MemberAcceptsAggregate<TRepositoryPort, "update", TAggregate> : [TAppendOnly] extends [true] ? unknown : RepositoryPortViolation<"the port declares no update, so the definition must set appendOnly: true">;
1871
1748
  /** @inline */
1872
- type RemovalConstraint<TRepositoryPort, TAggregate extends Aggregate<Id<string>, AnyDomainEvent>, TRemoval extends boolean> = "remove" extends keyof TRepositoryPort ? [TRemoval] extends [true] ? MemberAcceptsAggregate<TRepositoryPort, "remove", TAggregate> : RepositoryPortViolation<"the port declares remove, so the definition must set physicalRemoval: true"> : [TRemoval] extends [true] ? RepositoryPortViolation<"physicalRemoval is true, so the port must declare remove(aggregate): void"> : unknown;
1749
+ type RemovalConstraint<TRepositoryPort, TAggregate extends Aggregate<Id<string>, AnyDomainEvent>, TRemoval extends boolean> = "remove" extends DeclaredKeys<TRepositoryPort> ? [TRemoval] extends [true] ? MemberAcceptsAggregate<TRepositoryPort, "remove", TAggregate> : RepositoryPortViolation<"the port declares remove, so the definition must set physicalRemoval: true"> : [TRemoval] extends [true] ? RepositoryPortViolation<"physicalRemoval is true, so the port must declare remove(aggregate): void"> : unknown;
1873
1750
  /**
1874
1751
  * Checks the port against every constraint of {@link defineRepository}, one
1875
1752
  * at a time, so the report names the first violated constraint. Resolves to
@@ -1881,7 +1758,7 @@ type RemovalConstraint<TRepositoryPort, TAggregate extends Aggregate<Id<string>,
1881
1758
  */
1882
1759
  type RepositoryPortConstraint<TRepositoryPort, TAggregate extends Aggregate<Id<string>, AnyDomainEvent>, TRemoval extends boolean, TAppendOnly extends boolean> = unknown extends TRepositoryPort ? unknown : Then<PortShapeConstraint<TRepositoryPort>, Then<AddConstraint<TRepositoryPort, TAggregate>, Then<UpdateConstraint<TRepositoryPort, TAggregate, TAppendOnly>, RemovalConstraint<TRepositoryPort, TAggregate, TRemoval>>>>;
1883
1760
  /** @inline */
1884
- type RepositoryDefinitionBuilder<TRepositoryPort extends object> = <TAggregate extends Aggregate<Id<string>, AnyDomainEvent>, TCreate extends (transaction: never, tracking: RepositoryTracking<TAggregate>) => Omit<TRepositoryPort, "add" | "update" | "remove">, TBaseline, TChangeSet, TRemoval extends boolean = false, TAppendOnly extends boolean = false>(definition: RepositoryDefinitionOptions<Parameters<TCreate>[0], TRepositoryPort, TAggregate, TBaseline, TChangeSet, TRemoval, TAppendOnly> & {
1761
+ type RepositoryDefinitionBuilder<TRepositoryPort extends object> = <TAggregate extends Aggregate<Id<string>, AnyDomainEvent>, TCreate extends (transaction: never, tracking: RepositoryTracking<TAggregate>) => Omit<TRepositoryPort, "add" | "update" | "remove"> & LifecycleFreeAdapter, TBaseline, TChangeSet, TRemoval extends boolean = false, TAppendOnly extends boolean = false>(definition: RepositoryDefinitionOptions<Parameters<TCreate>[0], TRepositoryPort, TAggregate, TBaseline, TChangeSet, TRemoval, TAppendOnly> & {
1885
1762
  readonly create: TCreate;
1886
1763
  } & RepositoryPortConstraint<TRepositoryPort, TAggregate, TRemoval, TAppendOnly>) => RepositoryDefinition<Parameters<TCreate>[0], TRepositoryPort, TAggregate, TBaseline, TChangeSet, TRemoval, TAppendOnly>;
1887
1764
  /**
@@ -1891,7 +1768,8 @@ type RepositoryDefinitionBuilder<TRepositoryPort extends object> = <TAggregate e
1891
1768
  * aggregate, persistence, event, and lifecycle types from the adapter wiring.
1892
1769
  * The port must declare `add` for the aggregate. It declares `update` unless
1893
1770
  * the definition sets `appendOnly: true`. If it declares `remove`, the
1894
- * definition must set `physicalRemoval: true`. A violated constraint fails
1771
+ * definition must set `physicalRemoval: true`. The adapter that `create`
1772
+ * returns does not define `add`, `update`, or `remove`. A violated constraint fails
1895
1773
  * the call with a compiler error that names the constraint. The adapter
1896
1774
  * created by the definition implements only the remaining methods because
1897
1775
  * lifecycle writes are installed by the Unit of Work.
@@ -2062,8 +1940,6 @@ type VersionedWrite<TAggregate extends Aggregate<Id<string>, AnyDomainEvent>, TC
2062
1940
  * A statements object that changes later has no effect.
2063
1941
  */
2064
1942
  type VersionedFlushStatements<TCtx, TAggregate extends Aggregate<Id<string>, AnyDomainEvent>, TChangeSet> = {
2065
- /** The aggregate type that the raised errors name. */
2066
- readonly aggregateType: string;
2067
1943
  /**
2068
1944
  * Inserts the rows of a new aggregate and stamps `write.version`. The
2069
1945
  * store's unique constraint on the aggregate id rejects a second insert.
@@ -2120,6 +1996,31 @@ type VersionedFlushStatements<TCtx, TAggregate extends Aggregate<Id<string>, Any
2120
1996
  * `currentVersion` fail here, when the flush is built.
2121
1997
  */
2122
1998
  declare function versionedFlush<TCtx, TAggregate extends Aggregate<Id<string>, AnyDomainEvent>, TChangeSet>(statements: VersionedFlushStatements<TCtx, TAggregate, TChangeSet>): (transaction: TCtx, write: AggregatePersistenceWrite<TAggregate, TChangeSet>) => Promise<void>;
1999
+ /** Options of {@link classifyConcurrencyConflict}. */
2000
+ interface ClassifyConcurrencyConflictOptions<TCtx, TAggregateId extends string> {
2001
+ /** The aggregate of the write whose compare-and-set matched no row. */
2002
+ readonly identity: AggregateIdentity<TAggregateId>;
2003
+ /** The version that the compare-and-set predicate used. */
2004
+ readonly expectedVersion: number;
2005
+ readonly transaction: TCtx;
2006
+ /**
2007
+ * Reads the version that the store holds now, or `undefined` when the
2008
+ * aggregate no longer exists. It is the same statement as the
2009
+ * `currentVersion` of {@link VersionedFlushStatements}.
2010
+ */
2011
+ readonly currentVersion: (transaction: TCtx, aggregateId: TAggregateId) => number | undefined | Promise<number | undefined>;
2012
+ }
2013
+ /**
2014
+ * Builds the conflict of a compare-and-set that matched no row. It reads the
2015
+ * stored version and names the reason of the conflict. The zero row count
2016
+ * already proves the conflict, so the read is diagnostic: a read that fails
2017
+ * becomes `version_unknown`, with the failure as the cause.
2018
+ *
2019
+ * A version read that returns neither a stored version nor `undefined`, and
2020
+ * an expected version that is no version, are defects of the statements. They
2021
+ * throw {@link InvalidFlushStatementError}.
2022
+ */
2023
+ declare function classifyConcurrencyConflict<TCtx, TAggregateId extends string>(options: ClassifyConcurrencyConflictOptions<TCtx, TAggregateId>): Promise<ConcurrencyConflictError>;
2123
2024
  //#endregion
2124
2025
  //#region src/domain/entity/entity.d.ts
2125
2026
  /** A pure invariant check that throws when a candidate state is invalid. */
@@ -2516,6 +2417,7 @@ interface AggregateConfig<TState = unknown> extends EntityConfig<TState> {
2516
2417
  * (emitting any event becomes a compile error).
2517
2418
  */
2518
2419
  declare abstract class BaseAggregate<TState, TId extends Id<string>, TEvent extends AnyDomainEvent = never> extends Entity<TState, TId> implements Aggregate<TId, TEvent> {
2420
+ #private;
2519
2421
  /**
2520
2422
  * The aggregate's domain type as a string, used to populate
2521
2423
  * `aggregateType` on events created via {@link createEvent}.
@@ -2537,6 +2439,12 @@ declare abstract class BaseAggregate<TState, TId extends Id<string>, TEvent exte
2537
2439
  * subclass renaming).
2538
2440
  */
2539
2441
  protected abstract readonly aggregateType: string;
2442
+ /**
2443
+ * The full identity of the aggregate: its declared `aggregateType` and
2444
+ * its `id`, as one frozen value. The id alone is unique only within the
2445
+ * type, so this value names the aggregate unambiguously.
2446
+ */
2447
+ get aggregateIdentity(): AggregateIdentity<TId>;
2540
2448
  private _version;
2541
2449
  /**
2542
2450
  * Version the persistence layer last confirmed for this instance:
@@ -2630,8 +2538,8 @@ declare abstract class BaseAggregate<TState, TId extends Id<string>, TEvent exte
2630
2538
  /**
2631
2539
  * Appends a domain event to the pending list. The event must be minted
2632
2540
  * by a kit constructor; a missing `aggregateId` or `aggregateType` is
2633
- * stamped from this aggregate, and an address that names another
2634
- * aggregate throws {@link MisaddressedEventError} before anything is
2541
+ * stamped from this aggregate, and an aggregate identity that names another
2542
+ * aggregate throws {@link MisattributedEventError} before anything is
2635
2543
  * recorded. Each append is one fact. A decision appended twice becomes
2636
2544
  * two facts with distinct ids. A recorded event that is already pending
2637
2545
  * throws {@link DuplicateEventIdError}, and a list at `maxPendingEvents`
@@ -2663,7 +2571,7 @@ declare abstract class BaseAggregate<TState, TId extends Id<string>, TEvent exte
2663
2571
  protected assertPendingEventLimit(added: number): void;
2664
2572
  /**
2665
2573
  * Appends an event that the caller already passed through
2666
- * {@link addressNewEvent}, {@link assertEventIdsNotPending} and
2574
+ * {@link stampNewEventIdentity}, {@link assertEventIdsNotPending} and
2667
2575
  * {@link assertPendingEventLimit}. `setState()` and `apply()` run the
2668
2576
  * three before the state moves and append afterwards, so each gate
2669
2577
  * runs once per event.
@@ -2676,17 +2584,18 @@ declare abstract class BaseAggregate<TState, TId extends Id<string>, TEvent exte
2676
2584
  */
2677
2585
  protected discardPendingDecisions(): void;
2678
2586
  /**
2679
- * Address discipline for NEW facts, shared by both flavours: a
2587
+ * Aggregate identity discipline for NEW facts, shared by both flavours: a
2680
2588
  * present-but-foreign `aggregateId` / `aggregateType` is a wiring bug and
2681
- * throws {@link MisaddressedEventError}; missing fields are filled in
2682
- * from the aggregate, so a recorded event is always fully addressed and
2683
- * can never fail the harvest or the replay guard later. The mint gate
2589
+ * throws {@link MisattributedEventError}; missing fields are filled in
2590
+ * from the aggregate, so a recorded event always carries its full
2591
+ * aggregate identity and can never fail the harvest or the replay guard
2592
+ * later. The mint gate
2684
2593
  * runs first, so an unminted event fails before anything else. The
2685
2594
  * stamped copy is frozen like the original (payload and metadata are
2686
- * shared, already deep-frozen by the constructors); a fully addressed
2595
+ * shared, already deep-frozen by the constructors); a fully stamped
2687
2596
  * event is returned as is.
2688
2597
  */
2689
- protected addressNewEvent<E extends PendingDomainEvent<TEvent>>(event: E): E;
2598
+ protected stampNewEventIdentity<E extends PendingDomainEvent<TEvent>>(event: E): E;
2690
2599
  /**
2691
2600
  * Mint gate for every recording path: only an event that a kit
2692
2601
  * constructor produced passes. The kit marks two shapes: a recorded
@@ -2808,9 +2717,9 @@ declare abstract class EventSourcedAggregate<TState, TId extends Id<string>, TEv
2808
2717
  * Throws `MissingFoldError` if no fold is declared for `event.type`.
2809
2718
  * Throws `FoldReturnedNoStateError` (wiring) when the fold returns
2810
2719
  * `undefined`, the signature of a fold without a `return`.
2811
- * Throws `MisaddressedEventError` (wiring) when the event carries an
2720
+ * Throws `MisattributedEventError` (wiring) when the event carries an
2812
2721
  * `aggregateId` or `aggregateType` naming a different aggregate;
2813
- * missing address fields are stamped from the aggregate instead.
2722
+ * missing aggregate identity fields are stamped from the aggregate instead.
2814
2723
  *
2815
2724
  * State is not mutated if any step throws: the fold is invoked into
2816
2725
  * a local and only stored once all checks pass.
@@ -2842,16 +2751,16 @@ declare abstract class EventSourcedAggregate<TState, TId extends Id<string>, TEv
2842
2751
  * and the discriminator is resolved via the (statically-sound)
2843
2752
  * `folds` map.
2844
2753
  *
2845
- * Replay address check: a history event that names a DIFFERENT
2754
+ * Replay aggregate identity check: a history event that names a DIFFERENT
2846
2755
  * aggregate id or type is a persisted row that belongs to someone
2847
2756
  * else (a miswired stream read, colliding ids across types, a
2848
2757
  * corrupted store). Throws `ForeignEventError`, an
2849
2758
  * `InfrastructureError`, which PROPAGATES through the replay
2850
2759
  * methods (their `Result` channel is reserved for `DomainError`
2851
2760
  * stream corruption) after the all-or-nothing rollback. History
2852
- * events without the optional address fields pass unchecked (the
2761
+ * events without the optional aggregate identity fields pass unchecked (the
2853
2762
  * fields are optional on the event shape); NEW events are covered
2854
- * by the stricter `addressNewEvent` on the apply path.
2763
+ * by the stricter `stampNewEventIdentity` on the apply path.
2855
2764
  */
2856
2765
  private assertReplayedEventBelongsHere;
2857
2766
  private fold;
@@ -2875,8 +2784,8 @@ declare abstract class EventSourcedAggregate<TState, TId extends Id<string>, TEv
2875
2784
  * a reconstituted aggregate at v=P catching up on M newer events ends at
2876
2785
  * v=P+M. Events carry no stream position, so an overlap with the current
2877
2786
  * version is invisible here: the caller passes only the events after
2878
- * that version and checks the final version against the pinned stream
2879
- * head ({@link ReplayHeadMismatchError}).
2787
+ * that version, and it compares the final version with the version it
2788
+ * expects.
2880
2789
  *
2881
2790
  * The replay target must not carry pending decisions. Factory-vs-load
2882
2791
  * lifecycle is owned by the Unit of Work rather than inferred from an
@@ -2908,10 +2817,10 @@ declare abstract class EventSourcedAggregate<TState, TId extends Id<string>, TEv
2908
2817
  /**
2909
2818
  * Reconstitutes an event-sourced aggregate from one page of history and
2910
2819
  * yields it only on success. `createReplayTarget` builds the instance: a
2911
- * fresh one, or one restored from a snapshot. The instance exists only
2820
+ * fresh one, or one reconstituted from a snapshot. The instance exists only
2912
2821
  * inside this call. A rejected replay therefore leaves the caller with
2913
- * nothing to return by mistake. Later catch-up pages go through
2914
- * `replayHistory` on the value. A `DomainError` from a fold rides the
2822
+ * nothing to return by mistake. A stream read in pages goes through
2823
+ * `reconstituteAggregateFromStreamPages` instead. A `DomainError` from a fold rides the
2915
2824
  * `Result`; wiring errors and a foreign row throw, as in `replayHistory`.
2916
2825
  * The creator runs outside the `Result`: what it throws propagates.
2917
2826
  */
@@ -2931,10 +2840,10 @@ declare abstract class StateStoredAggregate<TState, TId extends Id<string>, TEve
2931
2840
  /**
2932
2841
  * Replaces the state, advances the OCC version, and records the events
2933
2842
  * of the change, in that order. State validation, the event mint gate,
2934
- * the event address check, the pending-identity check, and the pending
2935
- * event limit check run before the change becomes observable, so a
2936
- * rejected decision records nothing and moves nothing. Without events the call is a plain versioned state
2937
- * change.
2843
+ * the aggregate identity check of the event, the pending event-id check,
2844
+ * and the pending event limit check run before the change becomes
2845
+ * observable, so a rejected decision records nothing and moves nothing.
2846
+ * Without events the call is a plain versioned state change.
2938
2847
  */
2939
2848
  protected setState(newState: TState, events?: PendingDomainEvent<TEvent> | readonly PendingDomainEvent<TEvent>[]): void;
2940
2849
  /**
@@ -2947,7 +2856,7 @@ declare abstract class StateStoredAggregate<TState, TId extends Id<string>, TEve
2947
2856
  }
2948
2857
  //#endregion
2949
2858
  //#region src/domain/event/domain-event-errors.d.ts
2950
- type DomainEventValidationCode = "EVENT_ID_REQUIRED" | "EVENT_ID_INVALID" | "EVENT_TYPE_INVALID" | "EVENT_OCCURRED_AT_REQUIRED" | "EVENT_OCCURRED_AT_INVALID" | "EVENT_SCHEMA_VERSION_INVALID" | "EVENT_ADDRESS_INVALID";
2859
+ type DomainEventValidationCode = "EVENT_ID_REQUIRED" | "EVENT_ID_INVALID" | "EVENT_TYPE_INVALID" | "EVENT_OCCURRED_AT_REQUIRED" | "EVENT_OCCURRED_AT_INVALID" | "EVENT_SCHEMA_VERSION_INVALID" | "EVENT_AGGREGATE_IDENTITY_INVALID";
2951
2860
  type DomainEventValidationField = "eventId" | "type" | "occurredAt" | "schemaVersion" | "aggregateId" | "aggregateType";
2952
2861
  /**
2953
2862
  * Stable contract error for malformed domain-event data.
@@ -3679,22 +3588,40 @@ declare function deepEqual(a: unknown, b: unknown): boolean;
3679
3588
  * built-in are dropped. A function or a symbol value throws a raw
3680
3589
  * `DataCloneError`. An Error, a Promise, a WeakMap, or a WeakSet cannot be
3681
3590
  * detached at all. A SharedArrayBuffer and a view over one keep sharing
3682
- * their memory. A Proxy is invisible to the walk and fails inside the
3683
- * clone; that failure is rethrown as a `TypeError` with the cause.
3591
+ * their memory. A Proxy fails in the walk or in the clone; a failure in
3592
+ * the clone is rethrown as a `TypeError` with the cause. An error that a
3593
+ * Proxy trap throws in the walk passes unchanged, so a coded error of the
3594
+ * caller keeps its code.
3595
+ *
3596
+ * The walk reads the graph through property descriptors and walks a Map
3597
+ * or a Set with the built-in iteration, so no accessor and no own iterator
3598
+ * of the state runs. A Proxy runs its traps during the walk. A trap can
3599
+ * change the graph, and an accessor that a trap adds runs during the
3600
+ * clone. A second walk checks the clone, so a value that a trap swapped in
3601
+ * and the content of a built-in whose prototype was replaced are rejected
3602
+ * too. A trap that changes the graph after the first walk can still hide a
3603
+ * value that the copy drops: the walks catch accidents, not a hostile
3604
+ * Proxy. The second walk also follows the steps of the first walk: the kind
3605
+ * of each object and the key of each data property, in walk order. A copy
3606
+ * that differs throws, because a built-in whose prototype was replaced is
3607
+ * a built-in again in the copy and loses its own properties. `subject`
3608
+ * names the state in the messages.
3684
3609
  *
3685
3610
  * Plain objects (from any realm), arrays, Dates, Maps, Sets, bigints, and
3686
3611
  * typed arrays pass. A RegExp passes: pattern and flags survive the clone,
3687
3612
  * and `lastIndex` restores as 0. The scan state of a global or sticky
3688
- * pattern is not domain data. A non-enumerable property on a built-in
3689
- * passes: it is the built-in's own machinery (`lastIndex`), not data. A
3690
- * non-enumerable symbol key passes anywhere: it is metadata by convention.
3613
+ * pattern is not domain data. On a built-in, the mutator shadows of a deep
3614
+ * freeze, the `lastIndex` of a RegExp, and the `length` of a boxed String
3615
+ * pass: they are machinery, not data. Every other non-enumerable property
3616
+ * throws. A non-enumerable symbol key passes anywhere: it is metadata by
3617
+ * convention.
3691
3618
  *
3692
3619
  * The concrete entity uses it for a detached read DTO of a plain-data
3693
3620
  * state. The snapshot model uses it for the captured DTO and the restored
3694
3621
  * state. A state that carries a class-based child is mapped to plain data
3695
3622
  * first, in the entity or in the model.
3696
3623
  */
3697
- declare function detachState<T>(state: T): T;
3624
+ declare function detachState<T>(state: T, subject?: string): T;
3698
3625
  //#endregion
3699
3626
  //#region src/messaging/event-bus/errors.d.ts
3700
3627
  /**
@@ -4016,7 +3943,7 @@ interface IntegrationMessageContent<TType extends string, TPayload extends JsonV
4016
3943
  interface IntegrationMessage<TType extends string = string, TPayload extends JsonValue = JsonValue, TMetadata extends JsonObject = JsonObject> extends IntegrationMessageContent<TType, TPayload, TMetadata> {
4017
3944
  readonly messageId: string;
4018
3945
  readonly occurredAt: string;
4019
- readonly source: AggregateAddress;
3946
+ readonly source: AggregateIdentity;
4020
3947
  readonly position: CommitPosition;
4021
3948
  }
4022
3949
  /** Maps a private domain event to its explicit public message schema. */
@@ -4084,7 +4011,8 @@ interface InMemoryOutboxOptions {
4084
4011
  * candidate commit position) retained for idempotent `add` retries and
4085
4012
  * collision detection. Older receipts are evicted in dispatch order; a later
4086
4013
  * candidate behind its source head then rejects instead of rewinding the
4087
- * cursor.
4014
+ * cursor. A retry of an event at its source head still dedupes, because the
4015
+ * source cursor names that event.
4088
4016
  * Default `10_000`.
4089
4017
  */
4090
4018
  maxRetainedDispatchedEventIds?: number;
@@ -4103,12 +4031,16 @@ interface InMemoryOutboxOptions {
4103
4031
  * recent-dispatch receipt cache keeps retries idempotent after acknowledgement.
4104
4032
  * Re-adding a pending event refreshes the stored commit envelope while the
4105
4033
  * delivery attempt count survives. Its commit sequence and size remain
4106
- * immutable; only this transaction-unaware adapter may move a still-pending
4107
- * event to another aggregate version after an outer rollback leaked the first
4108
- * add. Dead-lettered and acknowledged retries must match the complete original
4109
- * candidate receipt. Reusing an `eventId` for another source or commit position
4034
+ * immutable. Only this in-memory adapter may move a still-pending event to
4035
+ * another aggregate version. Without an `InMemoryTransactionScope`, it keeps
4036
+ * the first add of a rolled-back attempt. Dead-lettered and acknowledged
4037
+ * retries must match the complete original candidate receipt. Reusing an `eventId` for another source or commit position
4110
4038
  * throws {@link EventHarvestError} while the pending, dead-letter, or bounded
4111
- * dispatched receipt still proves the collision. Insertion order is preserved:
4039
+ * dispatched receipt still proves the collision. `add` also throws
4040
+ * {@link EventHarvestError} for a malformed candidate: a part that is not an
4041
+ * object, an `eventId` or `type` that is not an own string data property, a
4042
+ * source field that is not a string, or a position that is not a valid
4043
+ * commit position. Insertion order is preserved:
4112
4044
  * `getPending` returns records in commit order, as the port contract requires.
4113
4045
  *
4114
4046
  * Dispatch tracking: `markFailed` increments the record's attempt count
@@ -4118,7 +4050,9 @@ interface InMemoryOutboxOptions {
4118
4050
  * inverse of `deadLetters()`); `markDispatched` acks pending AND
4119
4051
  * dead-lettered records (manual redelivery then ack).
4120
4052
  * To link future eventful commits, the implementation also retains one
4121
- * source cursor per qualified aggregate after dispatch. Consequently a
4053
+ * source cursor per qualified aggregate after dispatch. `endEventSources`
4054
+ * marks the cursor of a removed aggregate as ended, and a new event of that
4055
+ * source then throws {@link EventHarvestError}. Consequently a
4122
4056
  * long-lived instance is bounded only when `maxRecords` and `maxSources` are
4123
4057
  * configured, plus `maxRetainedDispatchedEventIds`; use a durable adapter with
4124
4058
  * an explicit source-head lifecycle and an event-id unique key for unbounded
@@ -4132,12 +4066,21 @@ interface InMemoryOutboxOptions {
4132
4066
  * that are never `markDispatched` accumulate until `maxRecords` rejects a new
4133
4067
  * add, or without that option grow unbounded. For a deliberate no-delivery
4134
4068
  * setup use {@link outboxWriterAcceptingEventLoss} instead. Sharper still:
4135
- * events `add()`ed inside a transaction that later rolls back are NOT
4136
- * removed (the Map knows nothing about your scope's rollback). Tests
4137
- * that assert rollback purity need an outbox that participates in the
4138
- * test store's transactional semantics; see the reference adapter at
4139
- * https://github.com/shi-rudo/ddd-kit-ts/blob/main/src/testing/repository-contract.test.ts
4140
- * (repo-only, not shipped to npm).
4069
+ * on its own, the outbox knows nothing about your scope's rollback. Events
4070
+ * `add()`ed inside a transaction that later rolls back stay, and a source
4071
+ * that `endEventSources` ended inside such a transaction stays ended: the
4072
+ * outbox then rejects every later event of that aggregate, also on the retry
4073
+ * of a `RetryingTransactionScope`. For tests that roll back or retry,
4074
+ * register the outbox with an `InMemoryTransactionScope`. A rollback then
4075
+ * returns the outbox to its state at the start of the attempt.
4076
+ *
4077
+ * A relay reads only committed records. While a transaction is open,
4078
+ * `getPending` returns a record that the transaction wrote as it was
4079
+ * committed at the first write, with its current attempts. It skips a record
4080
+ * that was not pending at that write, such as a new or a requeued record. A
4081
+ * rollback also undoes an acknowledgement or a failure report that a
4082
+ * dispatcher made while the transaction was open. The dispatcher then
4083
+ * delivers that record again.
4141
4084
  *
4142
4085
  * @example
4143
4086
  * ```ts
@@ -4155,13 +4098,20 @@ interface InMemoryOutboxOptions {
4155
4098
  * });
4156
4099
  * ```
4157
4100
  */
4158
- declare class InMemoryOutbox<Evt extends AnyDomainEvent> implements DispatchTrackingOutbox<Evt> {
4101
+ declare class InMemoryOutbox<Evt extends AnyDomainEvent> implements DispatchTrackingOutbox<Evt>, InMemoryTransactionParticipant {
4159
4102
  private readonly pending;
4160
4103
  private readonly dead;
4161
4104
  /** Latest eventful commit and its predecessor per qualified source. */
4162
4105
  private readonly sourceCursors;
4106
+ /** Keys of source cursors whose aggregate was removed. */
4107
+ private readonly endedSourceKeys;
4163
4108
  /** Bounded insertion-ordered receipts for exact retries after acknowledgement. */
4164
4109
  private readonly dispatchedEventIds;
4110
+ /**
4111
+ * The committed pending record of each event id that the open transaction
4112
+ * wrote, captured at its first write. `undefined` marks an id without one.
4113
+ */
4114
+ private committedVersions;
4165
4115
  private readonly maxDeliveryAttempts;
4166
4116
  private readonly maxRetainedDispatchedEventIds;
4167
4117
  private readonly maxRecords;
@@ -4173,6 +4123,36 @@ declare class InMemoryOutbox<Evt extends AnyDomainEvent> implements DispatchTrac
4173
4123
  private assertBatchPositionIntegrity;
4174
4124
  getPending(limit?: number): Promise<ReadonlyArray<OutboxRecord<Evt>>>;
4175
4125
  markDispatched(dispatchIds: ReadonlyArray<string>): Promise<void>;
4126
+ /**
4127
+ * Records the state that a rollback of an `InMemoryTransactionScope`
4128
+ * returns to: pending and dead-letter records, receipts, source cursors,
4129
+ * and ended sources, in their order. Until the transaction ends,
4130
+ * `getPending` returns the committed record of each event id that the
4131
+ * transaction writes.
4132
+ */
4133
+ beginTransaction(): InMemoryTransaction;
4134
+ /** A record that a dispatcher removed is no longer pending in the committed state. */
4135
+ private forgetCommittedVersion;
4136
+ private recordCommittedVersion;
4137
+ endEventSources(sources: ReadonlyArray<AggregateIdentity>): Promise<void>;
4138
+ /**
4139
+ * Rejects a new event of an ended source above its head. An exact retry of
4140
+ * a stored event of an ended source stays a retry; the caller skips
4141
+ * retries at the source head before this check. The stale-head, commit
4142
+ * size, and position checks reject a candidate below the head or at a
4143
+ * position that another event owns, and their messages name the
4144
+ * re-created identity as a cause.
4145
+ */
4146
+ private assertSourceNotEnded;
4147
+ /**
4148
+ * Event ids of the batch that the source head names at their position
4149
+ * although no receipt, pending record, or dead letter remains: events
4150
+ * that were dispatched and whose receipt was evicted. They are decided
4151
+ * against the heads before the batch, so their place in the batch does
4152
+ * not matter. Their receipts are restored after the batch.
4153
+ */
4154
+ private retriesAtSourceHead;
4155
+ private recordedAtSourceHead;
4176
4156
  private rememberDispatched;
4177
4157
  markFailed(dispatchId: string, error?: unknown): Promise<DeadLetterRecord<Evt> | undefined>;
4178
4158
  deadLetters(): Promise<ReadonlyArray<DeadLetterRecord<Evt>>>;
@@ -4196,29 +4176,204 @@ interface InMemoryEventStoreOptions {
4196
4176
  * `InMemoryCapacityExceededError`; histories are never silently evicted.
4197
4177
  * Implements the full port contract: expectedVersion-guarded appends
4198
4178
  * (throwing `ConcurrencyConflictError` on mismatch), atomic rejected
4199
- * appends, explicit missing/existing stream state with the actual head,
4179
+ * appends, explicit absent/existing stream state with the actual head,
4200
4180
  * append-order reads, mandatory page bounds, and `(fromVersion, toVersion]`
4201
- * slicing. Invalid limits or positions reject with `RangeError`.
4181
+ * slicing. Invalid limits or positions reject with `RangeError`. A read
4182
+ * with an aborted `signal` rejects with its `reason`.
4202
4183
  *
4203
4184
  * For production, back the port with a durable store whose append and
4204
4185
  * the aggregate transaction share atomicity (a table with a
4205
4186
  * `(aggregate_type, aggregate_id, position)` unique key inside the same
4206
4187
  * transaction, or a dedicated event store). Same caveat as
4207
- * `InMemoryOutbox`: this class
4208
- * lives in memory only and knows nothing about your `TransactionScope`
4209
- * rollbacks; events appended inside a transaction that later rolls back
4210
- * are NOT removed. The event-sourced repository contract suite's
4211
- * reference environment shows the snapshot/restore pattern for
4212
- * rollback-pure in-memory testing.
4188
+ * `InMemoryOutbox`: this class lives in memory only. On its own, it knows
4189
+ * nothing about your `TransactionScope` rollbacks, so events appended inside
4190
+ * a transaction that later rolls back stay. Register the store with an
4191
+ * `InMemoryTransactionScope` for tests that roll back or retry.
4213
4192
  */
4214
- declare class InMemoryEventStore<Evt extends AnyDomainEvent> implements EventStore<Evt> {
4193
+ declare class InMemoryEventStore<Evt extends AnyDomainEvent> implements EventStore<Evt>, InMemoryTransactionParticipant {
4215
4194
  private readonly streams;
4216
4195
  private readonly maxStreams;
4217
4196
  private readonly maxEvents;
4218
4197
  private totalEvents;
4219
4198
  constructor(options?: InMemoryEventStoreOptions);
4220
- append(stream: AggregateAddress, events: ReadonlyArray<Evt>, options: EventStoreAppendOptions): Promise<void>;
4221
- readStream(stream: AggregateAddress, options: ReadStreamOptions): Promise<StreamReadResult<Evt>>;
4199
+ /**
4200
+ * Records the state that a rollback of an `InMemoryTransactionScope`
4201
+ * returns to: every stream and the event count.
4202
+ */
4203
+ beginTransaction(): InMemoryTransaction;
4204
+ append(stream: AggregateIdentity, events: ReadonlyArray<Evt>, options: EventStoreAppendOptions): Promise<void>;
4205
+ /**
4206
+ * The stream that an append of `count` events at `expectedVersion`
4207
+ * writes to, or `undefined` for a new stream. Throws when the version
4208
+ * is stale or a capacity would overflow.
4209
+ */
4210
+ private existingStreamForAppend;
4211
+ readStream(stream: AggregateIdentity, options: ReadStreamOptions): Promise<StreamReadResult<Evt>>;
4212
+ }
4213
+ //#endregion
4214
+ //#region src/persistence/event-store/read-stream-pages.d.ts
4215
+ /** Options for {@link readStreamPages}. */
4216
+ interface ReadStreamPagesOptions extends Pick<ReadStreamOptions, "limit" | "fromVersion" | "signal"> {
4217
+ /**
4218
+ * The version a point-in-time read asks for (inclusive, 1-based event
4219
+ * count). Without it, the target version is the head that the first page
4220
+ * reports. A value beyond the head does not clamp: see
4221
+ * {@link pinTargetVersion}. Must be a positive safe integer when present.
4222
+ * Version 0 is the state before the first event, and no replay can end
4223
+ * there.
4224
+ */
4225
+ readonly toVersion?: number;
4226
+ }
4227
+ /**
4228
+ * A stream read with the target version pinned on its first page.
4229
+ *
4230
+ * The first page decides the state of the stream once, in three branches.
4231
+ * An absent stream is `exists: false`. An existing stream whose window lies
4232
+ * outside it is `reachable: false` and carries the actual head. The
4233
+ * remaining branch carries the target version and the pages after the
4234
+ * cursor. The other two branches both carry `reachable: false`, so one
4235
+ * guard narrows to the branch that
4236
+ * {@link reconstituteAggregateFromStreamPages} accepts. The caller decides
4237
+ * what the other two branches mean before the replay.
4238
+ */
4239
+ type StreamPages<Evt extends AnyDomainEvent> = AbsentStreamPages | UnreachableStreamPages | ReachableStreamPages<Evt>;
4240
+ /** The branch of {@link StreamPages} for a stream the store does not hold. */
4241
+ interface AbsentStreamPages {
4242
+ readonly exists: false;
4243
+ readonly reachable: false;
4244
+ }
4245
+ /**
4246
+ * The branch of {@link StreamPages} for a window that lies outside an
4247
+ * existing stream: the cursor lies beyond the target version, or the
4248
+ * target version lies beyond the head ({@link pinTargetVersion}).
4249
+ *
4250
+ * The caller tells the causes apart from its own inputs. A snapshot
4251
+ * version above `lastVersion` means that the snapshot outlived its stream:
4252
+ * discard it and replay from zero. A `toVersion` above `lastVersion` means
4253
+ * that the stream has not reached that version: answer not found and keep
4254
+ * the snapshot. A snapshot version above `toVersion` means that the
4255
+ * snapshot is too new for the request: keep it and replay from zero up to
4256
+ * `toVersion`.
4257
+ */
4258
+ interface UnreachableStreamPages {
4259
+ readonly exists: true;
4260
+ readonly reachable: false;
4261
+ /** The cursor the read started at: `fromVersion`, or `0`. */
4262
+ readonly fromVersion: number;
4263
+ /** The actual stream head on the first page. */
4264
+ readonly lastVersion: number;
4265
+ }
4266
+ /** The branch of {@link StreamPages} that the replay accepts. */
4267
+ interface ReachableStreamPages<Evt extends AnyDomainEvent> extends ReplayableStreamPages<Evt> {
4268
+ readonly exists: true;
4269
+ readonly reachable: true;
4270
+ }
4271
+ /** Options for {@link pinTargetVersion}. */
4272
+ interface PinTargetVersionOptions {
4273
+ /** The cursor of the read: the replay starts after this version. */
4274
+ readonly fromVersion: number;
4275
+ /** The version a point-in-time read asks for. Defaults to `lastVersion`. */
4276
+ readonly toVersion?: number;
4277
+ /** The head of the existing stream: its event count. */
4278
+ readonly lastVersion: number;
4279
+ }
4280
+ /** The verdict of {@link pinTargetVersion}. */
4281
+ type PinnedTargetVersion = {
4282
+ readonly reachable: true;
4283
+ readonly targetVersion: number;
4284
+ } | {
4285
+ readonly reachable: false;
4286
+ };
4287
+ /**
4288
+ * Pins the target version of a replay window on an existing stream, or
4289
+ * reports the window as unreachable.
4290
+ *
4291
+ * The target version is `toVersion` when given, else `lastVersion`. The
4292
+ * window is unreachable when `fromVersion` lies beyond the target version,
4293
+ * or the target version lies beyond `lastVersion`. The call never clamps
4294
+ * such a window to the head, so a request for version 10 of a stream that
4295
+ * ends at 7 never loads the latest state by accident.
4296
+ *
4297
+ * This is the decision `readStreamPages` makes on its first page. An
4298
+ * adapter that pages on its own makes it with this call, then hands its
4299
+ * pages to `reconstituteAggregateFromStreamPages`. Values that are not safe
4300
+ * integers, a negative `fromVersion`, and a `toVersion` or `lastVersion`
4301
+ * below 1 reject with `RangeError`: an existing stream holds at least one
4302
+ * event, and no replay can end at version 0.
4303
+ */
4304
+ declare function pinTargetVersion(options: PinTargetVersionOptions): PinnedTargetVersion;
4305
+ /**
4306
+ * Reads one stream in bounded pages up to a pinned target version.
4307
+ *
4308
+ * The call reads the first page. That page decides existence and reports
4309
+ * the head. The call then makes the window decision of
4310
+ * {@link pinTargetVersion}: the target version is `toVersion` when given,
4311
+ * else the head, and a window outside the stream is unreachable.
4312
+ *
4313
+ * The first iteration of `pages` yields the first page that the call read
4314
+ * and then reads the continuation pages, one page at a time. Every later
4315
+ * iteration reads all pages from the store again, so no two iterations
4316
+ * share an event object. Each of these reads passes the target version as
4317
+ * `toVersion` and starts after the events that the earlier pages
4318
+ * returned. Streams are append-only, so an iteration yields one stable
4319
+ * prefix even when another writer appends during the replay.
4320
+ *
4321
+ * The call checks every page against the `readStream` contract and throws
4322
+ * {@link InvalidEventStreamPageError} for a page that breaks it: a head
4323
+ * that is not a safe integer of at least 1, an empty page while events
4324
+ * remain in the window, a page with more events than its window has left
4325
+ * or than `limit`, and a continuation page that reports the stream absent
4326
+ * or a head below the head of the first page.
4327
+ *
4328
+ * Invalid options reject with `RangeError` before any page is read:
4329
+ * `limit` and `toVersion` must be positive safe integers, `fromVersion` a
4330
+ * non-negative one. The call passes `signal` to every page read, and it
4331
+ * checks the signal before each page read as well. An aborted signal
4332
+ * rejects with its `reason`.
4333
+ */
4334
+ declare function readStreamPages<Evt extends AnyDomainEvent>(reader: EventStreamReader<Evt>, stream: AggregateIdentity, options: ReadStreamPagesOptions): Promise<StreamPages<Evt>>;
4335
+ //#endregion
4336
+ //#region src/persistence/repository/adapters/in-memory-transaction-scope.d.ts
4337
+ /**
4338
+ * A {@link TransactionScope} for tests and demos that gives in-memory stores
4339
+ * a rollback. Register every store that the work writes inside the
4340
+ * transaction. When the work fails, each registered store undoes the writes
4341
+ * of the attempt, so the retry of a `RetryingTransactionScope` does not see
4342
+ * them. Each store decides what its rollback undoes, and its documentation
4343
+ * says so.
4344
+ *
4345
+ * **One transaction at a time.** A store cannot tell which of two open
4346
+ * transactions a write belongs to. The scope therefore runs its transactions
4347
+ * one after the other, in call order. A queued transaction stops its wait
4348
+ * when its abort signal fires. Work that waits inside a transaction for
4349
+ * another transaction of the same scope never finishes, because the inner
4350
+ * transaction waits for the outer one. Only the abort signal of the inner
4351
+ * transaction ends that wait. A database with only one connection behaves
4352
+ * the same way. Use a database with real isolation to test concurrent
4353
+ * transactions.
4354
+ *
4355
+ * **Code outside a transaction.** A dispatcher, a deadline processor, and a
4356
+ * `hasReached` check run outside the transactions. Outbox `getPending`,
4357
+ * deadline `due`, and checkpoint `hasReached` read only committed writes.
4358
+ * Other reads also see the writes of an open transaction. A store that
4359
+ * restores its whole state on rollback also undoes the writes that code
4360
+ * outside the transaction made meanwhile. An example is an acknowledgement
4361
+ * of an outbox dispatcher. The dispatcher then delivers the record again,
4362
+ * which the at-least-once contract allows.
4363
+ *
4364
+ * **A store belongs to one scope.** A scope works like one in-memory
4365
+ * database, so register all stores of a test with one scope. A second scope
4366
+ * with a registered store throws at construction, because the rollback of
4367
+ * one scope would undo a commit of the other.
4368
+ *
4369
+ * A store that is not registered keeps its own behavior: it does not roll
4370
+ * back.
4371
+ */
4372
+ declare class InMemoryTransactionScope implements TransactionScope<undefined> {
4373
+ private readonly participants;
4374
+ private lastTransaction;
4375
+ constructor(participants: ReadonlyArray<InMemoryTransactionParticipant>);
4376
+ transactional<T>(fn: (ctx: undefined) => Promise<T>, options?: TransactionalOptions): Promise<T>;
4222
4377
  }
4223
4378
  //#endregion
4224
4379
  //#region src/persistence/repository/repository.d.ts
@@ -4368,6 +4523,10 @@ interface RetryPolicy {
4368
4523
  * After `maxAttempts` the last error is rethrown unchanged, so a caller
4369
4524
  * can still match `ConcurrencyConflictError` and map it to HTTP 409.
4370
4525
  *
4526
+ * **Attempts.** Before each attempt, the scope calls `onAttemptStart` from
4527
+ * the `transactional` options, so the caller can attribute a failure to the
4528
+ * attempt that raised it.
4529
+ *
4371
4530
  * **Cancellation.** The `AbortSignal` from `transactional` options is
4372
4531
  * checked before each attempt and aborts the backoff wait, so an
4373
4532
  * `AbortSignal.timeout(ms)` bounds total elapsed time (there is
@@ -4407,16 +4566,28 @@ interface InMemorySnapshotStoreOptions {
4407
4566
  * rebuildable derived data, so `maxEntries` may evict the least recently used
4408
4567
  * entry and `ttlMs` may expire it safely. A load updates LRU recency but does
4409
4568
  * not extend TTL; only another save does.
4569
+ *
4570
+ * The port keeps snapshot writes out of the write transaction, so the store
4571
+ * does not roll back on its own. If you register it with an
4572
+ * `InMemoryTransactionScope`, a rollback restores the snapshots, their LRU
4573
+ * order, and their expiry from the start of the transaction. It also undoes
4574
+ * a save or a delete that code made outside the transaction meanwhile. This
4575
+ * is safe, because a snapshot is derived data.
4410
4576
  */
4411
- declare class InMemorySnapshotStore<TState = unknown> implements SnapshotStore<TState> {
4577
+ declare class InMemorySnapshotStore<TState = unknown> implements SnapshotStore<TState>, InMemoryTransactionParticipant {
4412
4578
  private readonly snapshots;
4413
4579
  private readonly maxEntries;
4414
4580
  private readonly ttlMs;
4415
4581
  private readonly clock;
4416
4582
  constructor(options?: InMemorySnapshotStoreOptions);
4417
- load(address: AggregateAddress): Promise<AggregateSnapshot<TState> | undefined>;
4418
- save(address: AggregateAddress, snapshot: AggregateSnapshot<TState>): Promise<void>;
4419
- delete(address: AggregateAddress): Promise<void>;
4583
+ /**
4584
+ * Records the state that a rollback of an `InMemoryTransactionScope`
4585
+ * returns to: every snapshot in LRU order.
4586
+ */
4587
+ beginTransaction(): InMemoryTransaction;
4588
+ load(identity: AggregateIdentity): Promise<AggregateSnapshot<TState> | undefined>;
4589
+ save(identity: AggregateIdentity, snapshot: AggregateSnapshot<TState>): Promise<void>;
4590
+ delete(identity: AggregateIdentity): Promise<void>;
4420
4591
  private readClock;
4421
4592
  private deleteExpired;
4422
4593
  }
@@ -4434,7 +4605,7 @@ interface SnapshotAggregate {
4434
4605
  * valid domain object; it does not know when or how snapshots are stored.
4435
4606
  */
4436
4607
  interface SnapshotModel<TAggregate extends SnapshotAggregate, TSnapshotState> {
4437
- /** Stable type name used to address schema errors and snapshot storage. */
4608
+ /** Stable type name that names the aggregate in schema errors and snapshot storage. */
4438
4609
  readonly aggregateType: string;
4439
4610
  /** Current schema version of the stored snapshot DTO. */
4440
4611
  readonly schemaVersion: number;
@@ -4489,5 +4660,5 @@ declare function captureAggregateSnapshot<TAggregate extends SnapshotAggregate,
4489
4660
  */
4490
4661
  declare function reconstituteAggregateFromSnapshot<TAggregate extends SnapshotAggregate, TSnapshotState>(model: SnapshotModel<TAggregate, TSnapshotState>, id: TAggregate["id"], snapshot: AggregateSnapshot<unknown>): TAggregate;
4491
4662
  //#endregion
4492
- export { type Aggregate, type AggregateAddress, type AggregateAddressMismatchOptions, type AggregateClass, type AggregateCommitToken, type AggregateConfig, AggregateDeletedError, AggregateNotFoundError, type AggregateNotFoundErrorOptions, type AggregatePersistence, type AggregatePersistenceWrite, type AggregateSnapshot, AggregateTrackingError, type AggregateTrackingReason, type AggregateWriteIntent, type AggregateWriteRegistration, type AnyDomainEvent, type AnyUncommittedDomainEvent, type AppendOnlyWriteRegistration, CapabilityRegistryConflictError, type ClockFactory, type Command, CommandBus, type CommandBusOptions, type CommandCommitOriginCandidate, type CommandHandler, type CommandMessageContent, type CommandMessageRelationships, type CommandOutboxCommitCandidate, type CommandOutboxMapper, type CommandOutboxWriter, type CommitEnrollment, type CommitEnrollmentOptions, CommitError, type CommitPosition, type CommittedDomainEvent, type CompatibleRepositoryDefinitions, ConcurrencyConflictError, type ConcurrencyConflictErrorOptions, type ConcurrencyConflictReason, type CreateDomainEventFromFactsOptions, type CreateDomainEventOptions, type CreateDomainEventStampOptions, type CreateUncommittedDomainEventOptions, type DeadLetterDeadline, type DeadLetterRecord, DeadlineProcessor, type DeadlineProcessorObservers, type DeadlineProcessorOptions, type DeadlineStore, type DeepEqualExceptOptions, type DeepOmitKey, type DeepOmitOptions, type DeepOmitPathSegment, type DeliveryFailureAssessment, type DeliveryFailureClassifier, type DeliveryFailureKind, DirectStateMutationError, type DispatchTrackingOutbox, DomainError, type DomainErrorClass, type DomainEvent, type DomainEventFactory, type DomainEventFactoryOptions, type DomainEventStamp, type DomainEventStampFactory, type DomainEventStampProvider, type DomainEventValidationCode, DomainEventValidationError, type DomainEventValidationField, type DomainMachineDefinition, type DomainMachineDefinitionAnalysis, type DomainMachineDefinitionDiagnostic, type DomainMachineInput, type DomainMachineReadonly, type DomainMachineSnapshot, type DomainMachineTransitionDescription, DomainStateMachine, type DomainStateNode, type DomainTransition, DomainTransitionGuardRejectedError, type DomainTransitionGuardResult, type DomainTransitionOutcome, type DomainTransitionResult, type DueDeadline, DuplicateAggregateError, type DuplicateAggregateErrorOptions, DuplicateEventIdError, DuplicateHandlerRegistrationError, type DuplicateHandlerRegistrationErrorOptions, type DurableCommandMessage, Entity, type EntityConfig, ErrorMapperFailedError, type ErrorMapperFailedErrorOptions, type EventBus, EventBusClosedError, EventBusImpl, type EventBusObservers, type EventBusOptions, type EventCommitCandidate, type EventCommitCandidatePosition, type EventHandler, EventHarvestError, type EventIdFactory, type EventMetadata, EventSourcedAggregate, type EventStore, type EventStoreAppendOptions, type ExecutionContext, type FlushStatementReason, FoldReturnedNoStateError, ForeignEventError, type HandlerFailureReport, HostileStateKeyError, type ICommandBus, type IEntity, type IQueryBus, type IValueObject, type Id, type IdGenerator, type IdempotencyClaim, type IdempotencyClaimHandle, IdempotencyClaimLostError, type IdempotencyClaimLostErrorOptions, IdempotencyCompletionWithoutClaimError, IdempotencyInFlightError, type IdempotencyInFlightErrorOptions, IdempotencyKeyReuseError, type IdempotencyKeyReuseErrorOptions, type IdempotencyLease, type IdempotencyOperationErrorContext, type IdempotencyReconciliation, type IdempotencyReconciliationDecision, IdempotencyReconciliationRequiredError, type IdempotencyReconciliationRequiredErrorOptions, type IdempotencyStore, type IdempotentCommitRequest, type IdempotentCommitResult, type IdempotentExecution, type Identifiable, IdentityMap, InMemoryCapacityExceededError, type InMemoryCapacityExceededErrorOptions, InMemoryDeadlineStore, type InMemoryDeadlineStoreOptions, InMemoryEventStore, type InMemoryEventStoreOptions, InMemoryIdempotencyStore, type InMemoryIdempotencyStoreOptions, InMemoryOutbox, type InMemoryOutboxOptions, InMemoryProjectionCheckpointStore, type InMemoryProjectionCheckpointStoreOptions, InMemorySnapshotStore, type InMemorySnapshotStoreOptions, InfrastructureError, type IntegrationMessage, type IntegrationMessageContent, type IntegrationMessageMapper, type IntegrationMessageRelationships, InvalidCommandMessageError, InvalidDomainMachineContextError, InvalidDomainMachineDefinitionError, InvalidDomainMachineInputError, InvalidDomainMachineSnapshotError, InvalidDomainTransitionError, InvalidDomainTransitionGuardResultError, InvalidDomainTransitionResultError, InvalidFlushStatementError, type InvalidFlushStatementErrorOptions, InvalidIntegrationMessageError, InvalidRepositoryAdapterError, InvalidRepositoryDefinitionError, InvalidVersionError, type JsonObject, type JsonPrimitive, type JsonValue, type KitErrorCode, type KitErrorOptions, type MatchedRows, MisaddressedEventError, MissingEntityIdError, MissingFoldError, MissingHandlerError, NestedUnitOfWorkError, NonProgressingEventStreamPageError, type NonProgressingEventStreamPageErrorOptions, type OnceOptions, type Outbox, OutboxDispatcher, type OutboxDispatcherObservers, type OutboxDispatcherOptions, type OutboxRecord, type OutboxSink, type OutboxWriter, type PendingDomainEvent, PendingEventBatchMismatchError, PendingEventLimitExceededError, type PendingEventLimitExceededErrorOptions, type PersistenceBaseline, type PersistenceChanges, type PersistenceLifecycle, type PersistenceModel, type PhysicalRemovalRegistration, type PreparedDomainMachineDefinition, type ProjectOptions, type Projection, type ProjectionBatchResult, type ProjectionCheckpoint, type ProjectionCheckpointStore, type ProjectionEventHandler, type ProjectionFromHandlersOptions, ProjectionGapError, type ProjectionHandlers, ProjectionIdentityViolationError, ProjectionOrderViolationError, type ProjectionPosition, ProjectionReceiptViolationError, Projector, type ProjectorOptions, type PublishAbortedReport, type PublishChainState, type PublishChainStore, PublishDepthExceededError, type PublishOptions, type PublishedCommand, type Query, QueryBus, type QueryBusOptions, type QueryHandler, type ReadStreamOptions, ReentrantDomainStateMachineEvaluationError, ReentrantEventRecordingError, ReplayHeadMismatchError, type ReplayHeadMismatchErrorOptions, type ReplayableAggregate, type RepositoriesOf, type Repository, type RepositoryDefinition, type RepositoryDefinitionOptions, RepositoryErrorMappingFailedError, type RepositoryTracking, type RetryPolicy, RetryingTransactionScope, RollbackError, type RunOptions, type SharedDomainEventStampOptions, SnapshotCorruptedError, type SnapshotModel, SnapshotSchemaMismatchError, type SnapshotSchemaMismatchErrorOptions, type SnapshotStore, SnapshotTimeValidationError, SnapshotVersionNotRestoredError, type SnapshotVersionNotRestoredErrorOptions, Specification, type SpecificationComposite, StateStoredAggregate, type StateValidator, type StreamReadResult, type SubscriptionThresholdReport, TransactionClosedError, type TransactionScope, type TransactionalOptions, type UncommittedDomainEvent, type UncommittedDomainEventOf, UnenrolledChangesError, UnitOfWork, type UnitOfWorkContext, type UnitOfWorkDeps, type UnitOfWorkIdentityMap, UnmanagedInstanceError, UnmintedEventError, UnprojectableEventError, UnregisteredHandlerError, type UnregisteredHandlerErrorOptions, UnreplayableAggregateError, type VO, ValueObject, type Version, type VersionedFlushStatements, type VersionedWrite, type WithCommitDeps, type WithCommitWorkResult, type WithIdempotentCommitDeps, analyzeDomainMachineDefinition, canTransitionDomainState, captureAggregateSnapshot, capturePersistenceBaseline, copyMetadata, createDomainEvent, createDomainEventFactory, createDomainEventFromFacts, createInitialDomainMachineSnapshot, createIntegrationMessage, createUncommittedDomainEvent, decodeIntegrationMessage, deepEqual, deepEqualExcept, deepFreeze, deepOmit, defaultDomainEventFactory, defineRepository, defineSnapshotModel, derivePersistenceChanges, detachState, domainErrorToResult, encodeIntegrationMessage, entityIds, eventBusSink, findEntityById, freezeShallow, hasEntityId, ignoreProjectionEvent, insertPersistenceBaseline, integrationMessageToCommittedEvent, isDomainErrorLike, isInfrastructureErrorLike, isPositionAfter, isWiringErrorLike, mergeMetadata, outboxWriterAcceptingEventLoss, persistenceProjectionDrifted, prepareDomainMachineDefinition, projectionFromHandlers, recapturePersistenceBaseline, reconstituteAggregateFromHistory, reconstituteAggregateFromSnapshot, recordDomainEvent, recordPendingEvents, removeEntityById, replaceEntityById, routeEventsToCommandOutbox, sameEntity, sameVersion, specification, toVersion, transitionDomainState, updateEntityById, versionedFlush, vo, voEquals, voEqualsExcept, voValidated, voWithValidation, withCommit, withIdempotentCommit };
4663
+ export { type AbsentStreamPages, type Aggregate, type AggregateClass, type AggregateCommitToken, type AggregateConfig, AggregateDeletedError, type AggregateDeletedErrorOptions, type AggregateIdentity, type AggregateIdentityMismatchOptions, AggregateNotFoundError, type AggregateNotFoundErrorOptions, type AggregatePersistence, type AggregatePersistenceWrite, type AggregateSnapshot, AggregateTrackingError, type AggregateTrackingErrorOptions, type AggregateTrackingReason, type AggregateWriteIntent, type AggregateWriteRegistration, type AnyDomainEvent, type AnyUncommittedDomainEvent, type AppendOnlyWriteRegistration, CapabilityRegistryConflictError, type ClassifyConcurrencyConflictOptions, type ClockFactory, type Command, CommandBus, type CommandBusOptions, type CommandCommitOriginCandidate, type CommandHandler, type CommandMessageContent, type CommandMessageRelationships, type CommandOutboxCommitCandidate, type CommandOutboxMapper, type CommandOutboxWriter, type CommitEnrollment, type CommitEnrollmentOptions, CommitError, type CommitPosition, type CommittedDomainEvent, type CompatibleRepositoryDefinitions, ConcurrencyConflictError, type ConcurrencyConflictErrorOptions, type ConcurrencyConflictReason, type CreateDomainEventFromFactsOptions, type CreateDomainEventOptions, type CreateDomainEventStampOptions, type CreateUncommittedDomainEventOptions, type DeadLetterDeadline, type DeadLetterRecord, DeadlineProcessor, type DeadlineProcessorObservers, type DeadlineProcessorOptions, type DeadlineStore, type DeepEqualExceptOptions, type DeepOmitKey, type DeepOmitOptions, type DeepOmitPathSegment, type DeliveryFailureAssessment, type DeliveryFailureClassifier, type DeliveryFailureKind, DirectStateMutationError, type DirectStateMutationErrorOptions, type DispatchTrackingOutbox, DomainError, type DomainErrorClass, type DomainEvent, type DomainEventFactory, type DomainEventFactoryOptions, type DomainEventStamp, type DomainEventStampFactory, type DomainEventStampProvider, type DomainEventValidationCode, DomainEventValidationError, type DomainEventValidationField, type DomainMachineDefinition, type DomainMachineDefinitionAnalysis, type DomainMachineDefinitionDiagnostic, type DomainMachineInput, type DomainMachineReadonly, type DomainMachineSnapshot, type DomainMachineTransitionDescription, DomainStateMachine, type DomainStateNode, type DomainTransition, DomainTransitionGuardRejectedError, type DomainTransitionGuardResult, type DomainTransitionOutcome, type DomainTransitionResult, type DueDeadline, DuplicateAggregateError, type DuplicateAggregateErrorOptions, DuplicateEventIdError, type DuplicateEventIdErrorOptions, DuplicateHandlerRegistrationError, type DuplicateHandlerRegistrationErrorOptions, type DurableCommandMessage, Entity, type EntityConfig, ErrorMapperFailedError, type ErrorMapperFailedErrorOptions, type EventBus, EventBusClosedError, EventBusImpl, type EventBusObservers, type EventBusOptions, type EventCommitCandidate, type EventCommitCandidatePosition, type EventHandler, EventHarvestError, type EventIdFactory, type EventMetadata, EventSourcedAggregate, type EventStore, type EventStoreAppendOptions, type EventStreamPageReason, type EventStreamReader, type ExecutionContext, type FlushStatementReason, FoldReturnedNoStateError, ForeignEventError, type HandlerFailureReport, HostileStateKeyError, type ICommandBus, type IEntity, type IQueryBus, type IValueObject, type Id, type IdGenerator, type IdempotencyClaim, type IdempotencyClaimHandle, IdempotencyClaimLostError, type IdempotencyClaimLostErrorOptions, IdempotencyCompletionWithoutClaimError, IdempotencyInFlightError, type IdempotencyInFlightErrorOptions, IdempotencyKeyReuseError, type IdempotencyKeyReuseErrorOptions, type IdempotencyLease, type IdempotencyOperationErrorContext, type IdempotencyReconciliation, type IdempotencyReconciliationDecision, IdempotencyReconciliationRequiredError, type IdempotencyReconciliationRequiredErrorOptions, type IdempotencyStore, type IdempotentCommitRequest, type IdempotentCommitResult, type IdempotentExecution, type Identifiable, IdentityMap, InMemoryCapacityExceededError, type InMemoryCapacityExceededErrorOptions, InMemoryDeadlineStore, type InMemoryDeadlineStoreOptions, InMemoryEventStore, type InMemoryEventStoreOptions, InMemoryIdempotencyStore, type InMemoryIdempotencyStoreOptions, InMemoryOutbox, type InMemoryOutboxOptions, InMemoryProjectionCheckpointStore, type InMemoryProjectionCheckpointStoreOptions, InMemorySnapshotStore, type InMemorySnapshotStoreOptions, type InMemoryTransaction, type InMemoryTransactionParticipant, InMemoryTransactionScope, InfrastructureError, type IntegrationMessage, type IntegrationMessageContent, type IntegrationMessageMapper, type IntegrationMessageRelationships, InvalidCommandMessageError, InvalidDomainMachineContextError, InvalidDomainMachineDefinitionError, InvalidDomainMachineInputError, InvalidDomainMachineSnapshotError, InvalidDomainTransitionError, InvalidDomainTransitionGuardResultError, InvalidDomainTransitionResultError, InvalidEventStreamPageError, type InvalidEventStreamPageErrorOptions, InvalidFlushStatementError, type InvalidFlushStatementErrorOptions, InvalidIntegrationMessageError, InvalidRepositoryAdapterError, type InvalidRepositoryAdapterErrorOptions, type InvalidRepositoryAdapterReason, InvalidRepositoryDefinitionError, InvalidVersionError, type JsonObject, type JsonPrimitive, type JsonValue, type KitErrorCode, type KitErrorOptions, type MatchedRows, MisattributedEventError, MissingEntityIdError, MissingFoldError, MissingHandlerError, NestedUnitOfWorkError, type OnceOptions, type Outbox, OutboxDispatcher, type OutboxDispatcherObservers, type OutboxDispatcherOptions, type OutboxRecord, type OutboxSink, type OutboxWriter, type PendingDomainEvent, PendingEventBatchMismatchError, type PendingEventBatchMismatchErrorOptions, PendingEventLimitExceededError, type PendingEventLimitExceededErrorOptions, type PersistenceBaseline, type PersistenceChanges, type PersistenceLifecycle, type PersistenceModel, type PhysicalRemovalRegistration, type PinTargetVersionOptions, type PinnedTargetVersion, type PreparedDomainMachineDefinition, type ProjectOptions, type Projection, type ProjectionBatchResult, type ProjectionCheckpoint, type ProjectionCheckpointStore, type ProjectionEventHandler, type ProjectionFromHandlersOptions, ProjectionGapError, type ProjectionHandlers, ProjectionIdentityViolationError, ProjectionOrderViolationError, type ProjectionPosition, ProjectionReceiptViolationError, Projector, type ProjectorOptions, type PublishAbortedReport, type PublishChainState, type PublishChainStore, PublishDepthExceededError, type PublishOptions, type PublishedCommand, type Query, QueryBus, type QueryBusOptions, type QueryHandler, type ReachableStreamPages, type ReadStreamOptions, type ReadStreamPagesOptions, ReentrantDomainStateMachineEvaluationError, ReentrantEventRecordingError, type ReentrantEventRecordingErrorOptions, ReplayRejectedError, type ReplayRejectedErrorOptions, ReplayTargetMismatchError, type ReplayTargetMismatchErrorOptions, type ReplayTargetMismatchReason, type ReplayableAggregate, type ReplayableStreamPages, type RepositoriesOf, type Repository, type RepositoryDefinition, type RepositoryDefinitionOptions, RepositoryErrorMappingFailedError, type RepositoryErrorMappingFailedErrorOptions, type RepositoryTracking, type RetryPolicy, RetryingTransactionScope, RollbackError, type RunOptions, type SharedDomainEventStampOptions, SnapshotCorruptedError, type SnapshotModel, SnapshotSchemaMismatchError, type SnapshotSchemaMismatchErrorOptions, type SnapshotStore, SnapshotTimeValidationError, SnapshotVersionNotRestoredError, type SnapshotVersionNotRestoredErrorOptions, Specification, type SpecificationComposite, StateStoredAggregate, type StateValidator, type StreamPages, type StreamReadResult, type SubscriptionThresholdReport, TransactionClosedError, type TransactionScope, type TransactionalOptions, type UncommittedDomainEvent, type UncommittedDomainEventOf, UnenrolledChangesError, type UnenrolledChangesErrorOptions, UnitOfWork, type UnitOfWorkContext, type UnitOfWorkDeps, type UnitOfWorkIdentityMap, UnmanagedInstanceError, UnmintedEventError, UnprojectableEventError, type UnreachableStreamPages, UnregisteredHandlerError, type UnregisteredHandlerErrorOptions, UnreplayableAggregateError, type UnreplayableAggregateErrorOptions, type VO, ValueObject, type Version, type VersionedFlushStatements, type VersionedWrite, type WithCommitDeps, type WithCommitWorkResult, type WithIdempotentCommitDeps, analyzeDomainMachineDefinition, canTransitionDomainState, captureAggregateSnapshot, capturePersistenceBaseline, classifyConcurrencyConflict, copyMetadata, createDomainEvent, createDomainEventFactory, createDomainEventFromFacts, createInitialDomainMachineSnapshot, createIntegrationMessage, createUncommittedDomainEvent, decodeIntegrationMessage, deepEqual, deepEqualExcept, deepFreeze, deepOmit, defaultDomainEventFactory, defineRepository, defineSnapshotModel, derivePersistenceChanges, detachState, domainErrorToResult, encodeIntegrationMessage, entityIds, eventBusSink, findEntityById, freezeShallow, hasEntityId, ignoreProjectionEvent, insertPersistenceBaseline, integrationMessageToCommittedEvent, isDomainErrorLike, isInfrastructureErrorLike, isPositionAfter, isWiringErrorLike, mergeMetadata, outboxWriterAcceptingEventLoss, persistenceProjectionDrifted, pinTargetVersion, prepareDomainMachineDefinition, projectionFromHandlers, readStreamPages, recapturePersistenceBaseline, reconstituteAggregateFromHistory, reconstituteAggregateFromSnapshot, reconstituteAggregateFromStreamPages, recordDomainEvent, recordPendingEvents, removeEntityById, replaceEntityById, routeEventsToCommandOutbox, sameEntity, sameVersion, specification, toVersion, transitionDomainState, updateEntityById, versionedFlush, vo, voEquals, voEqualsExcept, voValidated, voWithValidation, withCommit, withIdempotentCommit };
4493
4664
  //# sourceMappingURL=index.d.ts.map