@shirudo/ddd-kit 3.0.0-rc.6 → 3.0.0-rc.8

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.
@@ -931,9 +931,11 @@ interface AggregateSnapshot<TState> {
931
931
  * part of this surface. The application shell holds that authority.
932
932
  *
933
933
  * @template TId - The aggregate root identifier (branded via `Id<Tag>`)
934
- * @template TEvent - The domain-event union, defaults to `never`
934
+ * @template TEvent - The domain-event union. Defaults to `AnyDomainEvent`,
935
+ * so a bound written as `Aggregate<TId>` admits every aggregate root,
936
+ * with or without events.
935
937
  */
936
- interface Aggregate<TId extends Id<string>, TEvent extends AnyDomainEvent = never> {
938
+ interface Aggregate<TId extends Id<string>, TEvent extends AnyDomainEvent = AnyDomainEvent> {
937
939
  readonly id: TId;
938
940
  readonly version: Version;
939
941
  readonly pendingEvents: ReadonlyArray<PendingDomainEvent<TEvent>>;
package/dist/index.d.ts CHANGED
@@ -1533,6 +1533,12 @@ interface RepositoryTracking<TAggregate extends Aggregate<Id<string>, AnyDomainE
1533
1533
  * the exact moment at which the application registered its write intent.
1534
1534
  * Adapters must use the expected/current version pair for their OCC predicate
1535
1535
  * and must not read mutable write state back from an aggregate reference.
1536
+ *
1537
+ * The predicate itself is adapter code. The compare-and-set must run in the
1538
+ * store's own write statement. The kit does not know the store, so it cannot
1539
+ * write that statement. The kit owns the version pair and
1540
+ * {@link ConcurrencyConflictError}; the repository contract suite proves the
1541
+ * predicate.
1536
1542
  */
1537
1543
  interface AggregatePersistenceWrite<TAggregate extends Aggregate<Id<string>, AnyDomainEvent>, TChangeSet> {
1538
1544
  readonly intent: AggregateWriteIntent;
@@ -1731,7 +1737,12 @@ interface RunOptions {
1731
1737
  declare const repositoryDefinitionBrand: unique symbol;
1732
1738
  /** Adapter wiring accepted by {@link defineRepository}. */
1733
1739
  interface RepositoryDefinitionOptions<TCtx, TRepositoryPort extends object, TAggregate extends Aggregate<Id<string>, AnyDomainEvent>, TBaseline, TChangeSet, TRemoval extends boolean = false> {
1734
- /** Concrete aggregate class used as the Identity Map key. */
1740
+ /**
1741
+ * Concrete aggregate class used as the Identity Map key, and for nothing
1742
+ * else. The read adapter passes the same class to `identityMap.get`, so
1743
+ * the class is exported. Its protected constructor keeps `new` out of
1744
+ * reach; the static factories stay the only door.
1745
+ */
1735
1746
  readonly aggregate: AggregateClass<TAggregate>;
1736
1747
  /** Adapter-owned projection, baseline, and change-set policy. */
1737
1748
  readonly persistence: PersistenceModel<TAggregate, TBaseline, TChangeSet>;
@@ -4017,7 +4028,7 @@ declare class InMemoryEventStore<Evt extends AnyDomainEvent> implements EventSto
4017
4028
  * @template TAggregate - Aggregate root loaded and registered by the port.
4018
4029
  * @template TId - Branded aggregate identifier.
4019
4030
  */
4020
- interface AggregatePersistence<TAggregate extends Aggregate<TId>, TId extends Id<string>> {
4031
+ interface AggregatePersistence<TAggregate extends Aggregate<TId, AnyDomainEvent>, TId extends Id<string>> {
4021
4032
  /**
4022
4033
  * Finds an aggregate by identity.
4023
4034
  *
@@ -4066,7 +4077,7 @@ interface AggregatePersistence<TAggregate extends Aggregate<TId>, TId extends Id
4066
4077
  * by an order command, while read-heavy access remains on a projection or query
4067
4078
  * port.
4068
4079
  */
4069
- interface Repository<TAggregate extends Aggregate<TId>, TId extends Id<string>> extends AggregatePersistence<TAggregate, TId> {
4080
+ interface Repository<TAggregate extends Aggregate<TId, AnyDomainEvent>, TId extends Id<string>> extends AggregatePersistence<TAggregate, TId> {
4070
4081
  /**
4071
4082
  * Registers a tracked aggregate for physical removal at commit.
4072
4083
  *
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
  /**