@shirudo/ddd-kit 3.0.0-rc.7 → 3.0.0-rc.9

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
@@ -1422,6 +1422,11 @@ interface PersistenceModel<TAggregate, TBaseline, TChangeSet> {
1422
1422
  * `Set` members and `Map` keys by reference (JS `SameValueZero`
1423
1423
  * semantics): a capture that re-materializes object Set members or Map
1424
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.
1425
1430
  */
1426
1431
  capture(aggregate: TAggregate): TBaseline;
1427
1432
  /**
@@ -1505,8 +1510,10 @@ type UnitOfWorkIdentityMap = Pick<IdentityMap, "get" | "has" | "isDeleted">;
1505
1510
  * `tracking.trackLoaded(aggregate)` after hydration. This captures the
1506
1511
  * expected version before application code can mutate the instance.
1507
1512
  * - Adapter objects do not need lifecycle methods; the facade installs the
1508
- * Unit-of-Work-owned `add`, `update`, and optional `remove`. If a concrete
1509
- * adapter has same-named methods anyway, the facade masks them.
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.
1510
1517
  * - Other repository methods are reads. A custom method that performs a write
1511
1518
  * would bypass the Unit of Work and violates the adapter contract.
1512
1519
  */
@@ -1629,7 +1636,9 @@ declare class AggregateTrackingError extends KitWiringError<"AGGREGATE_TRACKING"
1629
1636
  readonly operation: AggregateWriteIntent | "load" | "commit";
1630
1637
  readonly reason: AggregateTrackingFailure;
1631
1638
  readonly registeredIntent?: AggregateWriteIntent | undefined;
1632
- constructor(aggregateId: string, operation: AggregateWriteIntent | "load" | "commit", reason: AggregateTrackingFailure, registeredIntent?: AggregateWriteIntent | undefined);
1639
+ constructor(aggregateId: string, operation: AggregateWriteIntent | "load" | "commit", reason: AggregateTrackingFailure, registeredIntent?: AggregateWriteIntent | undefined, options?: {
1640
+ readonly appendOnly?: boolean;
1641
+ });
1633
1642
  }
1634
1643
  /**
1635
1644
  * The unit of work failed AFTER the work callback completed
@@ -1736,7 +1745,7 @@ interface RunOptions {
1736
1745
  }
1737
1746
  declare const repositoryDefinitionBrand: unique symbol;
1738
1747
  /** Adapter wiring accepted by {@link defineRepository}. */
