@shirudo/ddd-kit 3.0.0-rc.8 → 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
@@ -2212,18 +2212,18 @@ var AggregateTrackingError = class extends KitWiringError {
2212
2212
  operation;
2213
2213
  reason;
2214
2214
  registeredIntent;
2215
- constructor(aggregateId, operation, reason, registeredIntent) {
2216
- 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));
2217
2217
  this.aggregateId = aggregateId;
2218
2218
  this.operation = operation;
2219
2219
  this.reason = reason;
2220
2220
  this.registeredIntent = registeredIntent;
2221
2221
  }
2222
2222
  };
2223
- function trackingFailureMessage(aggregateId, operation, reason, registeredIntent) {
2223
+ function trackingFailureMessage(aggregateId, operation, reason, registeredIntent, options) {
2224
2224
  switch (reason) {
2225
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.`;
2226
- 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.");
2227
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.`;
2228
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.`;
2229
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.`;
@@ -2386,9 +2386,14 @@ function defineForwardedRepositoryProperty(state, property, descriptor) {
2386
2386
  });
2387
2387
  state.forwardedOwnProperties.add(property);
2388
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
+ }
2389
2395
  function installRepositoryLifecycleOperations(state) {
2390
- const operations = state.definition.physicalRemoval ? REPOSITORY_LIFECYCLE_OPERATIONS : REPOSITORY_LIFECYCLE_OPERATIONS.slice(0, 2);
2391
- for (const operation of operations) {
2396
+ for (const operation of installedLifecycleOperations(state.definition)) {
2392
2397
  state.writes.add(operation);
2393
2398
  Object.defineProperty(state.target, operation, {
2394
2399
  configurable: false,
@@ -2414,13 +2419,13 @@ function createRepositoryFacadeHandler(state) {
2414
2419
  if (!hasMemberBelowObjectPrototype(target, property) && !hasMemberBelowObjectPrototype(state.source, property)) return Reflect.get(target, property, receiver);
2415
2420
  state.session.assertOpen(repositoryOperationName(property));
2416
2421
  if (Reflect.getOwnPropertyDescriptor(target, property)) return Reflect.get(target, property, receiver);
2417
- if (property === "remove") return void 0;
2422
+ if (isRepositoryLifecycleOperation(property)) return void 0;
2418
2423
  return readRepositorySource(state, property);
2419
2424
  },
2420
2425
  set: (target, property, value, receiver) => setRepositoryFacadeProperty(state, target, property, value, receiver),
2421
2426
  has: (target, property) => {
2422
2427
  state.session.assertOpen(repositoryOperationName(property));
2423
- 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));
2424
2429
  },
2425
2430
  defineProperty: (target, property, descriptor) => defineRepositoryFacadeProperty(state, target, property, descriptor),
2426
2431
  deleteProperty: (target, property) => deleteRepositoryFacadeProperty(state, target, property)
@@ -2771,7 +2776,7 @@ var Session = class {
2771
2776
  this.assertNotRemoved(aggregate, definition);
2772
2777
  const existing = this._trackingByAggregate.get(aggregate);
2773
2778
  if (existing && existing.definition !== definition) throw new AggregateTrackingError(String(aggregate.id), "add", "different_repository", existing.registration?.intent);
2774
- 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 });
2775
2780
  let entry = existing;
2776
2781
  const newlyTracked = !entry;
2777
2782
  if (!entry) {
@@ -2888,12 +2893,12 @@ var Session = class {
2888
2893
  this.assertUnchangedAfterRegistration(entry);
2889
2894
  continue;
2890
2895
  }
2891
- 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 });
2892
2897
  }
2893
2898
  for (const instance of this._identityMap.instancesWithNewPendingEvents()) {
2894
2899
  if (instance !== null && typeof instance === "object" && this.registrationOf(instance) !== void 0) continue;
2895
2900
  const id = instance.id;
2896
- throw new UnenrolledChangesError(String(id));
2901
+ throw new UnenrolledChangesError(String(id), { appendOnly: this._trackingByAggregate.get(instance)?.definition.appendOnly === true });
2897
2902
  }
2898
2903
  }
2899
2904
  /** Flushes every registered receipt in deterministic registration order. */
@@ -2954,20 +2959,7 @@ function mapRepositoryPersistenceError(definition, error, write) {
2954
2959
 
2955
2960
  //#endregion
2956
2961
  //#region src/application/unit-of-work/unit-of-work.ts
2957
- const repositoryDefinitionBrand = Symbol.for("@shirudo/ddd-kit/repository-definition/v1");
2958
- /**
2959
- * Defines repository wiring for an application-owned driven port.
2960
- *
2961
- * The first call makes the port explicit; the second infers the transaction,
2962
- * aggregate, persistence, event, and removal types from the adapter wiring.
2963
- * The port must declare `add` and `update`; if it declares `remove`, the
2964
- * definition must set `physicalRemoval: true`. The adapter created by the
2965
- * definition implements only the remaining methods because lifecycle writes
2966
- * are installed by the Unit of Work.
2967
- * The returned definition is the only form accepted by {@link UnitOfWork}; a
2968
- * raw adapter-shaped object cannot silently turn its concrete surface into the
2969
- * application contract.
2970
- */
2962
+ const repositoryDefinitionBrand = Symbol.for("@shirudo/ddd-kit/repository-definition/v2");
2971
2963
  function assertRepositoryDefinitionMembers(definition) {
2972
2964
  for (const key of [
2973
2965
  "create",
@@ -2977,6 +2969,21 @@ function assertRepositoryDefinitionMembers(definition) {
2977
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.");
2978
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.");
2979
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
+ */
2980
2987
  function defineRepository() {
2981
2988
  const builder = (definition) => {
2982
2989
  const branded = { ...definition };