1739
- interface RepositoryDefinitionOptions<TCtx, TRepositoryPort extends object, TAggregate extends Aggregate<Id<string>, AnyDomainEvent>, TBaseline, TChangeSet, TRemoval extends boolean = false> {
1748
+ interface RepositoryDefinitionOptions<TCtx, TRepositoryPort extends object, TAggregate extends Aggregate<Id<string>, AnyDomainEvent>, TBaseline, TChangeSet, TRemoval extends boolean = false, TAppendOnly extends boolean = false> {
1740
1749
  /**
1741
1750
  * Concrete aggregate class used as the Identity Map key, and for nothing
1742
1751
  * else. The read adapter passes the same class to `identityMap.get`, so
@@ -1748,7 +1757,8 @@ interface RepositoryDefinitionOptions<TCtx, TRepositoryPort extends object, TAgg
1748
1757
  readonly persistence: PersistenceModel<TAggregate, TBaseline, TChangeSet>;
1749
1758
  /**
1750
1759
  * Creates the transaction-bound adapter for the port's non-lifecycle
1751
- * methods. The Unit of Work supplies `add`, `update`, and optional `remove`.
1760
+ * methods. The Unit of Work supplies `add`, `update` unless the definition
1761
+ * is append-only, and `remove` with `physicalRemoval`.
1752
1762
  */
1753
1763
  readonly create: (transaction: TCtx, tracking: RepositoryTracking<TAggregate>) => Omit<TRepositoryPort, "add" | "update" | "remove">;
1754
1764
  /**
@@ -1767,19 +1777,83 @@ interface RepositoryDefinitionOptions<TCtx, TRepositoryPort extends object, TAgg
1767
1777
  readonly mapError: (error: unknown, write: AggregatePersistenceWrite<TAggregate, TChangeSet>) => InfrastructureError;
1768
1778
  /** Adds Unit-of-Work-owned `remove` to the application-facing repository. */
1769
1779
  readonly physicalRemoval?: TRemoval;
1780
+ /**
1781
+ * Leaves `update` out of the application-facing repository. An append-only
1782
+ * aggregate is a fact that the domain never changes after `add`, for
1783
+ * example a ledger entry or an audit record. The port then declares no
1784
+ * `update`, and the Unit of Work installs none.
1785
+ */
1786
+ readonly appendOnly?: TAppendOnly;
1770
1787
  }
1771
1788
  /** Complete, helper-created definition for one Unit-of-Work repository. */
1772
- interface RepositoryDefinition<TCtx, TRepositoryPort extends object, TAggregate extends Aggregate<Id<string>, AnyDomainEvent>, TBaseline, TChangeSet, TRemoval extends boolean = false> extends RepositoryDefinitionOptions<TCtx, TRepositoryPort, TAggregate, TBaseline, TChangeSet, TRemoval> {
1789
+ interface RepositoryDefinition<TCtx, TRepositoryPort extends object, TAggregate extends Aggregate<Id<string>, AnyDomainEvent>, TBaseline, TChangeSet, TRemoval extends boolean = false, TAppendOnly extends boolean = false> extends RepositoryDefinitionOptions<TCtx, TRepositoryPort, TAggregate, TBaseline, TChangeSet, TRemoval, TAppendOnly> {
1773
1790
  /** Nominal marker installed by {@link defineRepository}. */
1774
1791
  readonly [repositoryDefinitionBrand]: true;
1775
1792
  }
1776
1793
  /** @inline */
1777
1794
  type CallableValue = (...args: never[]) => unknown;
1795
+ /**
1796
+ * The compile-time report for a port that violates one constraint of
1797
+ * {@link defineRepository}. No definition can carry a property of type
1798
+ * `never`, so the compiler rejects the call. Its message names the violated
1799
+ * constraint instead of the bare "parameter of type never".
1800
+ * @inline
1801
+ */
1802
+ type RepositoryPortViolation<TConstraint extends string> = { readonly [constraint in `defineRepository: ${TConstraint}`]: never; };
1803
+ /**
1804
+ * Continues with the next constraint when the checked one passed, and
1805
+ * otherwise reports the violation of the checked one.
1806
+ * @inline
1807
+ */
1808
+ type Then<TChecked, TNext> = unknown extends TChecked ? TNext : TChecked;
1809
+ /** @inline */
1810
+ type IsUnion<T, TEach = T> = T extends unknown ? [TEach] extends [T] ? false : true : never;
1811
+ /** @inline */
1812
+ 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">;
1813
+ /**
1814
+ * Checks a lifecycle member that the port declares: it is required, and it
1815
+ * accepts the definition's aggregate. An optional member is the trap of a
1816
+ * port that extends a type with `update?` or `remove?`, so it gets its own
1817
+ * message.
1818
+ * @inline
1819
+ */
1820
+ 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`>;
1821
+ /** @inline */
1822
+ 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">;
1823
+ /** @inline */
1824
+ 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">;
1825
+ /** @inline */
1826
+ 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;
1827
+ /**
1828
+ * Checks the port against every constraint of {@link defineRepository}, one
1829
+ * at a time, so the report names the first violated constraint. Resolves to
1830
+ * `unknown` when the port satisfies all of them. A port typed `any` opts out
1831
+ * of the check, as it does everywhere else. Under the `object` bound of the
1832
+ * builder only `any` satisfies `unknown extends TRepositoryPort`; the usual
1833
+ * `0 extends 1 & T` probe misses an `any` that passed through that bound.
1834
+ * @inline
1835
+ */
1836
+ 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>>>>;
1778
1837
  /** @inline */
1779
- 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>(definition: RepositoryDefinitionOptions<Parameters<TCreate>[0], TRepositoryPort, TAggregate, TBaseline, TChangeSet, TRemoval> & {
1838
+ 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> & {
1780
1839
  readonly create: TCreate;
1781
- } & (TRepositoryPort extends AggregateWriteRegistration<TAggregate> ? TRemoval extends true ? TRepositoryPort extends PhysicalRemovalRegistration<TAggregate> ? unknown : never : TRepositoryPort extends PhysicalRemovalRegistration<TAggregate> ? never : unknown : never)) => RepositoryDefinition<Parameters<TCreate>[0], TRepositoryPort, TAggregate, TBaseline, TChangeSet, TRemoval>;
1782
- declare function defineRepository<TRepositoryPort extends object>(): Extract<TRepositoryPort, CallableValue> extends never ? RepositoryDefinitionBuilder<TRepositoryPort> : never;
1840
+ } & RepositoryPortConstraint<TRepositoryPort, TAggregate, TRemoval, TAppendOnly>) => RepositoryDefinition<Parameters<TCreate>[0], TRepositoryPort, TAggregate, TBaseline, TChangeSet, TRemoval, TAppendOnly>;
1841
+ /**
1842
+ * Defines repository wiring for an application-owned driven port.
1843
+ *
1844
+ * The first call makes the port explicit; the second infers the transaction,
1845
+ * aggregate, persistence, event, and lifecycle types from the adapter wiring.
1846
+ * The port must declare `add` for the aggregate. It declares `update` unless
1847
+ * the definition sets `appendOnly: true`. If it declares `remove`, the
1848
+ * definition must set `physicalRemoval: true`. A violated constraint fails
1849
+ * the call with a compiler error that names the constraint. The adapter
1850
+ * created by the definition implements only the remaining methods because
1851
+ * lifecycle writes are installed by the Unit of Work.
1852
+ * The returned definition is the only form accepted by {@link UnitOfWork}; a
1853
+ * raw adapter-shaped object cannot silently turn its concrete surface into the
1854
+ * application contract.
1855
+ */
1856
+ declare function defineRepository<TRepositoryPort extends object>(): RepositoryDefinitionBuilder<TRepositoryPort>;
1783
1857
  /** Application-facing repositories inferred from their adapter definitions. */
1784
1858
  type RepositoriesOf<TDefinitions> = { [K in keyof TDefinitions]: RepositoryFacadeOf<TDefinitions[K]>; };
1785
1859
  /**
@@ -1787,12 +1861,15 @@ type RepositoriesOf<TDefinitions> = { [K in keyof TDefinitions]: RepositoryFacad
1787
1861
  * entries, callable adapter results, and definitions whose transaction context
1788
1862
  * or aggregate event family does not belong to the Unit of Work that owns them.
1789
1863
  */
1790
- type CompatibleRepositoryDefinitions<Evt extends AnyDomainEvent, TCtx, TDefinitions> = { [K in keyof TDefinitions]: TDefinitions[K] extends RepositoryDefinition<infer TDefinitionContext, infer _TRepositoryPort, infer TAggregate, infer _TBaseline, infer _TChangeSet, infer _TRemoval> ? TAggregate extends Aggregate<Id<string>, infer TDefinitionEvent> ? [TDefinitionEvent] extends [Evt] ? TCtx extends TDefinitionContext ? TDefinitions[K] : never : never : never : never; };
1864
+ type CompatibleRepositoryDefinitions<Evt extends AnyDomainEvent, TCtx, TDefinitions> = { [K in keyof TDefinitions]: TDefinitions[K] extends RepositoryDefinition<infer TDefinitionContext, infer _TRepositoryPort, infer TAggregate, infer _TBaseline, infer _TChangeSet, infer _TRemoval, infer _TAppendOnly> ? TAggregate extends Aggregate<Id<string>, infer TDefinitionEvent> ? [TDefinitionEvent] extends [Evt] ? TCtx extends TDefinitionContext ? TDefinitions[K] : never : never : never : never; };
1791
1865
  /** @inline */
1792
- type RepositoryFacadeOf<TDefinition> = TDefinition extends RepositoryDefinition<infer _TCtx, infer TRepositoryPort, infer _TAggregate, infer _TBaseline, infer _TChangeSet, infer _TRemoval> ? TRepositoryPort : never;
1793
- /** Unit-of-Work-owned writes added to every application repository facade. */
1794
- interface AggregateWriteRegistration<TAggregate extends Aggregate<Id<string>, AnyDomainEvent>> {
1866
+ type RepositoryFacadeOf<TDefinition> = TDefinition extends RepositoryDefinition<infer _TCtx, infer TRepositoryPort, infer _TAggregate, infer _TBaseline, infer _TChangeSet, infer _TRemoval, infer _TAppendOnly> ? TRepositoryPort : never;
1867
+ /** The one Unit-of-Work-owned write of an append-only repository facade. */
1868
+ interface AppendOnlyWriteRegistration<TAggregate extends Aggregate<Id<string>, AnyDomainEvent>> {
1795
1869
  add(aggregate: TAggregate): void;
1870
+ }
1871
+ /** Unit-of-Work-owned writes of a repository facade that is not append-only. */
1872
+ interface AggregateWriteRegistration<TAggregate extends Aggregate<Id<string>, AnyDomainEvent>> extends AppendOnlyWriteRegistration<TAggregate> {
1796
1873
  update(aggregate: TAggregate): void;
1797
1874
  }
1798
1875
  /** Optional physical removal added only by an explicit repository definition. */
@@ -4274,5 +4351,5 @@ declare function captureAggregateSnapshot<TAggregate extends SnapshotAggregate,
4274
4351
  */
4275
4352
  declare function reconstituteAggregateFromSnapshot<TAggregate extends SnapshotAggregate, TSnapshotState>(model: SnapshotModel<TAggregate, TSnapshotState>, id: TAggregate["id"], snapshot: AggregateSnapshot<unknown>): TAggregate;
4276
4353
  //#endregion
4277
- 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 AggregateTrackingFailure, type AggregateWriteIntent, type AggregateWriteRegistration, type AnyDomainEvent, type AnyUncommittedDomainEvent, 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 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, 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, InvalidIntegrationMessageError, InvalidRepositoryAdapterError, InvalidRepositoryDefinitionError, InvalidVersionError, type JsonObject, type JsonPrimitive, type JsonValue, type KitErrorCode, type KitErrorOptions, 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 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, mergeMetadata, outboxWriterAcceptingEventLoss, persistenceProjectionDrifted, prepareDomainMachineDefinition, projectionFromHandlers, recapturePersistenceBaseline, reconstituteAggregateFromHistory, reconstituteAggregateFromSnapshot, recordDomainEvent, recordPendingEvents, removeEntityById, replaceEntityById, routeEventsToCommandOutbox, sameEntity, sameVersion, specification, toVersion, transitionDomainState, updateEntityById, vo, voEquals, voEqualsExcept, voValidated, voWithValidation, withCommit, withIdempotentCommit };
4354
+ 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 AggregateTrackingFailure, 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 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, 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, InvalidIntegrationMessageError, InvalidRepositoryAdapterError, InvalidRepositoryDefinitionError, InvalidVersionError, type JsonObject, type JsonPrimitive, type JsonValue, type KitErrorCode, type KitErrorOptions, 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 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, mergeMetadata, outboxWriterAcceptingEventLoss, persistenceProjectionDrifted, prepareDomainMachineDefinition, projectionFromHandlers, recapturePersistenceBaseline, reconstituteAggregateFromHistory, reconstituteAggregateFromSnapshot, recordDomainEvent, recordPendingEvents, removeEntityById, replaceEntityById, routeEventsToCommandOutbox, sameEntity, sameVersion, specification, toVersion, transitionDomainState, updateEntityById, vo, voEquals, voEqualsExcept, voValidated, voWithValidation, withCommit, withIdempotentCommit };
4278
4355
  //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { A as NonProgressingEventStreamPageError, B as SnapshotSchemaMismatchError, C as InvalidIntegrationMessageError, D as MissingEntityIdError, E as MisaddressedEventError, F as ProjectionOrderViolationError, G as UnprojectableEventError, H as UnenrolledChangesError, I as ProjectionReceiptViolationError, J as assertNoHostileOwnProtoKey, K as UnregisteredHandlerError, L as ReentrantEventRecordingError, M as PendingEventLimitExceededError, N as ProjectionGapError, O as MissingFoldError, P as ProjectionIdentityViolationError, R as ReplayHeadMismatchError, S as InvalidCommandMessageError, T as KitWiringError, U as UnmanagedInstanceError, V as SnapshotVersionNotRestoredError, W as UnmintedEventError, X as isInfrastructureErrorLike, Y as isDomainErrorLike, _ as IdempotencyInFlightError, a as DirectStateMutationError, b as InMemoryCapacityExceededError, c as DuplicateEventIdError, d as EventHarvestError, f as FoldReturnedNoStateError, g as IdempotencyCompletionWithoutClaimError, h as IdempotencyClaimLostError, i as ConcurrencyConflictError, j as PendingEventBatchMismatchError, k as MissingHandlerError, l as DuplicateHandlerRegistrationError, m as HostileStateKeyError, n as AggregateNotFoundError, o as DomainError, p as ForeignEventError, q as UnreplayableAggregateError, r as CapabilityRegistryConflictError, s as DuplicateAggregateError, t as AggregateDeletedError, u as ErrorMapperFailedError, v as IdempotencyKeyReuseError, w as InvalidVersionError, x as InfrastructureError, y as IdempotencyReconciliationRequiredError, z as SnapshotCorruptedError } from "./chunks/kit-errors.js";
2
- import { A as isBuiltInObject, C as voWithValidation, D as builtInTagWithoutInvokingAccessors, E as deepEqual, M as isWeakMap, O as findPropertyDescriptor, S as voEqualsExcept, T as deepOmit, _ as stampCooperativeBrand, a as createDomainEvent, b as vo, c as createUncommittedDomainEvent, d as isUncommittedDomainEvent, f as mergeMetadata, g as hasCooperativeBrand, h as SnapshotTimeValidationError, i as copyMetadata, j as isIntrinsicConstructorPrototype, k as hasIntrinsicPrototypeChain, l as defaultDomainEventFactory, m as DomainEventValidationError, n as adoptRecordedDomainEvent, o as createDomainEventFactory, p as recordDomainEvent, r as adoptUncommittedDomainEvent, s as createDomainEventFromFacts, t as isDispatchTrackingOutbox, u as isRecordedDomainEvent, v as ValueObject, w as deepEqualExcept, x as voEquals, y as deepFreeze } from "./chunks/ports.js";
2
+ import { A as voWithValidation, C as hasCooperativeBrand, D as vo, E as deepFreeze, F as findPropertyDescriptor, I as hasIntrinsicPrototypeChain, L as isBuiltInObject, M as deepOmit, N as deepEqual, O as voEquals, P as builtInTagWithoutInvokingAccessors, R as isIntrinsicConstructorPrototype, S as SnapshotTimeValidationError, T as ValueObject, _ as isRecordedDomainEvent, a as assertNonNegativeFinite, b as recordDomainEvent, c as abortReason, d as copyMetadata, f as createDomainEvent, g as defaultDomainEventFactory, h as createUncommittedDomainEvent, i as runBoundedExecution, j as deepEqualExcept, k as voEqualsExcept, l as adoptRecordedDomainEvent, m as createDomainEventFromFacts, n as DEFAULT_EXECUTION_TIMEOUT_MS, o as assertPositiveInteger, p as createDomainEventFactory, r as ownerSignalOf, s as assertPositiveSafeInteger, t as isDispatchTrackingOutbox, u as adoptUncommittedDomainEvent, v as isUncommittedDomainEvent, w as stampCooperativeBrand, x as DomainEventValidationError, y as mergeMetadata, z as isWeakMap } from "./chunks/ports.js";
3
3
  import { err, ok } from "@shirudo/result";
4
4
  import { ValidationError, someChainRetryable } from "@shirudo/base-error";
5
5
 
@@ -363,130 +363,6 @@ function pendingEventLifecycleReadViewFor(aggregate) {
363
363
  return pendingEventLifecycleCapabilityFor(aggregate);
364
364
  }
365
365
 
366
- //#endregion
367
- //#region src/internal/async/abort.ts
368
- /**
369
- * The value to reject with when an `AbortSignal` has fired.
370
- *
371
- * Returns the signal's `reason` (a `DOMException` `AbortError` for
372
- * `controller.abort()`, `TimeoutError` for `AbortSignal.timeout`), falling
373
- * back to a plain `Error` with `fallbackMessage` when `reason` is nullish.
374
- * A spec-compliant signal always populates `reason` when aborted, so the
375
- * fallback only fires for a non-spec polyfill; without it, a bare
376
- * `throw undefined` would surface, breaking `instanceof Error` handling.
377
- *
378
- * Centralizes the `signal.reason ?? new Error(...)` idiom used at every
379
- * abort site (event bus, `withCommit`, `UnitOfWork.run`, the retrying
380
- * scope) so a single fix covers all of them.
381
- */
382
- function abortReason(signal, fallbackMessage) {
383
- return signal.reason ?? new Error(fallbackMessage);
384
- }
385
-
386
- //#endregion
387
- //#region src/internal/validate.ts
388
- /**
389
- * Shared construction-time guards for numeric options. `context` names
390
- * the throwing component so the error reads like the component's own
391
- * validation ("OutboxDispatcher: pollIntervalMs must be...").
392
- */
393
- /** Guard for numeric options that must be a non-negative finite number. */
394
- function assertNonNegativeFinite(context, field, value) {
395
- if (!Number.isFinite(value) || value < 0) throw new Error(`${context}: ${field} must be a non-negative finite number, got ${value}`);
396
- }
397
- /** Guard for count options that must be a whole number of at least 1. */
398
- function assertPositiveInteger(context, field, value) {
399
- if (!Number.isInteger(value) || value < 1) throw new Error(`${context}: ${field} must be an integer >= 1, got ${value}`);
400
- }
401
- /** Guard for retained-record capacities that must fit exact JS integers. */
402
- function assertPositiveSafeInteger(context, field, value) {
403
- if (!Number.isSafeInteger(value) || value < 1) throw new RangeError(`${context}: ${field} must be a positive safe integer, got ${value}`);
404
- }
405
-
406
- //#endregion
407
- //#region src/internal/async/execution.ts
408
- /** Default bound for delivery and post-commit operations. */
409
- const DEFAULT_EXECUTION_TIMEOUT_MS = 3e4;
410
- /**
411
- * Owner signal of each child signal that {@link runBoundedExecution} minted.
412
- *
413
- * One bounded operation often wraps another, and every hop derives a fresh
414
- * signal. A consumer that follows a call chain by signal identity alone loses
415
- * the link at the first hop. Key and value are both weak: a long chain of
416
- * nested operations must not hold its whole ancestry alive.
417
- */
418
- const executionOwners = /* @__PURE__ */ new WeakMap();
419
- /**
420
- * The signal that a bounded execution derived this one from, or `undefined`
421
- * when the signal did not come from {@link runBoundedExecution} or had no
422
- * owner. Walk it to follow a chain across nested bounded executions.
423
- */
424
- function ownerSignalOf(signal) {
425
- return executionOwners.get(signal)?.deref();
426
- }
427
- /**
428
- * Runs one operation with a child signal that combines owner cancellation and a
429
- * shell-owned timeout. The returned promise settles on abort even when an
430
- * adapter ignores the signal; the adapter promise remains observed so a later
431
- * rejection cannot become an unhandled rejection.
432
- *
433
- * This bounds how long the shell waits; JavaScript cannot forcibly terminate
434
- * an arbitrary promise. An I/O adapter that must prevent zombie work and
435
- * overlapping retries has to pass `context.signal` to its native operation or
436
- * enforce a native timeout no later than `context.deadlineAt`.
437
- */
438
- function runBoundedExecution(label, options, operation) {
439
- if (options.deadlineAt === void 0) assertNonNegativeFinite(label, "timeoutMs", options.timeoutMs);
440
- else assertNonNegativeFinite(label, "deadlineAt", options.deadlineAt);
441
- const startedAt = Date.now();
442
- const deadlineAt = options.deadlineAt ?? startedAt + options.timeoutMs;
443
- const timeoutMs = Math.max(0, deadlineAt - startedAt);
444
- const timeoutError = () => new DOMException(`${label} timed out after ${timeoutMs}ms`, "TimeoutError");
445
- const controller = new AbortController();
446
- const context = Object.freeze({
447
- signal: controller.signal,
448
- deadlineAt
449
- });
450
- const ownerSignal = options.signal;
451
- if (ownerSignal !== void 0) executionOwners.set(controller.signal, new WeakRef(ownerSignal));
452
- const abortFromOwner = () => {
453
- controller.abort(ownerSignal === void 0 ? /* @__PURE__ */ new Error(`${label} aborted`) : abortReason(ownerSignal, `${label} aborted`));
454
- };
455
- if (ownerSignal?.aborted) abortFromOwner();
456
- else ownerSignal?.addEventListener("abort", abortFromOwner, { once: true });
457
- if (!controller.signal.aborted && options.deadlineAt !== void 0 && deadlineAt <= startedAt) controller.abort(timeoutError());
458
- const timer = setTimeout(() => {
459
- controller.abort(timeoutError());
460
- }, timeoutMs);
461
- return new Promise((resolve, reject) => {
462
- let settled = false;
463
- const finish = (complete) => {
464
- if (settled) return;
465
- settled = true;
466
- clearTimeout(timer);
467
- ownerSignal?.removeEventListener("abort", abortFromOwner);
468
- controller.signal.removeEventListener("abort", onAbort);
469
- complete();
470
- };
471
- const onAbort = () => {
472
- queueMicrotask(() => finish(() => reject(abortReason(controller.signal, `${label} aborted`))));
473
- };
474
- if (controller.signal.aborted) {
475
- onAbort();
476
- return;
477
- }
478
- controller.signal.addEventListener("abort", onAbort, { once: true });
479
- let outcome;
480
- try {
481
- outcome = Promise.resolve(operation(context));
482
- } catch (error) {
483
- finish(() => reject(error));
484
- return;
485
- }
486
- outcome.then((value) => finish(() => resolve(value)), (error) => finish(() => reject(error)));
487
- });
488
- }
489
-
490
366
  //#endregion
491
367
  //#region src/internal/observer.ts
492
368
  /**
@@ -2336,18 +2212,18 @@ var AggregateTrackingError = class extends KitWiringError {
2336
2212
  operation;
2337
2213
  reason;
2338
2214
  registeredIntent;
2339
- constructor(aggregateId, operation, reason, registeredIntent) {
2340
- super("AGGREGATE_TRACKING", trackingFailureMessage(aggregateId, operation, reason, registeredIntent));
2215
+ constructor(aggregateId, operation, reason, registeredIntent, options = {}) {
2216
+ super("AGGREGATE_TRACKING", trackingFailureMessage(aggregateId, operation, reason, registeredIntent, options));
2341
2217
  this.aggregateId = aggregateId;
2342
2218
  this.operation = operation;
2343
2219
  this.reason = reason;
2344
2220
  this.registeredIntent = registeredIntent;
2345
2221
  }
2346
2222
  };
2347
- function trackingFailureMessage(aggregateId, operation, reason, registeredIntent) {
2223
+ function trackingFailureMessage(aggregateId, operation, reason, registeredIntent, options) {
2348
2224
  switch (reason) {
2349
2225
  case "not_loaded": return `Aggregate ${aggregateId} cannot be registered for ${operation}: it was not loaded into this unit of work. Load it through the repository before updating or removing it.`;
2350
- case "loaded_as_new": return `Aggregate ${aggregateId} cannot be added as new because it was loaded by this unit of work. Use update for a loaded aggregate.`;
2226
+ case "loaded_as_new": return `Aggregate ${aggregateId} cannot be added as new because it was loaded by this unit of work. ` + (options.appendOnly ? "Its repository is append-only, so a loaded aggregate is already persisted and must not change." : "Use update for a loaded aggregate.");
2351
2227
  case "different_repository": return `Aggregate ${aggregateId} cannot be registered for ${operation} through a different repository in the same unit of work. One aggregate instance must remain owned by the repository definition that first tracked it.`;
2352
2228
  case "conflicting_intent": return `Aggregate ${aggregateId} is already registered for ${registeredIntent ?? "another write"}; ${operation} would create conflicting persistence intent in one unit of work. Decide the final lifecycle outcome before registering it.`;
2353
2229
  case "mutated_after_registration": return `Aggregate ${aggregateId} changed after ${registeredIntent ?? "write"} was registered. Make domain decisions first and call add, update, or remove last so persisted state and recorded events cannot diverge.`;
@@ -2510,9 +2386,14 @@ function defineForwardedRepositoryProperty(state, property, descriptor) {
2510
2386
  });
2511
2387
  state.forwardedOwnProperties.add(property);
2512
2388
  }
2389
+ function installedLifecycleOperations(definition) {
2390
+ const operations = ["add"];
2391
+ if (!definition.appendOnly) operations.push("update");
2392
+ if (definition.physicalRemoval) operations.push("remove");
2393
+ return operations;
2394
+ }
2513
2395
  function installRepositoryLifecycleOperations(state) {
2514
- const operations = state.definition.physicalRemoval ? REPOSITORY_LIFECYCLE_OPERATIONS : REPOSITORY_LIFECYCLE_OPERATIONS.slice(0, 2);
2515
- for (const operation of operations) {
2396
+ for (const operation of installedLifecycleOperations(state.definition)) {
2516
2397
  state.writes.add(operation);
2517
2398
  Object.defineProperty(state.target, operation, {
2518
2399
  configurable: false,
@@ -2538,13 +2419,13 @@ function createRepositoryFacadeHandler(state) {
2538
2419
  if (!hasMemberBelowObjectPrototype(target, property) && !hasMemberBelowObjectPrototype(state.source, property)) return Reflect.get(target, property, receiver);
2539
2420
  state.session.assertOpen(repositoryOperationName(property));
2540
2421
  if (Reflect.getOwnPropertyDescriptor(target, property)) return Reflect.get(target, property, receiver);
2541
- if (property === "remove") return void 0;
2422
+ if (isRepositoryLifecycleOperation(property)) return void 0;
2542
2423
  return readRepositorySource(state, property);
2543
2424
  },
2544
2425
  set: (target, property, value, receiver) => setRepositoryFacadeProperty(state, target, property, value, receiver),
2545
2426
  has: (target, property) => {
2546
2427
  state.session.assertOpen(repositoryOperationName(property));
2547
- return state.writes.has(property) || property !== "remove" && (Reflect.has(target, property) || Reflect.has(state.source, property));
2428
+ return state.writes.has(property) || !isRepositoryLifecycleOperation(property) && (Reflect.has(target, property) || Reflect.has(state.source, property));
2548
2429
  },
2549
2430
  defineProperty: (target, property, descriptor) => defineRepositoryFacadeProperty(state, target, property, descriptor),
2550
2431
  deleteProperty: (target, property) => deleteRepositoryFacadeProperty(state, target, property)
@@ -2895,7 +2776,7 @@ var Session = class {
2895
2776
  this.assertNotRemoved(aggregate, definition);
2896
2777
  const existing = this._trackingByAggregate.get(aggregate);
2897
2778
  if (existing && existing.definition !== definition) throw new AggregateTrackingError(String(aggregate.id), "add", "different_repository", existing.registration?.intent);
2898
- if (existing?.lifecycle === "loaded") throw new AggregateTrackingError(String(aggregate.id), "add", "loaded_as_new", existing.registration?.intent);
2779
+ if (existing?.lifecycle === "loaded") throw new AggregateTrackingError(String(aggregate.id), "add", "loaded_as_new", existing.registration?.intent, { appendOnly: definition.appendOnly === true });
2899
2780
  let entry = existing;
2900
2781
  const newlyTracked = !entry;
2901
2782
  if (!entry) {
@@ -3012,12 +2893,12 @@ var Session = class {
3012
2893
  this.assertUnchangedAfterRegistration(entry);
3013
2894
  continue;
3014
2895
  }
3015
- if (entry.lifecycle === "loaded" && (entry.aggregate.version !== entry.expectedVersion || persistenceProjectionDrifted(entry.baseline, entry.aggregate))) throw new UnenrolledChangesError(String(entry.aggregate.id));
2896
+ if (entry.lifecycle === "loaded" && (entry.aggregate.version !== entry.expectedVersion || persistenceProjectionDrifted(entry.baseline, entry.aggregate))) throw new UnenrolledChangesError(String(entry.aggregate.id), { appendOnly: entry.definition.appendOnly === true });
3016
2897
  }
3017
2898
  for (const instance of this._identityMap.instancesWithNewPendingEvents()) {
3018
2899
  if (instance !== null && typeof instance === "object" && this.registrationOf(instance) !== void 0) continue;
3019
2900
  const id = instance.id;
3020
- throw new UnenrolledChangesError(String(id));
2901
+ throw new UnenrolledChangesError(String(id), { appendOnly: this._trackingByAggregate.get(instance)?.definition.appendOnly === true });
3021
2902
  }
3022
2903
  }
3023
2904
  /** Flushes every registered receipt in deterministic registration order. */
@@ -3078,20 +2959,7 @@ function mapRepositoryPersistenceError(definition, error, write) {
3078
2959
 
3079
2960
  //#endregion
3080
2961
  //#region src/application/unit-of-work/unit-of-work.ts
3081
- const repositoryDefinitionBrand = Symbol.for("@shirudo/ddd-kit/repository-definition/v1");
3082
- /**
3083
- * Defines repository wiring for an application-owned driven port.
3084
- *
3085
- * The first call makes the port explicit; the second infers the transaction,
3086
- * aggregate, persistence, event, and removal types from the adapter wiring.
3087
- * The port must declare `add` and `update`; if it declares `remove`, the
3088
- * definition must set `physicalRemoval: true`. The adapter created by the
3089
- * definition implements only the remaining methods because lifecycle writes
3090
- * are installed by the Unit of Work.
3091
- * The returned definition is the only form accepted by {@link UnitOfWork}; a
3092
- * raw adapter-shaped object cannot silently turn its concrete surface into the
3093
- * application contract.
3094
- */
2962
+ const repositoryDefinitionBrand = Symbol.for("@shirudo/ddd-kit/repository-definition/v2");
3095
2963
  function assertRepositoryDefinitionMembers(definition) {
3096
2964
  for (const key of [
3097
2965
  "create",
@@ -3101,6 +2969,21 @@ function assertRepositoryDefinitionMembers(definition) {
3101
2969
  if (typeof definition.aggregate !== "function") throw new TypeError("defineRepository: \"aggregate\" is missing or not a class reference on the definition. Pass a plain object literal with own enumerable properties.");
3102
2970
  if (definition.persistence === null || typeof definition.persistence !== "object") throw new TypeError("defineRepository: \"persistence\" is missing or not a PersistenceModel on the definition. Pass a plain object literal with own enumerable properties.");
3103
2971
  }
2972
+ /**
2973
+ * Defines repository wiring for an application-owned driven port.
2974
+ *
2975
+ * The first call makes the port explicit; the second infers the transaction,
2976
+ * aggregate, persistence, event, and lifecycle types from the adapter wiring.
2977
+ * The port must declare `add` for the aggregate. It declares `update` unless
2978
+ * the definition sets `appendOnly: true`. If it declares `remove`, the
2979
+ * definition must set `physicalRemoval: true`. A violated constraint fails
2980
+ * the call with a compiler error that names the constraint. The adapter
2981
+ * created by the definition implements only the remaining methods because
2982
+ * lifecycle writes are installed by the Unit of Work.
2983
+ * The returned definition is the only form accepted by {@link UnitOfWork}; a
2984
+ * raw adapter-shaped object cannot silently turn its concrete surface into the
2985
+ * application contract.
2986
+ */
3104
2987
  function defineRepository() {
3105
2988
  const builder = (definition) => {
3106
2989
  const branded = { ...definition };