@shirudo/ddd-kit 3.0.0-rc.4 → 3.0.0-rc.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -20
- package/dist/chunks/{errors.d.ts → kit-errors.d.ts} +272 -48
- package/dist/chunks/{errors.js → kit-errors.js} +275 -57
- package/dist/chunks/kit-errors.js.map +1 -0
- package/dist/chunks/ports.js +910 -110
- package/dist/chunks/ports.js.map +1 -1
- package/dist/chunks/snapshot-store.d.ts +925 -1338
- package/dist/http.d.ts +2 -3
- package/dist/http.js +1 -1
- package/dist/http.js.map +1 -1
- package/dist/index.d.ts +3469 -2432
- package/dist/index.js +5663 -4869
- package/dist/index.js.map +1 -1
- package/dist/money.d.ts +11 -11
- package/dist/money.js +9 -9
- package/dist/money.js.map +1 -1
- package/dist/{presentation.d.ts → public-errors.d.ts} +5 -6
- package/dist/{presentation.js → public-errors.js} +5 -5
- package/dist/public-errors.js.map +1 -0
- package/dist/testing.d.ts +61 -11
- package/dist/testing.js +526 -56
- package/dist/testing.js.map +1 -1
- package/package.json +18 -18
- package/dist/chunks/deep-equal-except.js +0 -639
- package/dist/chunks/deep-equal-except.js.map +0 -1
- package/dist/chunks/errors.js.map +0 -1
- package/dist/chunks/utils.d.ts +0 -110
- package/dist/presentation.js.map +0 -1
- package/dist/utils.d.ts +0 -2
- package/dist/utils.js +0 -3
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["capabilities","capabilities","invalid","#snapshot","#evaluating"],"sources":["../src/aggregate/aggregate.ts","../src/entity/entity.ts","../src/aggregate/global-capability-registry.ts","../src/aggregate/pending-event-lifecycle.ts","../src/aggregate/pending-event-recording.ts","../src/aggregate/base-aggregate.ts","../src/aggregate/aggregate-root.ts","../src/aggregate/event-sourced-aggregate.ts","../src/app/bus-internals.ts","../src/app/command-bus.ts","../src/events/json-value.ts","../src/app/command-outbox.ts","../src/app/domain-error-result.ts","../src/utils/abort.ts","../src/utils/validate.ts","../src/utils/execution.ts","../src/utils/observer.ts","../src/app/handler.ts","../src/app/idempotency.ts","../src/app/in-memory-idempotency-store.ts","../src/app/query-bus.ts","../src/app/record-pending-events.ts","../src/repo/identity-map.ts","../src/repo/persistence-model.ts","../src/app/unit-of-work.ts","../src/utils/delivery-failure.ts","../src/utils/backoff.ts","../src/utils/in-flight.ts","../src/utils/sleep.ts","../src/utils/poll-loop.ts","../src/deadlines/deadline-processor.ts","../src/deadlines/in-memory-deadline-store.ts","../src/domain-state-machine/errors.ts","../src/domain-state-machine/machine-data.ts","../src/domain-state-machine/definition.ts","../src/domain-state-machine/snapshot.ts","../src/domain-state-machine/transition.ts","../src/domain-state-machine/analyzer.ts","../src/domain-state-machine/domain-state-machine.ts","../src/events/event-bus.ts","../src/events/integration-message.ts","../src/aggregate/aggregate-address.ts","../src/events/outbox.ts","../src/events/outbox-dispatcher.ts","../src/projections/ports.ts","../src/projections/in-memory-checkpoint-store.ts","../src/projections/projection-from-handlers.ts","../src/projections/projector.ts","../src/repo/in-memory-event-store.ts","../src/repo/in-memory-snapshot-store.ts","../src/repo/retrying-scope.ts","../src/repo/snapshot-model.ts","../src/specification/specification.ts","../src/validation/vo-validated.ts"],"sourcesContent":["import type { Result } from \"@shirudo/result\";\nimport type { DomainError } from \"../core/errors\";\nimport type { Id } from \"../core/id\";\nimport type { AnyDomainEvent, PendingDomainEvent } from \"./domain-event\";\n\n// Re-export domain event types for convenience\nexport * from \"./domain-event\";\n\n// --- Aggregate types ---\n\nexport type Version = number & { readonly __v: true };\n\n/**\n * Snapshot of an aggregate state at a specific point in time.\n * Used for optimizing event replay by starting from a snapshot\n * instead of replaying all events from the beginning.\n *\n * @template TState - The type of the aggregate state\n */\nexport interface AggregateSnapshot<TState> {\n\t/**\n\t * The state of the aggregate at the time of the snapshot.\n\t */\n\treadonly state: TState;\n\n\t/**\n\t * The version of the aggregate when the snapshot was taken.\n\t */\n\treadonly version: Version;\n\n\t/**\n\t * Timestamp when the snapshot was created.\n\t */\n\treadonly snapshotAt: Date;\n\n\t/**\n\t * Schema version of the stored `state` shape, declared by its adapter-owned\n\t * `SnapshotModel` and stamped by `captureAggregateSnapshot`. Distinct from\n\t * {@link version}, which counts mutations: this field says \"which\n\t * shape does the stored state have\", so a restore can detect a\n\t * snapshot written against an older DTO shape and migrate or\n\t * discard it instead of crashing later. Optional: absent on snapshots\n\t * written by older kit versions, which restore treats as schema `1`.\n\t */\n\treadonly schemaVersion?: number;\n}\n\n/**\n * Public contract every Aggregate Root satisfies. Implemented by\n * `BaseAggregate` and inherited by both `AggregateRoot` and\n * `EventSourcedAggregate`. Repository ports use this interface as their\n * aggregate type rather than depending on concrete base classes, so persistence\n * orchestration does not take a compile-time\n * dependency on the aggregate hierarchy.\n *\n * Full per-member documentation lives on the concrete `BaseAggregate`\n * class; the interface is intentionally terse to avoid drift. Persistence\n * facts are readable, but acknowledgement and pending-event disposal are not\n * part of this surface. `withCommit` and `UnitOfWork` hold that authority.\n *\n * @template TId - The aggregate root identifier (branded via `Id<Tag>`)\n * @template TEvent - The domain-event union, defaults to `never`\n */\nexport interface IAggregateRoot<\n\tTId extends Id<string>,\n\tTEvent extends AnyDomainEvent = never,\n> {\n\treadonly id: TId;\n\treadonly version: Version;\n\treadonly pendingEvents: ReadonlyArray<PendingDomainEvent<TEvent>>;\n}\n\n/**\n * Public contract for Event-Sourced Aggregate Roots. Extends\n * `IAggregateRoot` with the replay-from-history boundary.\n *\n * @template TId - The aggregate root identifier\n * @template TEvent - The union type of all domain events\n */\nexport interface IEventSourcedAggregate<\n\tTId extends Id<string>,\n\tTEvent extends AnyDomainEvent,\n> extends IAggregateRoot<TId, TEvent> {\n\t/**\n\t * Reconstitutes the aggregate from an event history. Returns\n\t * `Result` because event-stream corruption is an expected\n\t * recoverable failure at the infrastructure boundary.\n\t */\n\tloadFromHistory(history: ReadonlyArray<TEvent>): Result<void, DomainError>;\n}\n\n/**\n * Checks if two aggregates are at the same version (same ID and version).\n * Useful for optimistic concurrency control checks.\n *\n * Note: Two aggregates with the same ID ARE the same aggregate (identity).\n * This function checks if they are at the same version: i.e., no concurrent modification.\n *\n * @example\n * ```typescript\n * const before = await repository.findById(id);\n * // ... some operations ...\n * const after = await repository.findById(id);\n *\n * if (!sameVersion(before, after)) {\n * throw new Error(\"Aggregate was modified by another process\");\n * }\n * ```\n */\nexport function sameVersion<TId extends Id<string>>(\n\ta: { id: TId; version: Version },\n\tb: { id: TId; version: Version },\n): boolean {\n\treturn a.id === b.id && a.version === b.version;\n}\n","/**\n * Entity utilities and interfaces for Domain-Driven Design.\n *\n * In Domain-Driven Design, there are two types of entities:\n *\n * 1. **Aggregate Root Entity**: The parent Entity of an aggregate.\n * - Has identity (id), state, and version\n * - Implemented by classes extending `AggregateRoot` or `EventSourcedAggregate`\n * - Represents the aggregate externally\n * - Loaded/saved through repositories\n *\n * 2. **Child Entities**: Entities within an aggregate.\n * - Have identity (id) and state, but no own version\n * - Can extend `Entity<TState, TId>` for class-based entities\n * - Or use functional style with `Identifiable<TId> & TProps`\n * - Exist only within the aggregate boundary\n * - Versioned through the Aggregate Root\n * - Cannot be referenced directly from outside the aggregate\n *\n * This module provides:\n * - `Entity<TState, TId>` - Base class for entities with state\n * - `EntityConfig` - Construction options (validation and opt-in deep freeze)\n * - `Identifiable<TId>` - Minimal interface for objects with id\n * - Helper functions for working with collections of entities\n *\n * @example\n * ```typescript\n * // Class-based child entity with logic\n * const validateOrderItemState = (state: OrderItemState): void => {\n * if (state.quantity < 1) throw new Error(\"quantity must be positive\");\n * };\n *\n * class OrderItem extends Entity<OrderItemState, ItemId> {\n * constructor(id: ItemId, initialState: OrderItemState) {\n * super(id, initialState, { validateState: validateOrderItemState });\n * }\n *\n * updateQuantity(quantity: number): void {\n * // setState runs validateState and re-freezes; a direct\n * // `this._state = ...` assignment would skip both.\n * this.setState({ ...this.state, quantity });\n * }\n *\n * calculateSubtotal(): number {\n * return this.state.price * this.state.quantity;\n * }\n * }\n *\n * // Functional-style child entity (simpler, no logic)\n * type OrderItem = Identifiable<ItemId> & {\n * productId: string;\n * quantity: number;\n * price: number;\n * };\n *\n * // Aggregate Root (Entity with version)\n * class Order extends AggregateRoot<OrderState, OrderId> {\n * // Order is an Aggregate Root Entity\n * // OrderState contains OrderItem child entities\n * }\n * ```\n */\nimport { assertNoHostileOwnProtoKey } from \"../core/errors\";\nimport type { Id } from \"../core/id\";\nimport { deepFreeze } from \"../value-object/value-object\";\n\n/** A pure invariant check that throws when a candidate state is invalid. */\nexport type StateValidator<TState> = (state: TState) => void;\n\n/**\n * Construction options shared by `Entity` and (via `AggregateConfig`) the\n * aggregate base classes.\n */\nexport interface EntityConfig<TState = unknown> {\n\t/**\n\t * Pure state-invariant validator captured by the entity instance. It runs\n\t * against the exact frozen state stored during construction and every\n\t * {@link Entity.setState} call. Throw to reject the candidate state.\n\t *\n\t * Passing validation as data avoids virtual dispatch from the base\n\t * constructor: the function cannot observe partly initialised subclass\n\t * fields through `this`. Close over immutable policy supplied to the\n\t * concrete constructor when validation needs instance-specific inputs.\n\t */\n\treadonly validateState?: StateValidator<TState>;\n\n\t/**\n\t * Opt-in: freeze the WHOLE state graph (via `deepFreeze`) instead of\n\t * the default shallow freeze. This protects against nested aliases\n\t * retained by constructor callers and against accidental in-place\n\t * writes inside the entity; live state itself is never public.\n\t *\n\t * Defaults to `false` (the documented shallow contract): deep freezing\n\t * costs a full state-graph walk on every state write, which is why it\n\t * is not the default on hot paths.\n\t *\n\t * **Only for plain-data states.** The deep freeze walks the entire\n\t * graph: a class-based child entity inside the state would be frozen\n\t * too, and its own mutation methods would start throwing. States\n\t * carrying class-based children must keep the default shallow freeze.\n\t * Note that the ownership transfer widens accordingly: nested objects\n\t * passed into the constructor or `setState` are frozen IN PLACE (the\n\t * shallow copy protects only the top-level input object).\n\t */\n\tdeepFreezeState?: boolean;\n}\n\n/**\n * Functional definition of an Entity via its capability: an object is\n * identifiable if it has an `id`.\n *\n * `TId` is constrained to `Id<string>` so the brand discipline that\n * `Id<Tag>` enforces is preserved end-to-end: an `Identifiable<UserId>`\n * cannot accidentally be paired with an `Identifiable<OrderId>` or with\n * a plain `string`.\n */\nexport type Identifiable<TId extends Id<string>> = {\n\treadonly id: TId;\n};\n\n/**\n * Interface for Entities with state.\n *\n * In Domain-Driven Design, Entities have:\n * - Identity (id): Distinguishes one entity from another\n * - State: The attributes/properties of the entity\n *\n * Unlike Value Objects (which are immutable and compared by value),\n * Entities are compared by identity and can have mutable state.\n *\n * @template TId - The type of the entity identifier\n */\nexport interface IEntity<TId extends Id<string>> extends Identifiable<TId> {\n\t/**\n\t * Unique identifier of the entity.\n\t */\n\treadonly id: TId;\n}\n\n/**\n * Abstract base class for Entities with state.\n *\n * Provides:\n * - Identity management (id)\n * - State management\n * - Instance-bound pure state validation\n * - Protected state access for domain behavior\n *\n * This is the foundation for all Entities in DDD:\n * - Child Entities within aggregates can extend this\n * - Aggregate Roots extend this and add version + events\n *\n * @template TState - The type of the entity state\n * @template TId - The type of the entity identifier\n *\n * @example\n * ```typescript\n * // Child Entity within an aggregate\n * const validateOrderItemState = (state: OrderItemState): void => {\n * if (state.quantity < 1) throw new Error(\"quantity must be positive\");\n * };\n *\n * class OrderItem extends Entity<OrderItemState, ItemId> {\n * constructor(id: ItemId, initialState: OrderItemState) {\n * super(id, initialState, { validateState: validateOrderItemState });\n * }\n *\n * updateQuantity(quantity: number): void {\n * // setState runs validateState and re-freezes; a direct\n * // `this._state = ...` assignment would skip both.\n * this.setState({ ...this.state, quantity });\n * }\n * }\n * ```\n */\nexport abstract class Entity<TState, TId extends Id<string>>\n\timplements IEntity<TId>\n{\n\tpublic readonly id: TId;\n\n\t/**\n\t * Returns the live state to subclass domain behavior.\n\t *\n\t * This accessor is deliberately protected: returning the generic\n\t * `TState` publicly would expose the aggregate's live object graph and\n\t * let nested mutation bypass behavior, validation, versioning, and\n\t * dirty tracking. Concrete entities should expose business-meaningful queries or\n\t * detached immutable DTOs. Snapshot projection belongs to an adapter-owned\n\t * `SnapshotModel`; persistence code captures an aggregate with\n\t * `captureAggregateSnapshot(model, aggregate, snapshotAt)` rather than\n\t * asking the entity to create its own persistence memento.\n\t */\n\tprotected get state(): TState {\n\t\treturn this._state;\n\t}\n\n\t/**\n\t * The state is `protected` so that only the subclass can modify it.\n\t * Ordinary entity behavior must use {@link setState}; direct assignment\n\t * skips instance-bound validation. Kit event-sourcing internals use direct\n\t * assignment deliberately because historical evolution must not run\n\t * today's decision validator.\n\t */\n\tprotected _state: TState;\n\n\tprivate readonly _stateFreezeMode: StateFreezeMode;\n\tprivate readonly validateState: StateValidator<TState>;\n\n\t/**\n\t * **State ownership.** Plain-object and array states are shallow-copied\n\t * before the freeze, so the caller's own object stays mutable. A CLASS\n\t * INSTANCE passed as state is an ownership transfer: it is frozen\n\t * in place (a copy would strip its prototype). Do not keep mutating\n\t * the instance after handing it to the entity. The same contract\n\t * applies to {@link setState}. With\n\t * {@link EntityConfig.deepFreezeState} enabled, the ownership transfer\n\t * widens to the whole graph: NESTED objects are frozen in place too.\n\t *\n\t * @throws HostileStateKeyError when a plain-object, null-prototype,\n\t * or array state carries an own `\"__proto__\"` data key; validate and\n\t * strip untrusted input at the boundary.\n\t */\n\tprotected constructor(\n\t\tid: TId,\n\t\tinitialState: TState,\n\t\tconfig?: EntityConfig<TState>,\n\t) {\n\t\tif (id === null || id === undefined) {\n\t\t\tthrow new Error(\"Entity ID cannot be null or undefined\");\n\t\t}\n\t\tthis.id = id;\n\t\tthis._stateFreezeMode = config?.deepFreezeState ?? false ? \"deep\" : \"shallow\";\n\t\tthis.validateState = config?.validateState ?? noStateValidation;\n\t\t// Both mutation paths validate the exact frozen object that is stored.\n\t\t// Assigning the validator as an own property before invoking it also\n\t\t// prevents same-named prototype methods in JavaScript consumers from\n\t\t// turning this constructor call back into virtual dispatch. The module\n\t\t// freeze helper similarly avoids the protected post-construction hook.\n\t\tthis._state = freezeStateByMode(\n\t\t\tshallowCopyOwned(initialState),\n\t\t\tthis._stateFreezeMode,\n\t\t);\n\t\tthis.validateState(this._state);\n\t}\n\n\t/**\n\t * Freezes a state value according to this entity's configured freeze\n\t * mode: the default shallow freeze, or `deepFreeze` when\n\t * {@link EntityConfig.deepFreezeState} was enabled at construction.\n\t * Infrastructure-style subclass code that deliberately assigns\n\t * `this._state` directly must freeze through this method, not\n\t * `freezeShallow`, or the opt-in silently degrades to shallow for that\n\t * path. Ordinary domain behavior should use {@link setState} instead.\n\t */\n\tprotected freezeState(value: TState): TState {\n\t\treturn freezeStateByMode(value, this._stateFreezeMode);\n\t}\n\n\t/**\n\t * Sets the state of the entity.\n\t * This is a convenience method for state mutations.\n\t * Automatically validates `newState` with the instance-bound\n\t * {@link EntityConfig.validateState} function.\n\t *\n\t * Plain-object and array states are shallow-copied before the freeze\n\t * (the caller's object stays mutable); a class-instance state is an\n\t * ownership transfer and is frozen in place; see the constructor.\n\t *\n\t * @param newState - The new state\n\t * @throws HostileStateKeyError when the state carries an own\n\t * `\"__proto__\"` data key; the previous state is kept.\n\t */\n\tprotected setState(newState: TState): void {\n\t\t// Same copy-freeze-validate-assign order as the constructor: the\n\t\t// object validated IS the object stored, and a validation throw\n\t\t// leaves the previous state untouched.\n\t\tconst next = this.freezeState(shallowCopyOwned(newState));\n\t\tthis.validateState(next);\n\t\tthis._state = next;\n\t}\n}\n\nconst noStateValidation: StateValidator<unknown> = () => {};\n\n/** The entity's configured freeze depth, fixed once at construction. */\ntype StateFreezeMode = \"shallow\" | \"deep\";\n\nfunction freezeStateByMode<TState>(\n\tvalue: TState,\n\tmode: StateFreezeMode,\n): TState {\n\treturn mode === \"deep\" ? (deepFreeze(value) as TState) : freezeShallow(value);\n}\n\n/**\n * Shallow-freezes `value` when it's a non-null object or array, so that\n * direct property writes throw in strict mode. Returns the value as-is for\n * primitives. Used internally by `Entity` (via `freezeState`, which picks\n * shallow or deep per the `deepFreezeState` config) to prevent outside\n * mutation of state read through the `state` getter without paying the\n * cost of a deep clone on every read.\n *\n * Subclass code that assigns `this._state` directly should freeze through\n * the protected `freezeState(value)` method rather than calling this\n * helper, so the configured freeze mode is honored. The export remains\n * for consumers using it as a standalone utility.\n */\nexport function freezeShallow<T>(value: T): T {\n\tif (value !== null && typeof value === \"object\") {\n\t\treturn Object.freeze(value);\n\t}\n\treturn value;\n}\n\n/**\n * Returns a shallow copy for plain objects and arrays so the subsequent\n * `freezeShallow` never locks the caller's own object in place (their later\n * writes to it would throw in strict mode). Class instances and primitives\n * pass through unchanged: a spread would strip an instance's prototype,\n * and handing a class instance as state is an ownership transfer. Nested\n * objects stay shared by design (shallow-freeze, no deep clone).\n */\nfunction shallowCopyOwned<T>(value: T): T {\n\tif (value === null || typeof value !== \"object\") return value;\n\tif (Array.isArray(value)) {\n\t\tassertNoHostileOwnProtoKey(value, \"Entity state\");\n\t\t// Spread copies only iterated index elements; transfer own\n\t\t// enumerable NON-INDEX keys (items.total = 5 style annotations) as\n\t\t// data properties too, mirroring the plain-object branch, so the\n\t\t// copy never silently loses caller state.\n\t\tconst copy = [...value];\n\t\tfor (const key of Reflect.ownKeys(value)) {\n\t\t\tif (key === \"length\" || Object.hasOwn(copy, key)) continue;\n\t\t\tconst descriptor = Object.getOwnPropertyDescriptor(value, key);\n\t\t\tif (!descriptor?.enumerable) continue;\n\t\t\tObject.defineProperty(copy, key, {\n\t\t\t\tvalue: (value as Record<PropertyKey, unknown>)[key],\n\t\t\t\twritable: true,\n\t\t\t\tenumerable: true,\n\t\t\t\tconfigurable: true,\n\t\t\t});\n\t\t}\n\t\treturn copy as T;\n\t}\n\tconst proto = Object.getPrototypeOf(value);\n\tif (proto !== Object.prototype && proto !== null) return value;\n\tassertNoHostileOwnProtoKey(value, \"Entity state\");\n\t// Copy as data properties, never through [[Set]]: object spread uses\n\t// CreateDataProperty, so even without the guard above no key could\n\t// reach the `__proto__` setter the way Object.assign onto an\n\t// Object.prototype-based target would. On a null-prototype target no\n\t// setter exists in the chain, so Object.assign is safe there.\n\treturn (\n\t\tproto === null ? Object.assign(Object.create(null), value) : { ...value }\n\t) as T;\n}\n\n/**\n * Checks if two entities have the same ID.\n * Works with any object that has an 'id' property.\n *\n * @param a - First entity\n * @param b - Second entity\n * @returns true if both entities have the same ID, false otherwise\n *\n * @example\n * ```typescript\n * const item1: OrderItem = { id: itemId1, productId: \"prod-1\", quantity: 2 };\n * const item2: OrderItem = { id: itemId2, productId: \"prod-2\", quantity: 1 };\n *\n * sameEntity(item1, item2); // false\n * sameEntity(item1, item1); // true\n * ```\n */\nexport function sameEntity<TId extends Id<string>>(\n\ta: Identifiable<TId>,\n\tb: Identifiable<TId>,\n): boolean {\n\treturn a.id === b.id;\n}\n\n/**\n * Finds an entity by ID in a collection.\n * Returns undefined if not found.\n *\n * @param entities - Array of entities to search\n * @param id - The ID to search for\n * @returns The entity if found, undefined otherwise\n *\n * @example\n * ```typescript\n * const items: OrderItem[] = [\n * { id: itemId1, productId: \"prod-1\", quantity: 2 },\n * { id: itemId2, productId: \"prod-2\", quantity: 1 }\n * ];\n *\n * const item = findEntityById(items, itemId1);\n * // item is { id: itemId1, productId: \"prod-1\", quantity: 2 }\n * ```\n */\nexport function findEntityById<\n\tTId extends Id<string>,\n\tT extends Identifiable<TId>,\n>(entities: ReadonlyArray<T>, id: TId): T | undefined {\n\treturn entities.find((entity) => entity.id === id);\n}\n\n/**\n * Checks if an entity with the given ID exists in the collection.\n *\n * @param entities - Array of entities to search\n * @param id - The ID to check for\n * @returns true if an entity with the ID exists, false otherwise\n *\n * @example\n * ```typescript\n * const items: OrderItem[] = [\n * { id: itemId1, productId: \"prod-1\", quantity: 2 }\n * ];\n *\n * hasEntityId(items, itemId1); // true\n * hasEntityId(items, itemId2); // false\n * ```\n */\nexport function hasEntityId<\n\tTId extends Id<string>,\n\tT extends Identifiable<TId>,\n>(entities: ReadonlyArray<T>, id: TId): boolean {\n\treturn entities.some((entity) => entity.id === id);\n}\n\n/**\n * Removes an entity with the given ID from the collection. Returns the\n * ORIGINAL array when the id is absent (structural sharing for the\n * reference-based dirty tracking; see `updateEntityById`), otherwise a\n * new array without the entity.\n *\n * @param entities - Array of entities\n * @param id - The ID of the entity to remove\n * @returns A new array without the entity with the given ID\n *\n * @example\n * ```typescript\n * const items: OrderItem[] = [\n * { id: itemId1, productId: \"prod-1\", quantity: 2 },\n * { id: itemId2, productId: \"prod-2\", quantity: 1 }\n * ];\n *\n * const updated = removeEntityById(items, itemId1);\n * // updated is [{ id: itemId2, productId: \"prod-2\", quantity: 1 }]\n * ```\n */\nexport function removeEntityById<\n\tTId extends Id<string>,\n\tT extends Identifiable<TId>,\n>(entities: ReadonlyArray<T>, id: TId): ReadonlyArray<T> {\n\tconst filtered = entities.filter((entity) => entity.id !== id);\n\treturn filtered.length === entities.length ? entities : filtered;\n}\n\n/**\n * Updates an entity with the given ID in the collection.\n * Returns a new array with the updated entity.\n * Structural sharing for adapter-owned persistence projections: returns\n * the ORIGINAL array when nothing changed (no match, or the element kept\n * its reference), so a partial-write adapter can skip the untouched\n * collection; a new array only when an\n * element reference actually changed. The result is `ReadonlyArray<T>`:\n * it may BE the (possibly frozen) input; spread it if you need a mutable\n * copy.\n *\n * @param entities - Array of entities\n * @param id - The ID of the entity to update\n * @param updater - Function that takes the entity and returns the updated entity\n * @returns A new array with the updated entity\n *\n * @example\n * ```typescript\n * const items: OrderItem[] = [\n * { id: itemId1, productId: \"prod-1\", quantity: 2 }\n * ];\n *\n * const updated = updateEntityById(items, itemId1, (item) => ({\n * ...item,\n * quantity: item.quantity + 1\n * }));\n * // updated is [{ id: itemId1, productId: \"prod-1\", quantity: 3 }]\n * ```\n */\nexport function updateEntityById<\n\tTId extends Id<string>,\n\tT extends Identifiable<TId>,\n>(\n\tentities: ReadonlyArray<T>,\n\tid: TId,\n\tupdater: (entity: T) => T,\n): ReadonlyArray<T> {\n\tlet changed = false;\n\tconst mapped = entities.map((entity) => {\n\t\tif (entity.id !== id) return entity;\n\t\tconst next = updater(entity);\n\t\tif (next !== entity) changed = true;\n\t\treturn next;\n\t});\n\treturn changed ? mapped : entities;\n}\n\n/**\n * Replaces an entity with the given ID in the collection.\n * Returns a new array with the replaced entity.\n * Structural sharing for adapter-owned persistence projections: returns\n * the ORIGINAL array when nothing changed (no match, or the element kept\n * its reference), so a partial-write adapter can skip the untouched\n * collection; a new array only when an\n * element reference actually changed. The result is `ReadonlyArray<T>`:\n * it may BE the (possibly frozen) input; spread it if you need a mutable\n * copy.\n *\n * @param entities - Array of entities\n * @param id - The ID of the entity to replace\n * @param replacement - The replacement entity\n * @returns A new array with the replaced entity\n *\n * @example\n * ```typescript\n * const items: OrderItem[] = [\n * { id: itemId1, productId: \"prod-1\", quantity: 2 }\n * ];\n *\n * const updated = replaceEntityById(items, itemId1, {\n * id: itemId1,\n * productId: \"prod-1\",\n * quantity: 5\n * });\n * ```\n */\nexport function replaceEntityById<\n\tTId extends Id<string>,\n\tT extends Identifiable<TId>,\n>(entities: ReadonlyArray<T>, id: TId, replacement: T): ReadonlyArray<T> {\n\tlet changed = false;\n\tconst mapped = entities.map((entity) => {\n\t\tif (entity.id !== id) return entity;\n\t\tif (replacement !== entity) changed = true;\n\t\treturn replacement;\n\t});\n\treturn changed ? mapped : entities;\n}\n\n/**\n * Extracts all IDs from a collection of entities.\n *\n * @param entities - Array of entities\n * @returns Array of entity IDs\n *\n * @example\n * ```typescript\n * const items: OrderItem[] = [\n * { id: itemId1, productId: \"prod-1\", quantity: 2 },\n * { id: itemId2, productId: \"prod-2\", quantity: 1 }\n * ];\n *\n * const ids = entityIds(items);\n * // ids is [itemId1, itemId2]\n * ```\n */\nexport function entityIds<TId extends Id<string>, T extends Identifiable<TId>>(\n\tentities: ReadonlyArray<T>,\n): TId[] {\n\treturn entities.map((entity) => entity.id);\n}\n","/**\n * Shared bootstrap for the kit's cross-copy capability registries.\n *\n * A registry is a WeakMap installed once on `globalThis` under a versioned\n * `Symbol.for` key, so aggregates constructed by a bundled plugin copy of\n * the kit cooperate with the host package copy. The key version stamps the\n * capability SHAPE: registrations made under another key stay invisible, so\n * an incompatible copy fails the caller's generic capability check instead\n * of half-working.\n *\n * A registry is not a security boundary against code already running in the\n * same process; it is an architectural boundary kept out of package exports\n * and public aggregate types.\n */\nexport function createGlobalCapabilityRegistry<TCapability extends object>(\n\tkey: symbol,\n): WeakMap<object, TCapability> {\n\tconst existing = Object.getOwnPropertyDescriptor(globalThis, key)?.value;\n\tif (existing instanceof WeakMap) {\n\t\treturn existing as WeakMap<object, TCapability>;\n\t}\n\n\tconst registry = new WeakMap<object, TCapability>();\n\ttry {\n\t\tObject.defineProperty(globalThis, key, {\n\t\t\tvalue: registry,\n\t\t\tenumerable: false,\n\t\t\twritable: false,\n\t\t\tconfigurable: false,\n\t\t});\n\t} catch {\n\t\t// A hardened host may reject global registration. The local registry\n\t\t// still preserves the capability boundary; only duplicate-package\n\t\t// cooperation is unavailable in that host.\n\t}\n\treturn registry;\n}\n","import { createGlobalCapabilityRegistry } from \"./global-capability-registry\";\n\n/**\n * Kit-internal authority for acknowledging one exact pending-event batch.\n *\n * Kept out of every package entry point: repositories may inspect aggregate\n * state and pending events, but only application commit orchestration may\n * acknowledge or discard them after the surrounding transaction commits.\n */\nexport interface PendingEventLifecycleCapability {\n\t/**\n\t * Acknowledges the committed batch. `committedVersion` is the version the\n\t * commit actually persisted (captured at enrollment); the aggregate syncs\n\t * its persisted-version marker from it rather than from its live version,\n\t * so un-awaited concurrent work mutating the instance in the post-commit\n\t * window cannot desync the marker.\n\t */\n\tacknowledge(events: ReadonlyArray<unknown>, committedVersion?: number): void;\n\tdiscardPendingEvents(events: ReadonlyArray<unknown>): void;\n\t/**\n\t * Version the persistence layer last confirmed for the aggregate, or\n\t * `undefined` for a never-persisted instance. Grounds the `withCommit`\n\t * unique-cursor guard.\n\t */\n\tpersistedVersion(): number | undefined;\n\t/**\n\t * Count of unflushed pending events. The public `pendingEvents` getter\n\t * allocates and freezes a defensive copy per read, which count-only\n\t * consumers (the identity map's end-of-run scan) do not need.\n\t */\n\tpendingEventCount(): number;\n}\n\n// The key version stamps the capability SHAPE. Bump it whenever the\n// interface above changes: registrations made under another key stay\n// invisible, so an aggregate constructed by an incompatible package copy\n// fails the generic \"no kit-managed persistence lifecycle\" check instead of\n// half-working through a shape it does not fully implement.\nconst persistenceCapabilityRegistryKey = Symbol.for(\n\t\"@shirudo/ddd-kit/pending-event-lifecycle-registry/v4\",\n);\n\nconst capabilities = createGlobalCapabilityRegistry<PendingEventLifecycleCapability>(\n\tpersistenceCapabilityRegistryKey,\n);\n\nexport function registerPendingEventLifecycleCapability(\n\taggregate: object,\n\tcapability: PendingEventLifecycleCapability,\n): void {\n\tconst frozen = Object.freeze(capability);\n\tcapabilities.set(aggregate, frozen);\n}\n\nexport function pendingEventLifecycleCapabilityFor(\n\taggregate: object,\n): PendingEventLifecycleCapability | undefined {\n\treturn capabilities.get(aggregate);\n}\n","import { createGlobalCapabilityRegistry } from \"./global-capability-registry\";\nimport type {\n\tAnyDomainEvent,\n\tAnyUncommittedDomainEvent,\n\tDomainEventStamp,\n} from \"./domain-event\";\n\nexport type PendingEventStampFactory = (\n\tevent: AnyUncommittedDomainEvent,\n\tindex: number,\n) => DomainEventStamp;\n\nexport interface PendingEventRecordingCapability {\n\treadonly record: (\n\t\tcreateStamp: PendingEventStampFactory,\n\t) => ReadonlyArray<AnyDomainEvent>;\n}\n\n// The key version stamps the capability SHAPE, mirroring\n// pending-event-lifecycle.ts. Bump it whenever the interface above changes:\n// registrations made under another key stay invisible, so an aggregate\n// constructed by an incompatible package copy fails the caller's generic\n// \"created by this package\" check instead of half-working.\nconst recordingCapabilityRegistryKey = Symbol.for(\n\t\"@shirudo/ddd-kit/pending-event-recording-registry/v1\",\n);\n\nconst capabilities = createGlobalCapabilityRegistry<PendingEventRecordingCapability>(\n\trecordingCapabilityRegistryKey,\n);\n\nexport function registerPendingEventRecordingCapability(\n\taggregate: object,\n\tcapability: PendingEventRecordingCapability,\n): void {\n\tcapabilities.set(aggregate, Object.freeze(capability));\n}\n\nexport function pendingEventRecordingCapabilityFor(\n\taggregate: object,\n): PendingEventRecordingCapability | undefined {\n\treturn capabilities.get(aggregate);\n}\n","import {\n\tDuplicateEventIdError,\n\tReentrantEventRecordingError,\n\tUnmintedEventError,\n\tUnreplayableAggregateError,\n} from \"../core/errors\";\nimport type { Id } from \"../core/id\";\nimport { Entity, type EntityConfig } from \"../entity/entity\";\nimport type { IAggregateRoot, Version } from \"./aggregate\";\nimport {\n\ttype AnyDomainEvent,\n\ttype AnyUncommittedDomainEvent,\n\ttype CreateUncommittedDomainEventOptions,\n\tcreateUncommittedDomainEvent,\n\tisMintedEvent,\n\tisUncommittedDomainEvent,\n\ttype PendingDomainEvent,\n\trecordDomainEvent,\n\ttype UncommittedDomainEventOf,\n} from \"./domain-event\";\nimport { registerPendingEventLifecycleCapability } from \"./pending-event-lifecycle\";\nimport { registerPendingEventRecordingCapability } from \"./pending-event-recording\";\n\n/** Construction options shared by state-stored and event-sourced aggregates. */\nexport type AggregateConfig<TState = unknown> = EntityConfig<TState>;\n\n/**\n * Shared base for both `AggregateRoot` (state-stored) and\n * `EventSourcedAggregate`. Carries the lifecycle machinery that's\n * identical across the two flavours: current version, pending-event\n * tracking, the kit-internal post-commit acknowledgement capability,\n * the `markRestored` post-load marker, and the `createEvent` helper\n * that auto-injects `aggregateId` + `aggregateType` on every event the\n * aggregate emits. The application shell records the pending decisions\n * with `recordPendingEvents` before persistence.\n *\n * Consumers do NOT extend this class directly; extend\n * `AggregateRoot` for state-stored aggregates or\n * `EventSourcedAggregate` for event-sourced ones. The split between\n * those two reflects the canonical Vernon §8 (state-stored) /\n * Vernon §11 + Greg Young (event-sourced) distinction in how state\n * is represented; the lifecycle machinery is the same for both.\n *\n * @template TState - The type of the aggregate state\n * @template TId - The aggregate root identifier\n * @template TEvent - The domain-event union. Defaults to `never` so\n * aggregates without a declared event type cannot emit events\n * (emitting any event becomes a compile error).\n */\nexport abstract class BaseAggregate<\n\t\tTState,\n\t\tTId extends Id<string>,\n\t\tTEvent extends AnyDomainEvent = never,\n\t>\n\textends Entity<TState, TId>\n\timplements IAggregateRoot<TId, TEvent>\n{\n\t/**\n\t * The aggregate's domain type as a string, used to populate\n\t * `aggregateType` on events created via {@link createEvent}.\n\t *\n\t * Subclasses MUST declare this as a string literal:\n\t *\n\t * ```ts\n\t * class Order extends AggregateRoot<OrderState, OrderId, OrderEvent> {\n\t * protected readonly aggregateType = \"Order\";\n\t * }\n\t * ```\n\t *\n\t * The string is *the* identifier downstream consumers (outbox\n\t * dispatchers, projection handlers, audit logs) use to route by\n\t * aggregate kind. Use the same canonical name across your system;\n\t * matching the class name is the obvious choice, but the value\n\t * comes from this explicit declaration, not `constructor.name`\n\t * (which is fragile under minification, bundler transforms, and\n\t * subclass renaming).\n\t */\n\tprotected abstract readonly aggregateType: string;\n\n\tprivate _version: Version = 0 as Version;\n\n\t/**\n\t * Version the persistence layer last confirmed for this instance:\n\t * `undefined` until the aggregate is reconstituted (`markRestored`) or a\n\t * commit is acknowledged. Kit-internal via the lifecycle capability; it\n\t * grounds the `withCommit` unique-cursor guard so an eventful commit that\n\t * did not advance beyond the persisted row is rejected deterministically.\n\t */\n\tprivate _persistedVersion: Version | undefined;\n\n\tprivate _pendingEvents: PendingDomainEvent<TEvent>[] = [];\n\n\tprotected constructor(\n\t\tid: TId,\n\t\tinitialState: TState,\n\t\tconfig?: AggregateConfig<TState>,\n\t) {\n\t\tsuper(id, initialState, config);\n\t\tregisterPendingEventLifecycleCapability(this, {\n\t\t\tacknowledge: (events, committedVersion) => {\n\t\t\t\tthis.acknowledgePendingEvents(events, committedVersion);\n\t\t\t},\n\t\t\tdiscardPendingEvents: (events) => {\n\t\t\t\tthis.discardPendingEventsAfterDeletion(events);\n\t\t\t},\n\t\t\tpersistedVersion: () => this._persistedVersion,\n\t\t\tpendingEventCount: () => this._pendingEvents.length,\n\t\t});\n\t\tregisterPendingEventRecordingCapability(this, {\n\t\t\trecord: (createStamp) => {\n\t\t\t\tconst stamped = this._pendingEvents;\n\t\t\t\tconst stampedCount = stamped.length;\n\t\t\t\tconst recorded: TEvent[] = stamped.map((event, index) => {\n\t\t\t\t\tconst candidate = event as AnyDomainEvent | AnyUncommittedDomainEvent;\n\t\t\t\t\tif (isMintedEvent(candidate)) return candidate as TEvent;\n\t\t\t\t\tif (!isUncommittedDomainEvent(candidate)) {\n\t\t\t\t\t\tthrow new UnmintedEventError(\n\t\t\t\t\t\t\t(event as { readonly type: string }).type,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\treturn recordDomainEvent(\n\t\t\t\t\t\tcandidate,\n\t\t\t\t\t\tcreateStamp(candidate, index),\n\t\t\t\t\t) as TEvent;\n\t\t\t\t});\n\t\t\t\t// A stamp provider that triggers a new decision on this aggregate\n\t\t\t\t// grows or replaces the pending list mid-map; assigning `recorded`\n\t\t\t\t// would silently discard that decision. Checked BEFORE the\n\t\t\t\t// assignment, so recording stays atomic when the guard fires.\n\t\t\t\tif (\n\t\t\t\t\tthis._pendingEvents !== stamped ||\n\t\t\t\t\tthis._pendingEvents.length !== stampedCount\n\t\t\t\t) {\n\t\t\t\t\tthrow new ReentrantEventRecordingError(String(this.id));\n\t\t\t\t}\n\t\t\t\t// One identity per decision: a reused stamp would mint two facts\n\t\t\t\t// sharing one eventId, and idempotent consumers keyed on it\n\t\t\t\t// would silently drop one. Also checked before the assignment.\n\t\t\t\tconst seenEventIds = new Set<string>();\n\t\t\t\tfor (const event of recorded) {\n\t\t\t\t\tconst eventId = (event as AnyDomainEvent).eventId;\n\t\t\t\t\tif (seenEventIds.has(eventId)) {\n\t\t\t\t\t\tthrow new DuplicateEventIdError(String(this.id), eventId);\n\t\t\t\t\t}\n\t\t\t\t\tseenEventIds.add(eventId);\n\t\t\t\t}\n\t\t\t\tthis._pendingEvents = recorded;\n\t\t\t\treturn Object.freeze(recorded.slice()) as ReadonlyArray<AnyDomainEvent>;\n\t\t\t},\n\t\t});\n\t}\n\n\tprivate acknowledgePendingEvents(\n\t\tevents: ReadonlyArray<unknown>,\n\t\tcommittedVersion?: number,\n\t): void {\n\t\tthis.stripAcknowledgedPrefix(events);\n\t\t// The next eventful commit needs a cursor beyond the version this\n\t\t// commit persisted. The caller passes the enrollment-time version:\n\t\t// syncing from the live version instead would let un-awaited\n\t\t// concurrent work that mutates the instance in the post-commit window\n\t\t// desync the marker.\n\t\tthis._persistedVersion = (committedVersion ?? this._version) as Version;\n\t}\n\n\t/**\n\t * Post-commit cleanup for the deleted disposition. The row is gone, so\n\t * there is no persisted version to advance: stamping the marker from the\n\t * live instance would make a later legitimate re-enrollment of this\n\t * instance trip the unique-cursor guard for a row that does not exist.\n\t */\n\tprivate discardPendingEventsAfterDeletion(\n\t\tevents: ReadonlyArray<unknown>,\n\t): void {\n\t\tthis.stripAcknowledgedPrefix(events);\n\t}\n\n\tprivate stripAcknowledgedPrefix(events: ReadonlyArray<unknown>): void {\n\t\tif (\n\t\t\tevents.length > this._pendingEvents.length ||\n\t\t\tevents.some((event, index) => event !== this._pendingEvents[index])\n\t\t) {\n\t\t\tthrow new Error(\n\t\t\t\t\"The committed event batch is no longer the aggregate's pending prefix.\",\n\t\t\t);\n\t\t}\n\t\tthis._pendingEvents = this._pendingEvents.slice(events.length);\n\t}\n\n\tpublic get version(): Version {\n\t\treturn this._version;\n\t}\n\n\t/**\n\t * Read-only list of domain events recorded on this aggregate that\n\t * have not yet been flushed to the outbox / persistence layer.\n\t */\n\tpublic get pendingEvents(): ReadonlyArray<PendingDomainEvent<TEvent>> {\n\t\treturn Object.freeze(this._pendingEvents.slice());\n\t}\n\n\t/**\n\t * Count-only accessor for internal aggregate paths: the public\n\t * {@link pendingEvents} getter allocates and freezes\n\t * a defensive copy per read, which a length check does not need.\n\t */\n\tprotected get pendingEventCount(): number {\n\t\treturn this._pendingEvents.length;\n\t}\n\n\tprotected setVersion(version: Version): void {\n\t\tthis._version = version;\n\t}\n\n\t/**\n\t * Manually bumps the aggregate version. Used by state-stored\n\t * aggregates' `setState()` / `commit()` paths and by the\n\t * event-sourced replay path after each applied event.\n\t */\n\tprotected bumpVersion(): void {\n\t\tthis.setVersion((this._version + 1) as Version);\n\t}\n\n\t/**\n\t * **Lifecycle marker, Post-Load.** Syncs both `_version` and\n\t * the current version to the stored version. Used by\n\t * `reconstitute(...)` factories to assemble an in-memory aggregate\n\t * from a persisted row.\n\t *\n\t * The Factory-vs-Reconstitution distinction (Vernon §11) is honoured\n\t * structurally: reconstitution stays inside the aggregate factory while\n\t * post-commit acknowledgement belongs to application commit orchestration.\n\t *\n\t * If you override this, call `super.markRestored(version)` so the current\n\t * domain version remains aligned with the reconstituted facts.\n\t *\n\t * @param version - The version the row currently holds in the DB\n\t *\n\t * @example\n\t * ```ts\n\t * static reconstitute(id: OrderId, state: OrderState, version: Version): Order {\n\t * const order = new Order(id, state);\n\t * order.markRestored(version);\n\t * return order;\n\t * }\n\t * ```\n\t */\n\tprotected markRestored(version: Version): void {\n\t\tthis.setVersion(version);\n\t\tthis._persistedVersion = version;\n\t}\n\n\t/**\n\t * Appends a domain event to the pending list. Prefer the higher-level\n\t * `AggregateRoot.commit()` (state-stored) or `EventSourcedAggregate.apply()`\n\t * (event-sourced) call sites, both of which wrap `addDomainEvent` in the\n\t * canonical record-AFTER-mutation order (Vernon §8). Calling\n\t * `addDomainEvent` directly is appropriate only after a version-advancing\n\t * state mutation, or while constructing a never-persisted aggregate.\n\t * An event-only commit on an already-persisted aggregate has no unique\n\t * cursor and `withCommit` rejects it; use `commit(currentState, event)`.\n\t */\n\tprotected addDomainEvent(event: PendingDomainEvent<TEvent>): void {\n\t\tthis.assertMintedEvent(event);\n\t\tthis._pendingEvents.push(event);\n\t}\n\n\t/**\n\t * Immutability gate for every recording path: only events minted by\n\t * the kit's constructors (`createDomainEvent`,\n\t * `createDomainEventFromFacts`, `createEvent`) pass,\n\t * checked against the constructor's internal, unforgeable mint\n\t * marker. Minted implies deeply frozen with defensively copied\n\t * payload and metadata, a guarantee no frozen-ness probe can\n\t * establish (a shallow-frozen literal with mutable nested data\n\t * would fool it). O(1): one WeakSet lookup.\n\t */\n\tprotected assertMintedEvent(event: PendingDomainEvent<TEvent>): void {\n\t\tif (!isMintedEvent(event) && !isUncommittedDomainEvent(event)) {\n\t\t\tthrow new UnmintedEventError(\n\t\t\t\t(event as AnyDomainEvent | AnyUncommittedDomainEvent).type,\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Creates the immutable business fact accepted by this aggregate without\n\t * reading a clock, generating an id, or attaching tracing metadata.\n\t *\n\t * The application shell records pending events after the domain operation\n\t * and before persistence. Payload schema version stays here, next to the\n\t * concrete event producer, rather than in shell-owned recording data.\n\t */\n\tprotected createEvent<E extends TEvent>(\n\t\ttype: E[\"type\"],\n\t\tpayload: E[\"payload\"],\n\t\toptions?: Omit<\n\t\t\tCreateUncommittedDomainEventOptions,\n\t\t\t\"aggregateId\" | \"aggregateType\"\n\t\t>,\n\t): UncommittedDomainEventOf<E> {\n\t\treturn createUncommittedDomainEvent(type, payload, {\n\t\t\t...options,\n\t\t\taggregateId: this.id,\n\t\t\taggregateType: this.aggregateType,\n\t\t}) as UncommittedDomainEventOf<E>;\n\t}\n}\n\n/**\n * Replay-target guard used by `EventSourcedAggregate.loadFromHistory`: a\n * target carrying unflushed\n * `pendingEvents` throws {@link UnreplayableAggregateError} BEFORE anything\n * moves. Replay advances the aggregate's current version, so unflushed events\n * recorded against the old version would later be\n * harvested claiming a version baseline they were never part of. When the\n * discard is deliberate, discard this dirty instance and reconstitute a\n * fresh aggregate instead of mutating persistence lifecycle state publicly.\n *\n * Deliberately a module-level function, not a class method: it MUST not be\n * overridable by consumer subclasses (a no-op override would silently\n * disable the guard for all three call sites), and it checks the PUBLIC\n * `pendingEvents` getter, the same surface `withCommit` harvests.\n *\n * @internal Shared by the aggregate flavours in this package; not part of\n * the public API.\n */\nexport function assertReplayTargetHasNoPendingEvents(aggregate: {\n\treadonly id: unknown;\n\treadonly pendingEvents: ReadonlyArray<unknown>;\n}): void {\n\tconst pending = aggregate.pendingEvents.length;\n\tif (pending > 0) {\n\t\tthrow new UnreplayableAggregateError(\n\t\t\tString(aggregate.id),\n\t\t\t`it carries ${pending} unflushed pending event(s) that are not ` +\n\t\t\t\t\"part of the persisted stream; discard this dirty instance and \" +\n\t\t\t\t\"reconstitute a fresh aggregate before restoring persisted history\",\n\t\t);\n\t}\n}\n","import type { Id } from \"../core/id\";\nimport { BaseAggregate } from \"./base-aggregate\";\nimport type { AnyDomainEvent, PendingDomainEvent } from \"./domain-event\";\n\nexport type { IAggregateRoot } from \"./aggregate\";\nexport type { AggregateConfig } from \"./base-aggregate\";\n\n/**\n * OO-first Aggregate Root for state-stored domain models.\n *\n * The aggregate owns identity, valid domain state, behavior, its current\n * domain version, and pending domain events. It deliberately does not own a\n * database baseline or dirty-key bookkeeping. A repository adapter defines\n * its persistence projection through `PersistenceModel`; the Unit of Work\n * retains that opaque baseline and derives the adapter's change set at flush.\n */\nexport abstract class AggregateRoot<\n\tTState,\n\tTId extends Id<string>,\n\tTEvent extends AnyDomainEvent = never,\n> extends BaseAggregate<TState, TId, TEvent> {\n\t/**\n\t * Changes state and records the resulting facts in record-after-mutation\n\t * order. Validation and event mint checks run before the transition becomes\n\t * observable, so a rejected decision records nothing.\n\t */\n\tprotected commit(\n\t\tnewState: TState,\n\t\tevents:\n\t\t\t| PendingDomainEvent<TEvent>\n\t\t\t| readonly PendingDomainEvent<TEvent>[] = [],\n\t): void {\n\t\tconst eventBatch: readonly PendingDomainEvent<TEvent>[] = Array.isArray(\n\t\t\tevents,\n\t\t)\n\t\t\t? events\n\t\t\t: [events as PendingDomainEvent<TEvent>];\n\t\tfor (const event of eventBatch) this.assertMintedEvent(event);\n\n\t\tthis.setState(newState);\n\t\tfor (const event of eventBatch) this.addDomainEvent(event);\n\t}\n\n\t/** Every normal domain-state transition advances the OCC version. */\n\tprotected override setState(newState: TState): void {\n\t\tsuper.setState(newState);\n\t\tthis.bumpVersion();\n\t}\n\n\t/**\n\t * Replaces loss-tolerant derived state without advancing the domain version.\n\t *\n\t * This is intentionally loud: concurrent writers may overwrite such a\n\t * change. Keep business facts on the normal `setState`/`commit` path.\n\t */\n\tprotected setStateWithoutVersionBump(newState: TState): void {\n\t\tsuper.setState(newState);\n\t}\n}\n","import { err, ok, type Result } from \"@shirudo/result\";\nimport {\n\tDomainError,\n\tForeignEventError,\n\tMisaddressedEventError,\n\tMissingHandlerError,\n} from \"../core/errors\";\nimport type { Id } from \"../core/id\";\nimport type { IEventSourcedAggregate, Version } from \"./aggregate\";\nimport {\n\tassertReplayTargetHasNoPendingEvents,\n\tBaseAggregate,\n} from \"./base-aggregate\";\nimport {\n\ttype AnyDomainEvent,\n\ttype AnyUncommittedDomainEvent,\n\tadoptMintedEvent,\n\tadoptUncommittedDomainEvent,\n\tisMintedEvent,\n\ttype PendingDomainEvent,\n\ttype UncommittedDomainEventOf,\n} from \"./domain-event\";\n\n// Re-export for backwards compatibility: `IEventSourcedAggregate` lives\n// in `aggregate.ts` (the type hub).\nexport type { IEventSourcedAggregate } from \"./aggregate\";\n\ntype Handler<TState, TEvent> = (state: TState, event: TEvent) => TState;\n\n/**\n * Base class for Event-Sourced Aggregate Roots (Vernon, IDDD Chapter 8).\n *\n * Like `AggregateRoot`, this is both the root entity and the aggregate\n * boundary. The difference is persistence: state is derived from events,\n * not stored directly. Events are the single source of truth: all state\n * changes go through `apply()` → handler.\n *\n * Extends `BaseAggregate` (the shared lifecycle machinery) but does NOT\n * expose `setState()` or `commit()` from `AggregateRoot`. This enforces\n * the event sourcing pattern at the type level: there is no way to\n * mutate state without going through an event handler.\n *\n * `apply()` and `validateEvent()` throw `DomainError`-derived exceptions\n * on invariant violations. Subclasses override `validateEvent()` to\n * throw their own concrete subclasses (e.g. `OrderAlreadyConfirmedError`).\n * Validation guards NEW facts only. Replay through `loadFromHistory` never\n * runs `validateEvent`, because history is already accepted fact and decision\n * rules change over time;\n * a stream that was valid when written must stay loadable under\n * tomorrow's rules. The infrastructure-boundary method `loadFromHistory`\n * returns `Result`: it catches `DomainError` during replay so callers can\n * react to corrupted event streams without try/catch.\n *\n * @template TState - The aggregate state (contains child entities and value objects)\n * @template TEvent - The union type of all domain events\n * @template TId - The aggregate root identifier\n *\n * @example\n * ```typescript\n * class OrderAlreadyConfirmedError extends DomainError<\"ORDER_ALREADY_CONFIRMED\"> {\n * constructor(id: OrderId) {\n * super({ code: \"ORDER_ALREADY_CONFIRMED\", message: `Order ${id} is already confirmed` });\n * }\n * }\n *\n * class Order extends EventSourcedAggregate<OrderState, OrderEvent, OrderId> {\n * protected readonly aggregateType = \"Order\";\n *\n * confirm(): void {\n * this.apply(\n * this.createEvent(\"OrderConfirmed\", { orderId: this.id }),\n * );\n * }\n *\n * protected validateEvent(event: OrderEvent): void {\n * if (event.type === \"OrderConfirmed\" && this.state.status === \"confirmed\") {\n * throw new OrderAlreadyConfirmedError(this.id);\n * }\n * }\n *\n * protected readonly handlers = {\n * OrderConfirmed: (state: OrderState): OrderState => ({\n * ...state,\n * status: \"confirmed\",\n * }),\n * };\n * }\n * ```\n */\nexport abstract class EventSourcedAggregate<\n\t\tTState,\n\t\tTEvent extends AnyDomainEvent,\n\t\tTId extends Id<string>,\n\t>\n\textends BaseAggregate<TState, TId, TEvent>\n\timplements IEventSourcedAggregate<TId, TEvent>\n{\n\t/**\n\t * Validates a NEW event before `apply()` records it. Default is\n\t * no-op. Subclasses override to throw a concrete `DomainError`\n\t * subclass when the event violates an invariant in the current\n\t * state: the second net behind the command method's own guards.\n\t *\n\t * Replay never invokes this method. History is already accepted\n\t * fact, and decision rules evolve; re-checking yesterday's events\n\t * against today's rules would make legitimately persisted streams\n\t * unloadable after a rule change. Old storage shapes are not a\n\t * validation concern either: decode and upcast persisted events at\n\t * the read boundary (see the event-upcasting guide) so handlers\n\t * and replay always receive the current event shape.\n\t */\n\tprotected validateEvent(_event: UncommittedDomainEventOf<TEvent>): void {}\n\n\t/**\n\t * Applies an event: validates, locates the handler, computes the next\n\t * state, then commits state + pending event + version bump atomically.\n\t *\n\t * Throws `DomainError` (or a subclass) on validation failure.\n\t * Throws `MissingHandlerError` if no handler is registered for `event.type`.\n\t * Throws `MisaddressedEventError` (wiring) when the event carries an\n\t * `aggregateId` or `aggregateType` naming a different aggregate;\n\t * missing address fields are stamped from the aggregate instead.\n\t *\n\t * State is not mutated if any step throws: the handler is invoked into\n\t * a local and only assigned to `_state` once all checks pass.\n\t *\n\t * The method is generic in the event tag `K`, so concrete callers\n\t * (`this.apply(orderCreated)`) narrow to the literal tag and the\n\t * dispatched handler is typed as `Handler<TState, Extract<TEvent, { type: K }>>`,\n\t * with no `as` cast required at the call site.\n\t *\n\t * `apply()` is exclusively for NEW facts: it always records the event\n\t * and bumps the version (the former `isNew` flag argument is gone).\n\t * Replaying history is a different operation with its own entry\n\t * point, `loadFromHistory`.\n\t *\n\t * @param event - The domain event to apply\n\t */\n\tprotected apply<K extends TEvent[\"type\"]>(\n\t\tevent: PendingDomainEvent<Extract<TEvent, { type: K }>>,\n\t): void {\n\t\t// New facts get their address here, by construction: missing\n\t\t// fields are stamped from the aggregate (the createEvent\n\t\t// guarantee), a present-but-foreign address throws\n\t\t// MisaddressedEventError before anything is recorded. Without\n\t\t// this, a mis-addressed event would mutate state, version, and\n\t\t// pendingEvents and only fail later at harvest or on the next\n\t\t// load, poisoning the own stream.\n\t\tconst stamped = this.stampNewEventAddress(event);\n\t\t// Validation lives HERE, not in dispatch: only new facts are\n\t\t// checked against current rules; replay trusts history.\n\t\tthis.validateEvent(stamped as UncommittedDomainEventOf<TEvent>);\n\t\tthis.dispatch(stamped);\n\t\tthis.addDomainEvent(stamped);\n\t\tthis.bumpVersion();\n\t}\n\n\t/**\n\t * Address discipline for NEW facts: a present-but-foreign\n\t * `aggregateId` / `aggregateType` is a wiring bug and throws\n\t * {@link MisaddressedEventError}; missing fields are filled in from\n\t * the aggregate, so an applied event is always fully addressed and\n\t * can never fail the harvest or the replay guard later. The\n\t * stamped copy is frozen like the original (payload and metadata\n\t * are shared, already deep-frozen by `createDomainEvent`).\n\t */\n\tprivate stampNewEventAddress<K extends TEvent[\"type\"]>(\n\t\tevent: PendingDomainEvent<Extract<TEvent, { type: K }>>,\n\t): PendingDomainEvent<Extract<TEvent, { type: K }>> {\n\t\t// Immutability first: runs before validate/dispatch so a rejected\n\t\t// event cannot leave mutated state behind (addDomainEvent would\n\t\t// catch it too, but only after the handler already committed).\n\t\tthis.assertMintedEvent(event);\n\t\tconst { aggregateId, aggregateType } = event;\n\t\tconst idForeign = aggregateId !== undefined && aggregateId !== this.id;\n\t\tconst typeForeign =\n\t\t\taggregateType !== undefined && aggregateType !== this.aggregateType;\n\t\tif (idForeign || typeForeign) {\n\t\t\tthrow new MisaddressedEventError(\n\t\t\t\tthis.id,\n\t\t\t\tthis.aggregateType,\n\t\t\t\tevent.type,\n\t\t\t\taggregateId,\n\t\t\t\taggregateType,\n\t\t\t);\n\t\t}\n\t\tif (aggregateId !== undefined && aggregateType !== undefined) {\n\t\t\treturn event;\n\t\t}\n\t\t// The spread preserves the event's structural shape; TS cannot\n\t\t// prove it against the generic Extract, so the copy goes through\n\t\t// the event's own wider type. `aggregateId`/`aggregateType` are\n\t\t// `string | undefined` on DomainEvent; filling them in cannot\n\t\t// leave the declared shape.\n\t\tconst copy = {\n\t\t\t...event,\n\t\t\taggregateId: this.id,\n\t\t\taggregateType: this.aggregateType,\n\t\t};\n\t\tconst stamped: AnyDomainEvent | AnyUncommittedDomainEvent = isMintedEvent(\n\t\t\tevent,\n\t\t)\n\t\t\t? adoptMintedEvent(copy)\n\t\t\t: adoptUncommittedDomainEvent(copy);\n\t\treturn stamped as PendingDomainEvent<Extract<TEvent, { type: K }>>;\n\t}\n\n\t/**\n\t * Internal state-transition path shared by `apply()` and\n\t * `loadFromHistory`:\n\t * locate the handler, commit the next state. It deliberately does\n\t * NOT record the event, bump the version, or run `validateEvent`;\n\t * `apply()` layers all three on for new facts, while replay must not\n\t * (the history is already persisted, and validating it against\n\t * current rules would reject streams that were valid when written).\n\t * The replay loop iterates over `TEvent[]` and therefore cannot\n\t * supply a narrowed `K` generic, so this helper accepts `TEvent`\n\t * and the discriminator is resolved via the (statically-sound)\n\t * `handlers` map.\n\t *\n\t * Replay address check: a history event that names a DIFFERENT\n\t * aggregate id or type is a persisted row that belongs to someone\n\t * else (a miswired stream read, colliding ids across types, a\n\t * corrupted store). Throws `ForeignEventError`, an\n\t * `InfrastructureError`, which PROPAGATES through the replay\n\t * methods (their `Result` channel is reserved for `DomainError`\n\t * stream corruption) after the all-or-nothing rollback. History\n\t * events without the optional address fields pass unchecked (the\n\t * fields are optional on the event shape); NEW events are covered\n\t * by the stricter `stampNewEventAddress` on the apply path.\n\t */\n\tprivate assertReplayedEventBelongsHere(event: TEvent): void {\n\t\tconst idMismatch =\n\t\t\tevent.aggregateId !== undefined && event.aggregateId !== this.id;\n\t\tconst typeMismatch =\n\t\t\tevent.aggregateType !== undefined &&\n\t\t\tevent.aggregateType !== this.aggregateType;\n\t\tif (idMismatch || typeMismatch) {\n\t\t\tthrow new ForeignEventError(\n\t\t\t\tthis.id,\n\t\t\t\tthis.aggregateType,\n\t\t\t\tevent.type,\n\t\t\t\tevent.aggregateId,\n\t\t\t\tevent.aggregateType,\n\t\t\t);\n\t\t}\n\t}\n\n\tprivate dispatch(event: TEvent | UncommittedDomainEventOf<TEvent>): void {\n\t\t// Own-key guard: the handlers map is an object literal, so a plain\n\t\t// property get for event.type === \"toString\" / \"constructor\" /\n\t\t// \"__proto__\" (a corrupt or adversarial stream row) would resolve\n\t\t// through Object.prototype and invoke a non-handler.\n\t\tconst handler = Object.hasOwn(this.handlers, event.type)\n\t\t\t? (this.handlers[event.type as keyof typeof this.handlers] as Handler<\n\t\t\t\t\tTState,\n\t\t\t\t\tTEvent | UncommittedDomainEventOf<TEvent>\n\t\t\t\t>)\n\t\t\t: undefined;\n\t\tif (!handler) {\n\t\t\tthrow new MissingHandlerError(event.type);\n\t\t}\n\n\t\tconst nextState = handler(this._state, event);\n\n\t\t// Atomic commit: nothing above this line mutated aggregate state.\n\t\tthis._state = this.freezeState(nextState);\n\t}\n\n\t/**\n\t * Reconstitutes the aggregate from an event history. Catches `DomainError`\n\t * thrown during replay and returns it as an `Err`: this is the\n\t * infrastructure boundary, where event-stream corruption is an expected\n\t * recoverable failure. Unexpected (non-DomainError) throws propagate.\n\t *\n\t * All-or-nothing: if any event mid-stream throws, the aggregate's state\n\t * is rolled back to its pre-call value, the same contract as\n\t * every replay path. Partial replay is never observable.\n\t * (Version needs no rollback: replay goes through `dispatch`, which\n\t * never bumps it; only the final `markRestored` advances it.)\n\t *\n\t * Version advances additively: the aggregate's pre-existing version plus\n\t * `history.length`. A fresh aggregate (v=0) loading 3 events ends at v=3;\n\t * a reconstituted aggregate at v=P catching up on M newer events ends at\n\t * v=P+M.\n\t *\n\t * The replay target must not carry pending decisions. Factory-vs-load\n\t * lifecycle is owned by the Unit of Work rather than inferred from an\n\t * aggregate persistence flag.\n\t */\n\tpublic loadFromHistory(\n\t\thistory: ReadonlyArray<TEvent>,\n\t): Result<void, DomainError> {\n\t\tassertReplayTargetHasNoPendingEvents(this);\n\t\t// Empty stream: nothing was loaded, so preserve current state and version.\n\t\tif (history.length === 0) return ok();\n\n\t\tconst previousState = this._state;\n\t\tconst startVersion = this.version;\n\t\tfor (const event of history) {\n\t\t\ttry {\n\t\t\t\tthis.assertReplayedEventBelongsHere(event);\n\t\t\t\tthis.dispatch(event);\n\t\t\t} catch (e) {\n\t\t\t\tthis._state = previousState;\n\t\t\t\tif (e instanceof DomainError) return err(e);\n\t\t\t\tthrow e;\n\t\t\t}\n\t\t}\n\t\tthis.markRestored((startVersion + history.length) as Version);\n\t\treturn ok();\n\t}\n\n\t/**\n\t * A map of event types to their corresponding handlers.\n\t * Subclasses MUST implement this property.\n\t *\n\t * Handlers MUST fold state from `type` and `payload` only. The\n\t * parameter is typed as the uncommitted shape because a live `apply()`\n\t * dispatches the event BEFORE the shell records it: `eventId` and\n\t * `occurredAt` do not exist yet. Replay dispatches recorded events\n\t * through the same handlers, so those fields ARE present at runtime\n\t * there. A handler that reads them through an escape hatch (`as any`,\n\t * plain JavaScript) folds `undefined` live and a value on replay,\n\t * producing silently divergent state. When a time or identity changes a\n\t * business decision, pass it in the payload.\n\t */\n\tprotected abstract readonly handlers: {\n\t\t[K in TEvent[\"type\"]]: Handler<\n\t\t\tTState,\n\t\t\tUncommittedDomainEventOf<Extract<TEvent, { type: K }>>\n\t\t>;\n\t};\n}\n","import { err, type Result } from \"@shirudo/result\";\nimport {\n\tDuplicateHandlerRegistrationError,\n\tErrorMapperFailedError,\n\tUnregisteredHandlerError,\n} from \"../core/errors\";\n\n/**\n * INTERNAL shared pieces of `CommandBus` and `QueryBus`. The two buses are\n * deliberately separate public classes (distinct docs, distinct handler\n * types), but their wiring semantics must not drift: the expected-error\n * decision shape, register-once guard, no-handler gate, and handler-failure\n * classification live here exactly once. Not exported from any package entry.\n */\n\n/**\n * A positive classification decision from a bus's expected-error mapper.\n * The wrapper makes `undefined` a valid error-channel value without making\n * it ambiguous with the mapper declining to classify a thrown value.\n */\nexport interface ExpectedErrorDecision<E> {\n\treadonly error: E;\n}\n\n/**\n * Classifies and maps one handler throw. Returning `undefined` declines the\n * failure, which makes the bus rethrow the exact original value.\n */\nexport type ExpectedErrorMapper<E> = (\n\tthrown: unknown,\n) => ExpectedErrorDecision<E> | undefined;\n\n/**\n * Keeps manual result typing available only for the deliberately untyped\n * default map. Concrete maps, typed or refined index maps, and `any` keep their\n * mapped result contract authoritative.\n */\nexport type UntypedMapDispatch<\n\tTMap extends Record<string, unknown>,\n\tTMessage,\n> = 0 extends 1 & TMap\n\t? never\n\t: string extends keyof TMap\n\t\t? Record<string, unknown> extends TMap\n\t\t\t? TMessage\n\t\t\t: never\n\t\t: never;\n\n/**\n * Registers a handler exactly once. Silent replacement would turn the first\n * handler into dead code with no signal; wiring bugs must surface at\n * registration time.\n */\nexport function registerOnce<THandler>(\n\thandlers: Map<string, THandler>,\n\tbusKind: \"command\" | \"query\",\n\ttype: string,\n\thandler: THandler,\n): void {\n\tif (handlers.has(type)) {\n\t\tthrow new DuplicateHandlerRegistrationError({\n\t\t\tbusKind,\n\t\t\tmessageType: type,\n\t\t});\n\t}\n\thandlers.set(type, handler);\n}\n\n/**\n * Shared no-handler gate for dispatch: a wiring bug throws\n * `UnregisteredHandlerError` (crash-loud, same posture as\n * `MissingHandlerError`), it never rides the error channel. One\n * implementation so the buses and their unsafe paths cannot drift.\n */\nexport function handlerOrThrow<THandler>(\n\thandlers: Map<string, THandler>,\n\tbusKind: \"command\" | \"query\",\n\ttype: string,\n): THandler {\n\tconst handler = handlers.get(type);\n\tif (!handler) {\n\t\tthrow new UnregisteredHandlerError({ busKind, messageType: type });\n\t}\n\treturn handler;\n}\n\n/**\n * Classifies one registered handler failure. Absence of a mapper or an\n * `undefined` decision preserves and rethrows the exact failure: unknown\n * programmer, cancellation, and infrastructure errors cannot silently ride\n * a Result channel. A nested dispatch's wiring error always bypasses the\n * policy. A mapper that throws or returns a malformed decision is itself a\n * wiring bug and is wrapped without losing either cause.\n */\nexport function mapHandlerFailure<E>(\n\terror: unknown,\n\tmapExpectedError: ExpectedErrorMapper<E> | undefined,\n\tbusKind: \"command\" | \"query\",\n): Result<never, E> {\n\tif (\n\t\terror instanceof UnregisteredHandlerError ||\n\t\terror instanceof ErrorMapperFailedError\n\t) {\n\t\tthrow error;\n\t}\n\tif (!mapExpectedError) throw error;\n\n\tlet decision: ExpectedErrorDecision<E> | undefined;\n\ttry {\n\t\tdecision = mapExpectedError(error);\n\t} catch (mapperError) {\n\t\tthrow new ErrorMapperFailedError({\n\t\t\tbusKind,\n\t\t\thandlerError: error,\n\t\t\tmapperError,\n\t\t});\n\t}\n\tif (decision === undefined) throw error;\n\n\tlet mapped: E;\n\ttry {\n\t\tconst candidate: unknown = decision;\n\t\tif (\n\t\t\ttypeof candidate !== \"object\" ||\n\t\t\tcandidate === null ||\n\t\t\t!Object.hasOwn(candidate, \"error\")\n\t\t) {\n\t\t\tthrow new TypeError(\n\t\t\t\t\"mapExpectedError must return undefined or an own { error } decision\",\n\t\t\t);\n\t\t}\n\t\tmapped = (candidate as ExpectedErrorDecision<E>).error;\n\t} catch (mapperError) {\n\t\tthrow new ErrorMapperFailedError({\n\t\t\tbusKind,\n\t\t\thandlerError: error,\n\t\t\tmapperError,\n\t\t});\n\t}\n\treturn err(mapped);\n}\n","import type { Result } from \"@shirudo/result\";\nimport {\n\ttype ExpectedErrorMapper,\n\thandlerOrThrow,\n\tmapHandlerFailure,\n\tregisterOnce,\n\ttype UntypedMapDispatch,\n} from \"./bus-internals\";\nimport type { Command, CommandHandler } from \"./command\";\n\n/**\n * Internal adapter shape for handlers stored in the map.\n *\n * Registered handlers are typed as `CommandHandler<C, TMap[K]>` (narrower\n * input, specific return) and cannot be stored directly in a heterogeneous\n * map (function-parameter contravariance). The closure in `register`\n * downcasts `Command` to the handler's expected `C` based on the\n * dispatch-key invariant (we only call this entry when `cmd.type` matches\n * the key it was registered under). Result is widened to `unknown` here\n * and narrowed back via the public overloads on `execute`.\n */\ntype StoredCommandHandler<E> = (cmd: Command) => Promise<Result<unknown, E>>;\n\n/**\n * Type map for command types to their return types.\n * Used to improve type inference in CommandBus.\n *\n * @example\n * ```typescript\n * type MyCommandMap = {\n * CreateOrder: OrderId;\n * CancelOrder: void;\n * };\n *\n * const bus = new CommandBus<MyCommandMap>();\n * const result = await bus.execute({ type: \"CreateOrder\", ... });\n * // result: Result<OrderId, string> ← automatically inferred\n * ```\n */\ntype CommandTypeMap = Record<string, unknown>;\n\n/**\n * Construction options for {@link CommandBus}.\n *\n * @template E - The error channel type of the bus.\n */\nexport interface CommandBusOptions<E = string> {\n\t/**\n\t * Explicitly recognizes an expected handler failure and maps it into the\n\t * bus's error channel. Return `{ error }` only for failures this boundary\n\t * owns; return `undefined` to rethrow the exact original value. With no\n\t * mapper, every handler throw propagates. Unregistered-handler and nested\n\t * bus wiring errors always propagate.\n\t */\n\tmapExpectedError?: (thrown: unknown) => { readonly error: E } | undefined;\n}\n\n/**\n * Command Bus interface for dispatching commands to their handlers.\n * Provides a centralized way to execute commands with handler registration.\n *\n * Supports an optional type map (`TMap`) for automatic return type inference.\n * Without a type map, the return type must be specified manually or defaults to `unknown`.\n * With a concrete result map, its entry is the only result type for that\n * command; the loose explicit-result overload is unavailable.\n *\n * @template TMap - Optional mapping from command type strings to return types\n *\n * @example\n * ```typescript\n * // With a type map (recommended): the return type is inferred\n * type MyCommands = { CreateOrder: OrderId; CancelOrder: void };\n * const bus = new CommandBus<MyCommands>();\n * const result = await bus.execute({ type: \"CreateOrder\", ... });\n * // result: Result<OrderId, string>\n *\n * // Without a type map: the return type defaults to `unknown`\n * const bus = new CommandBus();\n * bus.register(\"CreateOrder\", createOrderHandler);\n * const result = await bus.execute({ type: \"CreateOrder\", ... });\n * // result: Result<unknown, string>\n * ```\n */\nexport interface ICommandBus<\n\tTMap extends CommandTypeMap = CommandTypeMap,\n\tE = string,\n> {\n\t/**\n\t * Executes a command by dispatching it to the registered handler.\n\t * When a type map is provided, the return type is inferred from the command type.\n\t *\n\t * @param command - The command to execute\n\t * @returns Result containing the success value or an error of type `E`\n\t * @throws UnregisteredHandlerError when no handler is registered for\n\t * `command.type` (a wiring bug; never delivered through the channel)\n\t * @throws The exact handler failure when `mapExpectedError` is absent or\n\t * returns `undefined`\n\t * @throws ErrorMapperFailedError when `mapExpectedError` fails\n\t */\n\texecute<C extends Command & { type: keyof TMap & string }>(\n\t\tcommand: C,\n\t): Promise<Result<TMap[C[\"type\"]], E>>;\n\t// Manual result typing belongs only to the default untyped map shape.\n\texecute<C extends Command, R>(\n\t\tcommand: UntypedMapDispatch<TMap, C>,\n\t): Promise<Result<R, E>>;\n\n\t/**\n\t * Registers a handler for a specific command type.\n\t *\n\t * When `TMap` is supplied, the `commandType` argument is restricted to\n\t * its keys and the handler signature is forced to match `TMap[K]` for the\n\t * return value: typos and wrong-typed handlers are compile errors.\n\t * Without `TMap` the registration is loose (any string key, any return\n\t * type) so the no-config path keeps working.\n\t *\n\t * @param commandType - The command type to register the handler for\n\t * @param handler - The handler function for this command type\n\t */\n\tregister<\n\t\tK extends keyof TMap & string,\n\t\tC extends Command & { type: K } = Command & { type: K },\n\t>(commandType: K, handler: CommandHandler<C, TMap[K], E>): void;\n}\n\n/**\n * Simple in-memory command bus implementation.\n * Handlers are stored in a Map and dispatched based on command type.\n *\n * Supports an optional type map (`TMap`) for automatic return type inference.\n * When `TMap` is concrete, `execute()` infers the result type from the command type.\n * An explicit competing result generic cannot override that map.\n * Without `TMap`, the return type defaults to `unknown` or is specified per call.\n *\n * **Note:** This is a basic implementation suitable for development and simple use cases.\n * For production environments, consider implementing or using a more feature-rich bus that includes:\n * - Middleware/Pipeline support (logging, validation, authorization)\n * - Error handling and retry logic\n * - Timeout handling\n * - Metrics and observability\n * - Transaction management\n * - Dead letter queue support\n *\n * The `CommandHandler` type can still be used with external production-grade buses\n * (e.g., RabbitMQ, AWS SQS) while maintaining type safety.\n *\n * @template TMap - Optional mapping from command type strings to return types\n *\n * @example\n * ```typescript\n * // With a type map: full inference\n * type Commands = { CreateOrder: OrderId; CancelOrder: void };\n * const bus = new CommandBus<Commands>();\n * const result = await bus.execute({ type: \"CreateOrder\", ... });\n * // result: Result<OrderId, string>\n *\n * // Without a type map: specify the return type per call\n * const bus = new CommandBus();\n * bus.register(\"CreateOrder\", async (cmd) => ok(orderId));\n * const result = await bus.execute({ type: \"CreateOrder\", ... });\n * ```\n */\nexport class CommandBus<\n\tTMap extends CommandTypeMap = CommandTypeMap,\n\tE = string,\n> implements ICommandBus<TMap, E>\n{\n\tprivate readonly handlers = new Map<string, StoredCommandHandler<E>>();\n\tprivate readonly mapExpectedError: ExpectedErrorMapper<E> | undefined;\n\n\tconstructor(options?: CommandBusOptions<E>) {\n\t\tthis.mapExpectedError = options?.mapExpectedError;\n\t}\n\n\tregister<\n\t\tK extends keyof TMap & string,\n\t\tC extends Command & { type: K } = Command & { type: K },\n\t>(commandType: K, handler: CommandHandler<C, TMap[K], E>): void {\n\t\tregisterOnce(this.handlers, \"command\", commandType, (cmd: Command) =>\n\t\t\thandler(cmd as C),\n\t\t);\n\t}\n\n\tasync execute<C extends Command & { type: keyof TMap & string }>(\n\t\tcommand: C,\n\t): Promise<Result<TMap[C[\"type\"]], E>>;\n\t// Keep the class surface identical to ICommandBus's untyped fallback.\n\tasync execute<C extends Command, R>(\n\t\tcommand: UntypedMapDispatch<TMap, C>,\n\t): Promise<Result<R, E>>;\n\tasync execute<C extends Command, R>(command: C): Promise<Result<R, E>> {\n\t\t// No-handler dispatch is a wiring bug, not a domain failure: thrown,\n\t\t// never delivered through the error channel (see handlerOrThrow).\n\t\tconst handler = handlerOrThrow(this.handlers, \"command\", command.type);\n\t\ttry {\n\t\t\treturn (await handler(command)) as Result<R, E>;\n\t\t} catch (error) {\n\t\t\treturn mapHandlerFailure(error, this.mapExpectedError, \"command\");\n\t\t}\n\t}\n}\n","/** A primitive value represented without loss by JSON. */\nexport type JsonPrimitive = boolean | null | number | string;\n\n/** A recursively JSON-safe value. Runtime validation rejects lossy shapes. */\nexport type JsonValue =\n\t| JsonPrimitive\n\t| ReadonlyArray<JsonValue>\n\t| { readonly [key: string]: JsonValue };\n\n/** A JSON-safe object. */\nexport type JsonObject = { readonly [key: string]: JsonValue };\n\n/** Non-null, non-array object shape check shared by the message boundaries. */\nexport function isJsonObject(value: unknown): value is JsonObject {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\ntype InvalidJsonValue = (path: string, reason: string) => never;\n\n/**\n * Proves that JSON serialization preserves a value exactly.\n *\n * The caller owns the boundary-specific error type through `invalid`.\n */\nexport function assertJsonValue(\n\tvalue: unknown,\n\tpath: string,\n\tinvalid: InvalidJsonValue,\n\tactive = new WeakSet<object>(),\n): asserts value is JsonValue {\n\tif (value === null) return;\n\tswitch (typeof value) {\n\t\tcase \"string\":\n\t\tcase \"boolean\":\n\t\t\treturn;\n\t\tcase \"number\":\n\t\t\tif (!Number.isFinite(value)) {\n\t\t\t\treturn invalid(path, \"numbers must be finite JSON numbers\");\n\t\t\t}\n\t\t\t// JSON.stringify(-0) produces \"0\", so negative zero does not\n\t\t\t// round-trip; rejecting it keeps the exactness contract honest.\n\t\t\tif (Object.is(value, -0)) {\n\t\t\t\treturn invalid(path, \"negative zero changes to 0 in JSON\");\n\t\t\t}\n\t\t\treturn;\n\t\tcase \"object\":\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tinvalid(path, `value of type ${typeof value} is not JSON-safe`);\n\t}\n\n\tif (active.has(value)) {\n\t\tinvalid(path, \"cyclic references are not JSON-safe\");\n\t}\n\tactive.add(value);\n\tif (Array.isArray(value)) {\n\t\tfor (const key of Reflect.ownKeys(value)) {\n\t\t\tif (key === \"length\") continue;\n\t\t\tif (typeof key === \"symbol\") {\n\t\t\t\tinvalid(path, \"symbol-keyed array properties would be dropped by JSON\");\n\t\t\t}\n\t\t\tconst index = Number(key);\n\t\t\tif (\n\t\t\t\t!Number.isInteger(index) ||\n\t\t\t\tindex < 0 ||\n\t\t\t\tindex >= value.length ||\n\t\t\t\tString(index) !== key\n\t\t\t) {\n\t\t\t\tinvalid(\n\t\t\t\t\t`${path}.${key}`,\n\t\t\t\t\t\"named array properties would be dropped by JSON\",\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\tfor (let index = 0; index < value.length; index += 1) {\n\t\t\tconst descriptor = Object.getOwnPropertyDescriptor(value, index);\n\t\t\tif (descriptor === undefined) {\n\t\t\t\tinvalid(\n\t\t\t\t\t`${path}[${index}]`,\n\t\t\t\t\t\"sparse array holes would change to null in JSON\",\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (!(\"value\" in descriptor) || !descriptor.enumerable) {\n\t\t\t\tinvalid(\n\t\t\t\t\t`${path}[${index}]`,\n\t\t\t\t\t\"accessor and non-enumerable array elements are not JSON-safe\",\n\t\t\t\t);\n\t\t\t}\n\t\t\tassertJsonValue(descriptor.value, `${path}[${index}]`, invalid, active);\n\t\t}\n\t\tactive.delete(value);\n\t\treturn;\n\t}\n\n\tconst prototype = Object.getPrototypeOf(value);\n\tif (prototype !== Object.prototype && prototype !== null) {\n\t\tinvalid(\n\t\t\tpath,\n\t\t\t\"Date, Map, Set, and class instances are not JSON-safe here; map \" +\n\t\t\t\t\"them explicitly to strings, arrays, or plain objects\",\n\t\t);\n\t}\n\tfor (const key of Reflect.ownKeys(value)) {\n\t\tif (typeof key === \"symbol\") {\n\t\t\tinvalid(path, \"symbol-keyed properties would be dropped by JSON\");\n\t\t}\n\t\tconst descriptor = Object.getOwnPropertyDescriptor(value, key);\n\t\tif (descriptor === undefined) continue;\n\t\tconst childPath = `${path}.${key}`;\n\t\tif (key === \"__proto__\") {\n\t\t\tinvalid(\n\t\t\t\tchildPath,\n\t\t\t\t\"hostile __proto__ keys are not accepted at integration boundaries\",\n\t\t\t);\n\t\t}\n\t\tif (!(\"value\" in descriptor) || !descriptor.enumerable) {\n\t\t\tinvalid(\n\t\t\t\tchildPath,\n\t\t\t\t\"accessor and non-enumerable properties are not JSON-safe\",\n\t\t\t);\n\t\t}\n\t\tassertJsonValue(descriptor.value, childPath, invalid, active);\n\t}\n\tactive.delete(value);\n}\n","import type { AggregateAddress } from \"../aggregate/aggregate-address\";\nimport type { AnyDomainEvent } from \"../aggregate/domain-event\";\nimport { InvalidCommandMessageError } from \"../core/errors\";\nimport {\n\tassertJsonValue,\n\tisJsonObject,\n\ttype JsonObject,\n} from \"../events/json-value\";\nimport type {\n\tEventCommitCandidate,\n\tEventCommitCandidatePosition,\n\tOutboxWriter,\n} from \"../events/ports\";\nimport { deepFreeze } from \"../value-object/value-object\";\nimport type { PublishedCommand } from \"./command\";\n\n/**\n * Business relationships and technical trace context selected explicitly for\n * an outgoing command. Correlation/conversation explain the business flow;\n * W3C Trace Context connects technical spans.\n */\nexport interface CommandMessageRelationships {\n\t/** Groups messages that belong to one operation or trace. */\n\treadonly correlationId?: string;\n\t/** Groups every message in one long-running business interaction. */\n\treadonly conversationId?: string;\n\t/** W3C Trace Context parent for technical distributed tracing. */\n\treadonly traceparent?: string;\n\t/** Optional vendor trace state associated with `traceparent`. */\n\treadonly tracestate?: string;\n}\n\n/**\n * Application-owned Published Language produced from one private domain or\n * process event. `destination` names one receiver contract; it is deliberately\n * required because a command is an instruction, not a broadcast fact.\n *\n * The command carries a stable schema `version` and JSON-safe `payload`.\n * Domain value objects are translated to wire DTOs by the mapper before this\n * boundary.\n */\nexport interface CommandMessageContent<C extends PublishedCommand>\n\textends CommandMessageRelationships {\n\treadonly destination: string;\n\treadonly command: C;\n}\n\n/**\n * Immutable, JSON-safe command envelope stored for later at-least-once\n * delivery.\n *\n * `causationId` always identifies the private event whose accepted decision\n * requested this command. The mapper cannot replace it with a weaker\n * correlation. Consumer-produced events should in turn use `messageId` as\n * their causation id.\n */\nexport interface DurableCommandMessage<C extends PublishedCommand>\n\textends CommandMessageContent<C> {\n\treadonly messageId: string;\n\treadonly recordedAt: string;\n\treadonly causationId: string;\n}\n\n/**\n * Receipt for the private event that requested one command batch. It retains\n * commit identity and ordering without putting the private event or its\n * payload into the command outbox.\n */\nexport interface CommandCommitOriginCandidate {\n\treadonly eventId: string;\n\treadonly source: AggregateAddress;\n\treadonly position: EventCommitCandidatePosition;\n}\n\n/**\n * One private process-event commit and the exact commands it requested.\n * `messages` may be empty: the receipt still advances the originating source\n * and makes an exact retry distinguishable from a missing commit.\n */\nexport interface CommandOutboxCommitCandidate<C extends PublishedCommand> {\n\treadonly origin: CommandCommitOriginCandidate;\n\treadonly messages: ReadonlyArray<DurableCommandMessage<C>>;\n}\n\n/**\n * Write port for a dedicated transactional command outbox.\n *\n * The adapter is bound to the same ambient transaction as the aggregate or\n * event-stream repository. It must persist the complete input atomically,\n * retain input order, deduplicate exact retries by `origin.eventId`, and reject\n * a reused origin id whose source, position, or messages differ. It also owns\n * the durable source cursor represented by `origin.position`; an empty command\n * batch still advances that cursor.\n *\n * Delivery is out of band and at least once. A consumer therefore uses\n * `message.messageId` as its idempotency key and acknowledges only after the\n * command result has been stored.\n */\nexport interface CommandOutboxWriter<C extends PublishedCommand> {\n\tadd(commits: ReadonlyArray<CommandOutboxCommitCandidate<C>>): Promise<void>;\n}\n\n/** Maps one private accepted event to zero or more addressed commands. */\nexport type CommandOutboxMapper<\n\tEvt extends AnyDomainEvent,\n\tC extends PublishedCommand,\n> = (event: Evt) => ReadonlyArray<CommandMessageContent<C>>;\n\n/**\n * Adapts a dedicated command outbox to the event-candidate write port consumed\n * by `withCommit`.\n *\n * Mapping happens inside the transaction, before the command outbox write.\n * The private event is used only at this boundary and is reduced to an origin\n * receipt. The helper never publishes it or copies its payload implicitly; the\n * application mapper selects and translates the data that belongs in the\n * versioned Published Language. The route rejects values JSON would lose or\n * change before it calls the adapter.\n * Every command gets a stable id derived from the event id and its zero-based\n * order, so an exact transaction retry produces the same rows.\n *\n * Omit `withCommit`'s in-process `bus` for private process events. Participants\n * consume the durable command messages from their explicitly named\n * destinations, while event-stream replay only rebuilds process state.\n */\nexport function routeEventsToCommandOutbox<\n\tC extends PublishedCommand,\n\tEvt extends AnyDomainEvent = AnyDomainEvent,\n>(\n\toutbox: CommandOutboxWriter<C>,\n\tmapper: CommandOutboxMapper<Evt, C>,\n): OutboxWriter<Evt> {\n\treturn {\n\t\tadd: async (events) => {\n\t\t\tconst commits = events.map((candidate) =>\n\t\t\t\ttoCommandCommit(candidate, mapper),\n\t\t\t);\n\t\t\tawait outbox.add(commits);\n\t\t},\n\t};\n}\n\nfunction toCommandCommit<\n\tEvt extends AnyDomainEvent,\n\tC extends PublishedCommand,\n>(\n\tcandidate: EventCommitCandidate<Evt>,\n\tmapper: CommandOutboxMapper<Evt, C>,\n): CommandOutboxCommitCandidate<C> {\n\tconst mapped = mapper(candidate.event);\n\tif (!Array.isArray(mapped)) {\n\t\tthrow new TypeError(\n\t\t\t\"Command outbox mapper must return a readonly array of commands\",\n\t\t);\n\t}\n\tconst messages = Array.from(mapped, (content, index) =>\n\t\ttoDurableCommand<C>(candidate.event, content, index),\n\t);\n\treturn deepFreeze({\n\t\torigin: {\n\t\t\teventId: candidate.event.eventId,\n\t\t\tsource: { ...candidate.source },\n\t\t\tposition: { ...candidate.position },\n\t\t},\n\t\tmessages,\n\t}) as CommandOutboxCommitCandidate<C>;\n}\n\nfunction toDurableCommand<C extends PublishedCommand>(\n\tevent: AnyDomainEvent,\n\tcontent: CommandMessageContent<C>,\n\tindex: number,\n): DurableCommandMessage<C> {\n\tif (\n\t\tcontent === null ||\n\t\ttypeof content !== \"object\" ||\n\t\tArray.isArray(content)\n\t) {\n\t\tthrow new TypeError(\"Command outbox mapper entry must be an object\");\n\t}\n\tconst {\n\t\tdestination,\n\t\tcommand: sourceCommand,\n\t\tcorrelationId,\n\t\tconversationId,\n\t\ttraceparent,\n\t\ttracestate,\n\t} = content;\n\tassertNonBlank(\"destination\", destination);\n\tif (\n\t\tsourceCommand === null ||\n\t\ttypeof sourceCommand !== \"object\" ||\n\t\tArray.isArray(sourceCommand)\n\t) {\n\t\tthrow new TypeError(\"Command outbox command must be an object\");\n\t}\n\tassertPublishedCommand(sourceCommand);\n\tassertOptionalNonBlank(\"correlationId\", correlationId);\n\tassertOptionalNonBlank(\"conversationId\", conversationId);\n\tassertTraceContext(traceparent, tracestate);\n\n\tconst command = JSON.parse(JSON.stringify(sourceCommand)) as C;\n\treturn deepFreeze({\n\t\tmessageId: `${event.eventId}:command:${index}`,\n\t\trecordedAt: event.occurredAt.toISOString(),\n\t\tdestination,\n\t\tcommand,\n\t\t...(correlationId === undefined ? {} : { correlationId }),\n\t\t...(conversationId === undefined ? {} : { conversationId }),\n\t\t...(traceparent === undefined ? {} : { traceparent }),\n\t\t...(tracestate === undefined ? {} : { tracestate }),\n\t\tcausationId: event.eventId,\n\t}) as DurableCommandMessage<C>;\n}\n\nfunction assertNonBlank(\n\tfield: string,\n\tvalue: unknown,\n): asserts value is string {\n\tif (typeof value !== \"string\" || value.trim().length === 0) {\n\t\tinvalid(`$.${field}`, \"must be a non-blank string\");\n\t}\n}\n\nfunction assertOptionalNonBlank(field: string, value: unknown): void {\n\tif (value !== undefined) assertNonBlank(field, value);\n}\n\nfunction assertPublishedCommand(\n\tvalue: unknown,\n): asserts value is PublishedCommand {\n\tassertJsonValue(value, \"$.command\", invalid);\n\tif (!isJsonObject(value)) {\n\t\tinvalid(\"$.command\", \"must be a plain JSON object\");\n\t}\n\tfor (const key of Object.keys(value)) {\n\t\tif (key !== \"type\" && key !== \"version\" && key !== \"payload\") {\n\t\t\tinvalid(\n\t\t\t\t`$.command.${key}`,\n\t\t\t\t\"is not part of the published command schema\",\n\t\t\t);\n\t\t}\n\t}\n\tassertNonBlank(\"command.type\", value.type);\n\tif (\n\t\ttypeof value.version !== \"number\" ||\n\t\t!Number.isInteger(value.version) ||\n\t\tvalue.version < 1\n\t) {\n\t\tinvalid(\"$.command.version\", \"must be an integer >= 1\");\n\t}\n\tif (!Object.hasOwn(value, \"payload\")) {\n\t\tinvalid(\"$.command.payload\", \"is required (use null for an empty payload)\");\n\t}\n}\n\nconst TRACEPARENT =\n\t/^([0-9a-f]{2})-([0-9a-f]{32})-([0-9a-f]{16})-([0-9a-f]{2})([\\x21-\\x7e]*)$/;\nconst TRACESTATE_MEMBER =\n\t/^([a-z0-9][a-z0-9_@*/-]{0,255})=[\\x20-\\x2b\\x2d-\\x3c\\x3e-\\x7e]{1,256}$/;\n\nfunction assertTraceContext(traceparent: unknown, tracestate: unknown): void {\n\tif (traceparent === undefined) {\n\t\tif (tracestate !== undefined) {\n\t\t\tinvalid(\"$.tracestate\", \"requires traceparent\");\n\t\t}\n\t\treturn;\n\t}\n\tif (typeof traceparent !== \"string\") {\n\t\tinvalid(\"$.traceparent\", \"must be a W3C traceparent string\");\n\t}\n\tconst match = TRACEPARENT.exec(traceparent);\n\tconst version = match?.[1];\n\tconst extension = match?.[5] ?? \"\";\n\tif (\n\t\tmatch === null ||\n\t\tversion === \"ff\" ||\n\t\t/^0+$/.test(match[2] ?? \"\") ||\n\t\t/^0+$/.test(match[3] ?? \"\") ||\n\t\t(version === \"00\" && extension.length > 0) ||\n\t\t(version !== \"00\" &&\n\t\t\textension.length > 0 &&\n\t\t\t(!extension.startsWith(\"-\") || extension.length === 1))\n\t) {\n\t\tinvalid(\n\t\t\t\"$.traceparent\",\n\t\t\t\"must be a structurally valid lowercase W3C traceparent\",\n\t\t);\n\t}\n\tif (tracestate === undefined) return;\n\tif (typeof tracestate !== \"string\" || tracestate.length > 512) {\n\t\tinvalid(\n\t\t\t\"$.tracestate\",\n\t\t\t\"must stay within the 512-character command limit\",\n\t\t);\n\t}\n\t// W3C Trace Context requires receivers to tolerate empty list-members\n\t// (\"vendor1=abc,,vendor2=def\"). They carry no data and are dropped\n\t// before validation; a header with only empty members counts as absent.\n\tconst members = tracestate\n\t\t.split(\",\")\n\t\t.map((member) => member.trim())\n\t\t.filter((member) => member.length > 0);\n\tif (members.length === 0) return;\n\tconst keys = new Set<string>();\n\tif (\n\t\tmembers.length > 32 ||\n\t\tmembers.some((member) => {\n\t\t\tconst memberMatch = TRACESTATE_MEMBER.exec(member);\n\t\t\tconst key = memberMatch?.[1];\n\t\t\tif (key === undefined || keys.has(key)) return true;\n\t\t\tkeys.add(key);\n\t\t\treturn false;\n\t\t})\n\t) {\n\t\tinvalid(\n\t\t\t\"$.tracestate\",\n\t\t\t\"must contain 1 to 32 unique, valid W3C tracestate list-members\",\n\t\t);\n\t}\n}\n\nfunction invalid(path: string, reason: string): never {\n\tthrow new InvalidCommandMessageError(path, reason);\n}\n","import { err, ok, type Result } from \"@shirudo/result\";\nimport { DomainError } from \"../core/errors\";\n\n/** A concrete consumer-defined DomainError subclass accepted at a boundary. */\nexport type DomainErrorClass<E extends DomainError = DomainError> = new (\n\t...args: never[]\n) => E;\n\ntype ListedDomainError<TClasses extends readonly DomainErrorClass[]> =\n\tInstanceType<TClasses[number]>;\n\n/**\n * Runs application-boundary work and turns only explicitly listed domain\n * rejections into a typed Result error. Every unlisted DomainError and every\n * non-domain failure is rethrown unchanged. The class list is copied and\n * validated before work starts.\n *\n * @throws TypeError when expectedErrors is empty or contains a non-DomainError\n * class\n * @throws The exact operation failure when it is not an instance of a listed\n * class\n */\nexport async function domainErrorToResult<\n\tT,\n\tconst TClasses extends readonly [DomainErrorClass, ...DomainErrorClass[]],\n>(\n\toperation: () => T | PromiseLike<T>,\n\texpectedErrors: TClasses,\n): Promise<Result<T, ListedDomainError<TClasses>>> {\n\tconst stableExpectedErrors = [...expectedErrors];\n\tassertExpectedErrorClasses(stableExpectedErrors);\n\n\ttry {\n\t\treturn ok(await operation());\n\t} catch (error) {\n\t\tfor (const errorClass of stableExpectedErrors) {\n\t\t\tif (\n\t\t\t\t((typeof error === \"object\" && error !== null) ||\n\t\t\t\t\ttypeof error === \"function\") &&\n\t\t\t\tObject.prototype.isPrototypeOf.call(errorClass.prototype, error)\n\t\t\t) {\n\t\t\t\treturn err(error as ListedDomainError<TClasses>);\n\t\t\t}\n\t\t}\n\t\tthrow error;\n\t}\n}\n\nfunction assertExpectedErrorClasses(\n\terrorClasses: readonly unknown[],\n): asserts errorClasses is readonly [DomainErrorClass, ...DomainErrorClass[]] {\n\tif (errorClasses.length === 0) {\n\t\tthrow new TypeError(\n\t\t\t\"domainErrorToResult requires at least one expected DomainError class\",\n\t\t);\n\t}\n\tfor (const errorClass of errorClasses) {\n\t\tif (\n\t\t\ttypeof errorClass !== \"function\" ||\n\t\t\t!Object.prototype.isPrototypeOf.call(\n\t\t\t\tDomainError.prototype,\n\t\t\t\terrorClass.prototype,\n\t\t\t)\n\t\t) {\n\t\t\tthrow new TypeError(\n\t\t\t\t\"domainErrorToResult expected every entry to be a concrete DomainError subclass\",\n\t\t\t);\n\t\t}\n\t}\n}\n","/**\n * The value to reject with when an `AbortSignal` has fired.\n *\n * Returns the signal's `reason` (a `DOMException` `AbortError` for\n * `controller.abort()`, `TimeoutError` for `AbortSignal.timeout`), falling\n * back to a plain `Error` with `fallbackMessage` when `reason` is nullish.\n * A spec-compliant signal always populates `reason` when aborted, so the\n * fallback only fires for a non-spec polyfill; without it, a bare\n * `throw undefined` would surface, breaking `instanceof Error` handling.\n *\n * Centralizes the `signal.reason ?? new Error(...)` idiom used at every\n * abort site (event bus, `withCommit`, `UnitOfWork.run`, the retrying\n * scope) so a single fix covers all of them.\n */\nexport function abortReason(\n\tsignal: AbortSignal,\n\tfallbackMessage: string,\n): unknown {\n\treturn signal.reason ?? new Error(fallbackMessage);\n}\n","/**\n * Shared construction-time guards for numeric options. `context` names\n * the throwing component so the error reads like the component's own\n * validation (\"OutboxDispatcher: pollIntervalMs must be...\").\n */\n\n/** Guard for numeric options that must be a non-negative finite number. */\nexport function assertNonNegativeFinite(\n\tcontext: string,\n\tfield: string,\n\tvalue: number,\n): void {\n\tif (!Number.isFinite(value) || value < 0) {\n\t\tthrow new Error(\n\t\t\t`${context}: ${field} must be a non-negative finite number, got ${value}`,\n\t\t);\n\t}\n}\n\n/** Guard for count options that must be a whole number of at least 1. */\nexport function assertPositiveInteger(\n\tcontext: string,\n\tfield: string,\n\tvalue: number,\n): void {\n\tif (!Number.isInteger(value) || value < 1) {\n\t\tthrow new Error(\n\t\t\t`${context}: ${field} must be an integer >= 1, got ${value}`,\n\t\t);\n\t}\n}\n\n/** Guard for retained-record capacities that must fit exact JS integers. */\nexport function assertPositiveSafeInteger(\n\tcontext: string,\n\tfield: string,\n\tvalue: number,\n): void {\n\tif (!Number.isSafeInteger(value) || value < 1) {\n\t\tthrow new RangeError(\n\t\t\t`${context}: ${field} must be a positive safe integer, got ${value}`,\n\t\t);\n\t}\n}\n","import { abortReason } from \"./abort\";\nimport { assertNonNegativeFinite } from \"./validate\";\n\n/** Cancellation and deadline controls for one bounded shell operation. */\nexport interface ExecutionContext {\n\t/** Cooperative cancellation for the in-flight operation. */\n\treadonly signal: AbortSignal;\n\t/** Absolute Unix epoch millisecond at which the shell stops waiting. */\n\treadonly deadlineAt: number;\n}\n\n/** Caller controls for one bounded shell operation. */\ntype ExecutionOptions =\n\t| {\n\t\t\t/** Optional owner/request cancellation signal. */\n\t\t\treadonly signal?: AbortSignal;\n\t\t\t/** Maximum time the shell waits for the operation. */\n\t\t\treadonly timeoutMs: number;\n\t\t\treadonly deadlineAt?: never;\n\t }\n\t| {\n\t\t\t/** Optional owner/request cancellation signal. */\n\t\t\treadonly signal?: AbortSignal;\n\t\t\treadonly timeoutMs?: never;\n\t\t\t/** Shared absolute deadline for a multi-operation budget. */\n\t\t\treadonly deadlineAt: number;\n\t };\n\n/** Default bound for delivery and post-commit operations. */\nexport const DEFAULT_EXECUTION_TIMEOUT_MS = 30_000;\n\n/**\n * Runs one operation with a child signal that combines owner cancellation and a\n * shell-owned timeout. The returned promise settles on abort even when an\n * adapter ignores the signal; the adapter promise remains observed so a later\n * rejection cannot become an unhandled rejection.\n *\n * This bounds how long the shell waits; JavaScript cannot forcibly terminate\n * an arbitrary promise. An I/O adapter that must prevent zombie work and\n * overlapping retries has to pass `context.signal` to its native operation or\n * enforce a native timeout no later than `context.deadlineAt`.\n */\nexport function runBoundedExecution<T>(\n\tlabel: string,\n\toptions: ExecutionOptions,\n\toperation: (context: ExecutionContext) => Promise<T> | T,\n): Promise<T> {\n\tif (options.deadlineAt === undefined) {\n\t\tassertNonNegativeFinite(label, \"timeoutMs\", options.timeoutMs);\n\t} else {\n\t\tassertNonNegativeFinite(label, \"deadlineAt\", options.deadlineAt);\n\t}\n\tconst startedAt = Date.now();\n\tconst deadlineAt = options.deadlineAt ?? startedAt + options.timeoutMs;\n\tconst timeoutMs = Math.max(0, deadlineAt - startedAt);\n\tconst timeoutError = (): DOMException =>\n\t\tnew DOMException(`${label} timed out after ${timeoutMs}ms`, \"TimeoutError\");\n\tconst controller = new AbortController();\n\tconst context = Object.freeze({\n\t\tsignal: controller.signal,\n\t\tdeadlineAt,\n\t});\n\tconst ownerSignal = options.signal;\n\tconst abortFromOwner = (): void => {\n\t\tcontroller.abort(\n\t\t\townerSignal === undefined\n\t\t\t\t? new Error(`${label} aborted`)\n\t\t\t\t: abortReason(ownerSignal, `${label} aborted`),\n\t\t);\n\t};\n\n\tif (ownerSignal?.aborted) abortFromOwner();\n\telse ownerSignal?.addEventListener(\"abort\", abortFromOwner, { once: true });\n\tif (\n\t\t!controller.signal.aborted &&\n\t\toptions.deadlineAt !== undefined &&\n\t\tdeadlineAt <= startedAt\n\t) {\n\t\tcontroller.abort(timeoutError());\n\t}\n\n\tconst timer = setTimeout(() => {\n\t\tcontroller.abort(timeoutError());\n\t}, timeoutMs);\n\n\treturn new Promise<T>((resolve, reject) => {\n\t\tlet settled = false;\n\t\tconst finish = (complete: () => void): void => {\n\t\t\tif (settled) return;\n\t\t\tsettled = true;\n\t\t\tclearTimeout(timer);\n\t\t\townerSignal?.removeEventListener(\"abort\", abortFromOwner);\n\t\t\tcontroller.signal.removeEventListener(\"abort\", onAbort);\n\t\t\tcomplete();\n\t\t};\n\t\tconst onAbort = (): void => {\n\t\t\t// Defer one microtask so a promise that settled immediately before the\n\t\t\t// abort keeps its acknowledgement semantics. If abort happened first,\n\t\t\t// this microtask was queued first and still wins deterministically.\n\t\t\tqueueMicrotask(() =>\n\t\t\t\tfinish(() =>\n\t\t\t\t\treject(abortReason(controller.signal, `${label} aborted`)),\n\t\t\t\t),\n\t\t\t);\n\t\t};\n\n\t\tif (controller.signal.aborted) {\n\t\t\tonAbort();\n\t\t\treturn;\n\t\t}\n\t\tcontroller.signal.addEventListener(\"abort\", onAbort, { once: true });\n\t\tlet outcome: Promise<T>;\n\t\ttry {\n\t\t\toutcome = Promise.resolve(operation(context));\n\t\t} catch (error) {\n\t\t\tfinish(() => reject(error));\n\t\t\treturn;\n\t\t}\n\t\toutcome.then(\n\t\t\t(value) => finish(() => resolve(value)),\n\t\t\t(error) => finish(() => reject(error)),\n\t\t);\n\t});\n}\n","/**\n * Invokes a fire-and-forget observer hook (`onPersistError`,\n * `onPublishError`, `onRetry`) and neutralises BOTH failure shapes it can\n * produce. The observers are typed `(...) => void`, but a `void` return\n * type still admits an `async` function, so an observer can fail in two\n * ways: a synchronous throw, or a rejected promise. Either would replace\n * or mask the operation's real outcome (a committed write made to look\n * failed, a retryable error swapped for the observer's own), and the\n * async rejection additionally becomes an `unhandledRejection` that can\n * crash the process under Node's default policy. Both are swallowed\n * here: observers report, they never affect the operation they observe.\n *\n * Internal utility (not exported from the package barrels).\n */\nexport function reportToObserver(invoke: () => void): void {\n\tlet result: unknown;\n\ttry {\n\t\tresult = invoke() as unknown;\n\t} catch {\n\t\treturn;\n\t}\n\tif (\n\t\tresult !== null &&\n\t\ttypeof result === \"object\" &&\n\t\ttypeof (result as { then?: unknown }).then === \"function\"\n\t) {\n\t\t(result as Promise<unknown>).then(undefined, () => {});\n\t}\n}\n\n/** Runtime-validates and immutably captures a production-observer bundle. */\nexport function captureObserverFunctions<\n\tT extends object,\n\tK extends Extract<keyof T, string>,\n>(context: string, observers: T, required: readonly K[]): Readonly<Pick<T, K>> {\n\tif (observers === null || typeof observers !== \"object\") {\n\t\tthrow new TypeError(\n\t\t\t`${context}.observers must provide ${required.join(\", \")}`,\n\t\t);\n\t}\n\tconst captured: Partial<Record<K, T[K]>> = {};\n\tfor (const name of required) {\n\t\tconst observer = (observers as Record<string, unknown>)[name];\n\t\tif (typeof observer !== \"function\") {\n\t\t\tthrow new TypeError(`${context}.observers.${name} must be a function`);\n\t\t}\n\t\tcaptured[name] = observer as T[K];\n\t}\n\treturn Object.freeze(captured) as Readonly<Pick<T, K>>;\n}\n","import type { Version } from \"../aggregate/aggregate\";\nimport type { IAggregateRoot } from \"../aggregate/aggregate-root\";\nimport {\n\ttype AnyDomainEvent,\n\tisMintedEvent,\n\ttype PendingDomainEvent,\n} from \"../aggregate/domain-event\";\nimport {\n\ttype PendingEventLifecycleCapability,\n\tpendingEventLifecycleCapabilityFor,\n} from \"../aggregate/pending-event-lifecycle\";\nimport { EventHarvestError } from \"../core/errors\";\nimport type { Id } from \"../core/id\";\nimport type {\n\tEventBus,\n\tEventCommitCandidate,\n\tOutboxWriter,\n} from \"../events/ports\";\nimport type { TransactionScope } from \"../repo/scope\";\nimport { abortReason } from \"../utils/abort\";\nimport {\n\tDEFAULT_EXECUTION_TIMEOUT_MS,\n\ttype ExecutionContext,\n\trunBoundedExecution,\n} from \"../utils/execution\";\nimport { reportToObserver } from \"../utils/observer\";\nimport { assertNonNegativeFinite } from \"../utils/validate\";\n\n/** Dependencies for {@link withCommit}. */\nexport interface WithCommitDeps<Evt extends AnyDomainEvent, TCtx> {\n\t/**\n\t * The write half of the outbox: `withCommit` only ever calls `add()`.\n\t * Pass a full `Outbox` for the kit's poll-based dispatch, or a bare\n\t * `OutboxWriter` backed by an external delivery solution.\n\t *\n\t * Required on purpose, while `bus` is optional: the bus is the\n\t * best-effort in-process fast path, the outbox is the delivery\n\t * guarantee. Running without delivery reliability is a decision, not\n\t * a default; make it explicit with\n\t * `outboxWriterAcceptingEventLoss()`.\n\t */\n\toutbox: OutboxWriter<Evt>;\n\tbus?: EventBus<Evt>;\n\tscope: TransactionScope<TCtx>;\n\t/**\n\t * Observer for post-commit `bus.publish` failures. Called with the\n\t * error and the events that were published. Must not be relied on\n\t * for delivery: the outbox dispatcher is the reliable path.\n\t */\n\tonPublishError?: (error: unknown, events: ReadonlyArray<Evt>) => void;\n\t/**\n\t * Application-shell observer invoked for each successfully acknowledged\n\t * saved aggregate, after every commit record has completed its internal\n\t * acknowledgement attempt. Deleted aggregates do not trigger it. `version`\n\t * is the commit-time value captured before any observer runs. Observer\n\t * failures are reported through `onPersistError` and never turn an already\n\t * committed write into an apparent failure. The execution context carries\n\t * owner cancellation and the configured post-commit deadline.\n\t */\n\tonPersisted?: (\n\t\taggregate: IAggregateRoot<Id<string>, Evt>,\n\t\tversion: Version,\n\t\tcontext: ExecutionContext,\n\t) => void | Promise<void>;\n\t/**\n\t * Observer for post-commit persistence failures: either the internal\n\t * acknowledgement/disposal step or the application-shell `onPersisted`\n\t * observer. Called once per failure with the error and affected aggregate.\n\t * Symmetric with {@link onPublishError}: the\n\t * transaction has already committed, so the failure must NOT reject the\n\t * write; without this observer it would otherwise vanish silently. The\n\t * hook is an observer only: if it throws, its error is swallowed so the\n\t * post-commit invariant holds, and the loop continues the remaining\n\t * post-commit work.\n\t */\n\tonPersistError?: (\n\t\terror: unknown,\n\t\taggregate: IAggregateRoot<Id<string>, Evt>,\n\t) => void;\n\t/**\n\t * Total time allotted to the complete post-commit application phase:\n\t * every application observer followed by in-process bus publication shares\n\t * one absolute deadline. Callbacks that have not started when the deadline is\n\t * reached are skipped and reported as timeouts. Defaults to `30000`ms.\n\t * Timing out or aborting these best-effort operations is reported through the\n\t * matching error observer and never rejects an already committed write.\n\t */\n\tpostCommitTimeoutMs?: number;\n\t/**\n\t * Cooperative-cancellation signal. If already aborted, `withCommit`\n\t * rejects with the signal's `reason` BEFORE opening the transaction.\n\t * Otherwise the signal is forwarded to `scope.transactional`, where a\n\t * cancellation-aware scope can abort an in-flight query. The kit does\n\t * not race the work promise: aborting does not kill a running query\n\t * unless the scope honors the signal.\n\t */\n\tsignal?: AbortSignal;\n}\n\ndeclare const aggregateCommitTokenBrand: unique symbol;\n\n/**\n * Opaque receipt that one aggregate was explicitly enrolled in the current\n * {@link withCommit} invocation. Tokens are minted only by the invocation's\n * {@link CommitEnrollment} capability and are bound to that invocation at\n * runtime; a forged token or one retained from an earlier call is rejected\n * inside the transaction.\n */\nexport interface AggregateCommitToken<\n\tEvt extends AnyDomainEvent = AnyDomainEvent,\n> {\n\treadonly [aggregateCommitTokenBrand]: Evt;\n}\n\n/**\n * Invocation-scoped enrollment capability handed to a {@link withCommit}\n * callback. Call `enrollSaved` only for an aggregate participating in the\n * repository write, and return every resulting token in `commits`. Omitting\n * any token rejects the transaction: an enrolled write may not commit without\n * its event harvest and post-commit acknowledgement. Enrollable instances\n * must extend `AggregateRoot` or `EventSourcedAggregate`; structural\n * `IAggregateRoot` lookalikes have no internal lifecycle capability and fail\n * before commit.\n */\nexport interface CommitEnrollment<Evt extends AnyDomainEvent> {\n\tenrollSaved(\n\t\taggregate: IAggregateRoot<Id<string>, Evt>,\n\t\toptions?: CommitEnrollmentOptions,\n\t): AggregateCommitToken<Evt>;\n\t/**\n\t * Enroll an aggregate whose row is deleted by the current transaction.\n\t * Its events are harvested and discarded after commit, but the saved-only\n\t * application `onPersisted` observer is not called.\n\t */\n\tenrollDeleted(\n\t\taggregate: IAggregateRoot<Id<string>, Evt>,\n\t\toptions?: CommitEnrollmentOptions,\n\t): AggregateCommitToken<Evt>;\n}\n\n/** OCC baseline associated with one exact commit enrollment. */\nexport interface CommitEnrollmentOptions {\n\t/** Absent for a new aggregate; captured at load for update or removal. */\n\treadonly expectedVersion?: Version;\n}\n\n/** The resolved value of a {@link withCommit} work callback. */\nexport interface WithCommitWorkResult<Evt extends AnyDomainEvent, R> {\n\tresult: R;\n\t/**\n\t * Commit tokens returned by the invocation's enrollment capability.\n\t * Every token minted during the callback must appear at least once.\n\t * Naked aggregates are intentionally not accepted: touching an aggregate\n\t * does not prove that its repository write participated in the transaction.\n\t */\n\tcommits: ReadonlyArray<AggregateCommitToken<Evt>>;\n}\n\ntype CommitDisposition = \"saved\" | \"deleted\";\n\ninterface AggregateCommitRecord<Evt extends AnyDomainEvent> {\n\treadonly aggregate: IAggregateRoot<Id<string>, Evt>;\n\treadonly eventLifecycle: PendingEventLifecycleCapability;\n\treadonly version: Version;\n\treadonly expectedVersion: Version | undefined;\n\t/**\n\t * Version the persistence layer last confirmed for the aggregate at\n\t * enrollment time (kit-maintained). `undefined` means the aggregate was\n\t * never persisted, so any single eventful commit cursor is unique.\n\t */\n\treadonly persistedVersion: Version | undefined;\n\treadonly events: ReadonlyArray<PendingDomainEvent<Evt>>;\n\tdisposition: CommitDisposition;\n}\n\n/**\n * True when the aggregate's live version or pending-event batch no longer\n * matches its enrollment-time snapshot. Shared by the duplicate-enrollment\n * gate and the harvest-time recheck: both must reject the same divergence,\n * or events recorded after enrollment would be silently dropped.\n */\nfunction enrollmentDiverged<Evt extends AnyDomainEvent>(\n\trecord: AggregateCommitRecord<Evt>,\n): boolean {\n\tconst pending = record.aggregate.pendingEvents;\n\treturn (\n\t\trecord.aggregate.version !== record.version ||\n\t\tpending.length !== record.events.length ||\n\t\trecord.events.some((event, index) => event !== pending[index])\n\t);\n}\n\ninterface CommitTokenScope<Evt extends AnyDomainEvent> {\n\treadonly enrollment: CommitEnrollment<Evt>;\n\tclose(): void;\n\tresolve(tokens: unknown): ReadonlyArray<AggregateCommitRecord<Evt>>;\n}\n\n/** One token registry per transactional callback attempt. */\nfunction createCommitTokenScope<\n\tEvt extends AnyDomainEvent,\n>(): CommitTokenScope<Evt> {\n\tconst recordsByToken = new WeakMap<object, AggregateCommitRecord<Evt>>();\n\tconst tokensByAggregate = new WeakMap<\n\t\tIAggregateRoot<Id<string>, Evt>,\n\t\tAggregateCommitToken<Evt>\n\t>();\n\tlet mintedTokenCount = 0;\n\tlet open = true;\n\n\tconst enroll = (\n\t\taggregate: IAggregateRoot<Id<string>, Evt>,\n\t\tdisposition: CommitDisposition,\n\t\toptions?: CommitEnrollmentOptions,\n\t): AggregateCommitToken<Evt> => {\n\t\tif (!open) {\n\t\t\tthrow new EventHarvestError(\n\t\t\t\t\"withCommit: commit enrollment was used after its work callback \" +\n\t\t\t\t\t\"settled. Await every repository write and return its token before \" +\n\t\t\t\t\t\"leaving the callback.\",\n\t\t\t);\n\t\t}\n\n\t\tconst existing = tokensByAggregate.get(aggregate);\n\t\tif (existing) {\n\t\t\tconst record = recordsByToken.get(existing);\n\t\t\tif (!record) {\n\t\t\t\tthrow new EventHarvestError(\n\t\t\t\t\t\"withCommit: internal commit-token registry is inconsistent.\",\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (record.disposition === \"deleted\" && disposition === \"saved\") {\n\t\t\t\tthrow new EventHarvestError(\n\t\t\t\t\t`withCommit: aggregate ${String(aggregate.id)} was enrolled as ` +\n\t\t\t\t\t\t\"saved after it was enrolled as deleted in the same transaction.\",\n\t\t\t\t);\n\t\t\t}\n\t\t\t// Duplicate enrollment is idempotent by reference. An omitted\n\t\t\t// expectedVersion is no assertion, not an assertion of \"absent\":\n\t\t\t// only a supplied value is compared against the recorded baseline.\n\t\t\tif (\n\t\t\t\toptions?.expectedVersion !== undefined &&\n\t\t\t\toptions.expectedVersion !== record.expectedVersion\n\t\t\t) {\n\t\t\t\tthrow new EventHarvestError(\n\t\t\t\t\t`withCommit: aggregate ${String(aggregate.id)} was re-enrolled ` +\n\t\t\t\t\t\t`with expectedVersion ${String(options.expectedVersion)}, but its ` +\n\t\t\t\t\t\t`enrollment recorded ${String(record.expectedVersion)}. Duplicate ` +\n\t\t\t\t\t\t\"enrollment must assert the same OCC baseline or none.\",\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (enrollmentDiverged(record)) {\n\t\t\t\tthrow new EventHarvestError(\n\t\t\t\t\t`withCommit: aggregate ${String(aggregate.id)} changed after its ` +\n\t\t\t\t\t\t\"commit batch was enrolled. Register persistence intent last.\",\n\t\t\t\t);\n\t\t\t}\n\t\t\t// The widened disposition is adopted only after every check passed:\n\t\t\t// a rejected enrollDeleted whose error the callback catches must\n\t\t\t// not leave a saved aggregate marked deleted, or the post-commit\n\t\t\t// loop would discard instead of acknowledge.\n\t\t\tif (disposition === \"deleted\") {\n\t\t\t\trecord.disposition = \"deleted\";\n\t\t\t}\n\t\t\treturn existing;\n\t\t}\n\n\t\tconst eventLifecycle = pendingEventLifecycleCapabilityFor(aggregate);\n\t\tif (!eventLifecycle) {\n\t\t\tthrow new EventHarvestError(\n\t\t\t\t`withCommit: aggregate ${String(aggregate.id)} has no kit-managed ` +\n\t\t\t\t\t\"persistence lifecycle. Extend AggregateRoot or \" +\n\t\t\t\t\t\"EventSourcedAggregate; repository DTOs and structural lookalikes \" +\n\t\t\t\t\t\"cannot be enrolled for commit acknowledgement.\",\n\t\t\t);\n\t\t}\n\n\t\tconst token = Object.freeze(\n\t\t\tObject.create(null),\n\t\t) as AggregateCommitToken<Evt>;\n\t\t// The pendingEvents getter already returns a frozen detached copy;\n\t\t// re-copying and re-freezing it here would only duplicate the work.\n\t\tconst events = aggregate.pendingEvents;\n\t\t// Recorded-before-persistence is checked HERE, not only at harvest:\n\t\t// the UnitOfWork enrolls at write registration, so this rejection\n\t\t// lands before any adapter flush. The harvest guard alone fires after\n\t\t// flush, and a non-transactional event store would already have\n\t\t// appended the unstamped batch durably.\n\t\tfor (const event of events) {\n\t\t\tif (!isMintedEvent(event)) {\n\t\t\t\tthrow new EventHarvestError(\n\t\t\t\t\t`withCommit: event \"${(event as { readonly type: string }).type}\" ` +\n\t\t\t\t\t\t\"has not been recorded. Call recordPendingEvents(aggregate, \" +\n\t\t\t\t\t\t\"createStamp) in the application shell before persistence or \" +\n\t\t\t\t\t\t\"outbox harvest.\",\n\t\t\t\t\t(event as { readonly type: string }).type,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\t// The kit-maintained marker, not the enrollment-supplied\n\t\t// expectedVersion, grounds the unique-cursor guard: it survives\n\t\t// callers who omit enrollment options (the documented\n\t\t// direct-withCommit style), and grounding the guard in data supplied\n\t\t// by the very caller it checks would be circular.\n\t\tconst persistedVersion = eventLifecycle.persistedVersion() as\n\t\t\t| Version\n\t\t\t| undefined;\n\t\ttokensByAggregate.set(aggregate, token);\n\t\trecordsByToken.set(token, {\n\t\t\taggregate,\n\t\t\teventLifecycle,\n\t\t\tdisposition,\n\t\t\tversion: aggregate.version,\n\t\t\texpectedVersion: options?.expectedVersion,\n\t\t\tpersistedVersion,\n\t\t\tevents,\n\t\t});\n\t\tmintedTokenCount += 1;\n\t\treturn token;\n\t};\n\n\treturn {\n\t\tenrollment: Object.freeze({\n\t\t\tenrollSaved: (\n\t\t\t\taggregate: IAggregateRoot<Id<string>, Evt>,\n\t\t\t\toptions?: CommitEnrollmentOptions,\n\t\t\t) => enroll(aggregate, \"saved\", options),\n\t\t\tenrollDeleted: (\n\t\t\t\taggregate: IAggregateRoot<Id<string>, Evt>,\n\t\t\t\toptions?: CommitEnrollmentOptions,\n\t\t\t) => enroll(aggregate, \"deleted\", options),\n\t\t}),\n\t\tclose: () => {\n\t\t\topen = false;\n\t\t},\n\t\tresolve: (tokens) => {\n\t\t\tif (!Array.isArray(tokens)) {\n\t\t\t\tthrow new EventHarvestError(\n\t\t\t\t\t\"withCommit: the work callback must return `commits` containing \" +\n\t\t\t\t\t\t\"tokens from the current enrollment capability. Naked aggregate \" +\n\t\t\t\t\t\t\"arrays are not commit evidence.\",\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst seen = new Set<object>();\n\t\t\tconst records: AggregateCommitRecord<Evt>[] = [];\n\t\t\tfor (const token of tokens) {\n\t\t\t\tif (\n\t\t\t\t\ttoken === null ||\n\t\t\t\t\t(typeof token !== \"object\" && typeof token !== \"function\")\n\t\t\t\t) {\n\t\t\t\t\tthrow new EventHarvestError(\n\t\t\t\t\t\t\"withCommit: a commit token was not minted by this callback's \" +\n\t\t\t\t\t\t\t\"enrollment capability. Forged and stale tokens are rejected.\",\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tconst tokenObject = token as object;\n\t\t\t\tconst record = recordsByToken.get(tokenObject);\n\t\t\t\tif (!record) {\n\t\t\t\t\tthrow new EventHarvestError(\n\t\t\t\t\t\t\"withCommit: a commit token was not minted by this callback's \" +\n\t\t\t\t\t\t\t\"enrollment capability. Forged and stale tokens are rejected.\",\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tif (seen.has(tokenObject)) continue;\n\t\t\t\tseen.add(tokenObject);\n\t\t\t\t// Harvest-time recheck of the enrollment snapshot: an event\n\t\t\t\t// recorded after enrollSaved but before the callback returned\n\t\t\t\t// would be excluded from the harvest and silently lost by the\n\t\t\t\t// post-commit prefix acknowledgement. Divergence fails loudly\n\t\t\t\t// inside the transaction instead.\n\t\t\t\tif (enrollmentDiverged(record)) {\n\t\t\t\t\tthrow new EventHarvestError(\n\t\t\t\t\t\t`withCommit: aggregate ${String(record.aggregate.id)} changed ` +\n\t\t\t\t\t\t\t\"after its commit batch was enrolled; events recorded after \" +\n\t\t\t\t\t\t\t\"enrollment are not part of the attested write and would be \" +\n\t\t\t\t\t\t\t\"silently dropped. Make domain decisions first, write, and \" +\n\t\t\t\t\t\t\t\"enroll last.\",\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\trecords.push(record);\n\t\t\t}\n\t\t\tif (seen.size !== mintedTokenCount) {\n\t\t\t\tthrow new EventHarvestError(\n\t\t\t\t\t\"withCommit: every token minted by the current enrollment \" +\n\t\t\t\t\t\t\"capability must be returned in `commits`. If an enrolled write \" +\n\t\t\t\t\t\t\"must not commit, throw so the transaction rolls back.\",\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn records;\n\t\t},\n\t};\n}\n\n/**\n * Helper for executing a write Use Case inside a transaction scope.\n *\n * The use-case callback receives an invocation-scoped enrollment capability\n * and returns opaque commit tokens for the repository writes that completed\n * in the transaction. `withCommit` owns the post-commit lifecycle (harvest,\n * outbox, mark-persisted, publish). A naked aggregate is not commit evidence:\n * merely touching or constructing one must never make it look persisted.\n *\n * **Trust boundary.** A token proves invocation-local enrollment, not that the\n * kit inspected a database write; a generic transaction helper cannot observe\n * adapter internals. Repository code must enroll only writes participating in\n * this transaction. `UnitOfWork` centralizes that rule in repository methods.\n * The opaque, scoped token prevents accidental aggregate smuggling and stale\n * reuse; it is not a security boundary against code that deliberately lies to\n * its own persistence capability.\n *\n * Order of operations:\n * 1. `fn(ctx, enrollment)` runs inside `scope.transactional(...)`; domain\n * mutations + repo writes happen here. After a repository write has\n * enrolled an aggregate, the callback includes that opaque token in its\n * `commits` result. Tokens are invocation-bound: forged or stale tokens\n * fail before harvest. `ctx` is whatever transaction handle the `scope`\n * exposes (Drizzle `tx`, Prisma `tx`, Mongo session, or `undefined` for\n * context-free scopes).\n * 2. **Still inside the transaction**, `withCommit` harvests every\n * aggregate's `pendingEvents` and writes them via `outbox.add` (so\n * events persist atomically with the state change). Skipped when no\n * events were recorded. Each bare domain event is composed into an\n * `EventCommitCandidate` carrying its aggregate source and the commit\n * facts known by the application. The outbox source atomically links\n * that candidate to the preceding eventful commit and persists the\n * resulting `CommittedDomainEvent`. The domain event itself is never\n * stamped or copied.\n *\n * **Harvest order.** Events are concatenated in the order\n * tokens appear in the returned `commits` array, then in\n * each aggregate's `pendingEvents` order (insertion order via\n * `apply` / `commit` / `addDomainEvent`). So tokens for `[a, b]`\n * with `a` emitting `[e1, e2]` and `b` emitting `[e3]` produces\n * `outbox.add([envelope(e1), envelope(e2), envelope(e3)])` and\n * `bus.publish([e1, e2, e3])` in that exact order.\n *\n * **Two ordering guarantees, not one.** Within a single aggregate\n * the order is *causal*: events are recorded in the order the\n * domain methods ran, and subscribers (handlers, projections,\n * replay) MUST process them in that order. Across aggregates the\n * order in this batch is deterministic but *not* a domain\n * guarantee. Greg Young / Vernon IDDD §10: aggregates are\n * independent consistency boundaries; events across them are\n * eventually consistent. Subscribers should NOT engineer\n * dependencies on cross-aggregate ordering; use\n * `EventMetadata.causationId` to express true causation, or a\n * process manager to coordinate. The in-process EventBus delivers\n * this batch in order, sequential outbox-dispatchers preserve it\n * too, but parallel dispatchers or message brokers may reorder\n * across aggregates at delivery time.\n * 3. The transaction commits.\n * 4. **After** the commit, a non-exported capability acknowledges every\n * saved enrollment and discards pending events for deleted enrollments.\n * Only after the complete commit set is clean does the optional\n * application-shell `onPersisted(aggregate, version, context)` observer run for\n * saved aggregates. Deleted rows never trigger that observer.\n * 5. `bus.publish(events)` fires for the in-process fast path (skipped\n * when no events or no `bus` is wired).\n *\n * Publishing AFTER commit prevents the classic \"publish before commit\"\n * footgun: in-process subscribers can never react to events from a\n * transaction that later rolled back. If `bus.publish` itself throws, the\n * outbox still holds the events and an outbox-dispatcher will deliver\n * them (eventual consistency).\n *\n * **A `bus.publish` failure never rejects `withCommit`.** Once the\n * transaction has committed, the write succeeded; surfacing a subscriber\n * failure as a rejection would hand the caller a use-case failure for a\n * committed write (a typical caller retries, double-executing it). The\n * in-process fast path is best-effort by design; the error is reported to\n * the optional `onPublishError(error, events)` hook (wire it to your\n * logger/metrics) and otherwise dropped; delivery is still guaranteed via\n * the outbox. The hook is an observer: if it throws, its error is\n * swallowed so the post-commit invariant holds.\n * The complete application-observer and bus-publication phase shares one\n * absolute `postCommitTimeoutMs` budget (30 seconds by default); later callbacks\n * are not started once it expires. A timeout or owner abort is reported\n * through the same observer paths and never changes the committed result.\n *\n * If the transaction rolls back, no acknowledgement occurs: the aggregate\n * keeps its pending events, so the caller can retry or discard the instance.\n *\n * Enrollment captures an exact version and event batch. Re-enrolling the same\n * aggregate after it changes rejects. `UnitOfWork` additionally seals the\n * adapter persistence projection and rejects later mutation before flush. For\n * direct `withCommit` use, make domain decisions first, write, and enroll last.\n *\n * **Duplicate enrollment is idempotent by reference.** Enrolling the same\n * instance repeatedly returns the same token, and a repeated token in\n * `commits` is harvested once. A repeat call that omits `expectedVersion`\n * makes no OCC assertion; only a supplied value that contradicts the\n * enrollment-time baseline rejects. Each event lands in the outbox exactly once\n * and post-commit acknowledgement runs exactly once. Two\n * *different* instances with the same logical id cannot be detected\n * at this layer; that is a Repository contract violation (failure to\n * maintain Fowler's Identity Map per Unit of Work). See\n * `docs/guide/repository.md` → \"Identity Map: one instance per\n * aggregate per Unit of Work\" for the requirement on repository\n * implementations that makes this dedupe sound.\n *\n * @example Tx-bound repos (Drizzle, Prisma, Mongo, …)\n * ```typescript\n * const result = await withCommit({ outbox, bus, scope }, async (tx, enrollment) => {\n * const orderRepository = makeOrderRepository(tx); // your factory binds tx to the repo\n * const order = await orderRepository.getById(orderId);\n * order.confirm();\n * await persistOrder(tx, order); // low-level adapter write\n * const commit = enrollment.enrollSaved(order); // attest the repository write\n * return { result: order.id, commits: [commit] };\n * });\n * ```\n */\nexport async function withCommit<Evt extends AnyDomainEvent, R, TCtx>(\n\tdeps: WithCommitDeps<Evt, TCtx>,\n\tfn: (\n\t\tctx: TCtx,\n\t\tenrollment: CommitEnrollment<Evt>,\n\t) => Promise<WithCommitWorkResult<Evt, R>>,\n): Promise<R> {\n\tconst postCommitTimeoutMs =\n\t\tdeps.postCommitTimeoutMs ?? DEFAULT_EXECUTION_TIMEOUT_MS;\n\tassertNonNegativeFinite(\n\t\t\"withCommit\",\n\t\t\"postCommitTimeoutMs\",\n\t\tpostCommitTimeoutMs,\n\t);\n\n\t// Pre-flight: an already-aborted caller never opens a transaction.\n\t// Throwing the signal's reason matches the web AbortSignal convention;\n\t// the `??` fallback mirrors event-bus.ts and guards a non-spec polyfill\n\t// whose `reason` is undefined (a bare `throw undefined` is unusable).\n\tif (deps.signal?.aborted) {\n\t\tthrow abortReason(\n\t\t\tdeps.signal,\n\t\t\t\"withCommit aborted before opening a transaction\",\n\t\t);\n\t}\n\n\tconst { result, commitRecords, events } = await deps.scope.transactional(\n\t\tasync (ctx) => {\n\t\t\tconst tokenScope = createCommitTokenScope<Evt>();\n\t\t\tlet fnResult: WithCommitWorkResult<Evt, R>;\n\t\t\ttry {\n\t\t\t\tfnResult = await fn(ctx, tokenScope.enrollment);\n\t\t\t} finally {\n\t\t\t\t// A callback can leak the capability into delayed work. Seal it as\n\t\t\t\t// soon as the callback settles so a late enrollment fails loudly\n\t\t\t\t// instead of being accepted after the harvest snapshot.\n\t\t\t\ttokenScope.close();\n\t\t\t}\n\t\t\tconst commitRecords = tokenScope.resolve(fnResult.commits);\n\t\t\t// Prepare each bare domain event for source finalization in the outbox.\n\t\t\t// The aggregate's event remains untouched and is what the in-process\n\t\t\t// domain bus receives.\n\t\t\tconst candidates = commitRecords.flatMap((record) => {\n\t\t\t\tconst agg = record.aggregate;\n\t\t\t\tif (\n\t\t\t\t\trecord.events.length > 0 &&\n\t\t\t\t\trecord.persistedVersion !== undefined &&\n\t\t\t\t\t(record.version as number) <= (record.persistedVersion as number)\n\t\t\t\t) {\n\t\t\t\t\tthrow new EventHarvestError(\n\t\t\t\t\t\t`withCommit: aggregate ${String(agg.id)} recorded events but ` +\n\t\t\t\t\t\t\t`did not advance its version beyond the persisted version ` +\n\t\t\t\t\t\t\t`(${String(record.persistedVersion)}). An eventful commit needs a unique ` +\n\t\t\t\t\t\t\t`cursor; use AggregateRoot.commit(currentState, event) instead ` +\n\t\t\t\t\t\t\t`of addDomainEvent(event) alone.`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\treturn record.events.map((event, index) => {\n\t\t\t\t\tif (!isMintedEvent(event)) {\n\t\t\t\t\t\tthrow new EventHarvestError(\n\t\t\t\t\t\t\t`withCommit: event \"${event.type}\" has not been recorded. ` +\n\t\t\t\t\t\t\t\t\"Call recordPendingEvents(aggregate, createStamp) in the \" +\n\t\t\t\t\t\t\t\t\"application shell before persistence or outbox harvest.\",\n\t\t\t\t\t\t\tevent.type,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\tconst recordedEvent = event as Evt;\n\t\t\t\t\tconst commitSize = record.events.length;\n\t\t\t\t\tconst aggregateId = recordedEvent.aggregateId;\n\t\t\t\t\tconst aggregateType = recordedEvent.aggregateType;\n\t\t\t\t\tconst missing: string[] = [];\n\t\t\t\t\tif (!aggregateId) missing.push(\"aggregateId\");\n\t\t\t\t\tif (!aggregateType) missing.push(\"aggregateType\");\n\t\t\t\t\tif (!aggregateId || !aggregateType) {\n\t\t\t\t\t\tthrow new EventHarvestError(\n\t\t\t\t\t\t\t`withCommit: event \"${recordedEvent.type}\" is missing ${missing.join(\n\t\t\t\t\t\t\t\t\" and \",\n\t\t\t\t\t\t\t)}. ` +\n\t\t\t\t\t\t\t\t`Use this.createEvent(type, payload) inside aggregate methods ` +\n\t\t\t\t\t\t\t\t`instead of createDomainEvent(...); createEvent auto-injects ` +\n\t\t\t\t\t\t\t\t`aggregateId and aggregateType. Outbox dispatchers and ` +\n\t\t\t\t\t\t\t\t`projection handlers rely on the envelope source.`,\n\t\t\t\t\t\t\trecordedEvent.type,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\treturn Object.freeze({\n\t\t\t\t\t\tevent: recordedEvent,\n\t\t\t\t\t\tsource: Object.freeze({ aggregateId, aggregateType }),\n\t\t\t\t\t\tposition: Object.freeze({\n\t\t\t\t\t\t\taggregateVersion: record.version as number,\n\t\t\t\t\t\t\tcommitSequence: index,\n\t\t\t\t\t\t\tcommitSize,\n\t\t\t\t\t\t}),\n\t\t\t\t\t}) as EventCommitCandidate<Evt>;\n\t\t\t\t});\n\t\t\t});\n\t\t\tif (candidates.length > 0) {\n\t\t\t\tawait deps.outbox.add(candidates);\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tresult: fnResult.result,\n\t\t\t\tcommitRecords,\n\t\t\t\tevents: candidates.map(({ event }) => event),\n\t\t\t};\n\t\t},\n\t\t{ signal: deps.signal },\n\t);\n\n\t// Post-commit: capture the persisted versions, acknowledge every saved\n\t// aggregate, and discard pending events for deleted aggregates through the\n\t// non-exported capability.\n\t// Done AFTER the tx commits so a rolled-back transaction never silently\n\t// \"consumes\" the in-memory pending events. A deleted row does not trigger\n\t// the saved-only application observer.\n\tconst persistedObservations: Array<{\n\t\treadonly aggregate: IAggregateRoot<Id<string>, Evt>;\n\t\treadonly version: Version;\n\t}> = [];\n\tfor (const {\n\t\taggregate,\n\t\teventLifecycle,\n\t\tdisposition,\n\t\tversion,\n\t\tevents: committedEvents,\n\t} of commitRecords) {\n\t\ttry {\n\t\t\tif (disposition === \"deleted\") {\n\t\t\t\teventLifecycle.discardPendingEvents(committedEvents);\n\t\t\t} else {\n\t\t\t\teventLifecycle.acknowledge(committedEvents, version as number);\n\t\t\t\tpersistedObservations.push({ aggregate, version });\n\t\t\t}\n\t\t} catch (error) {\n\t\t\t// An aggregate can still be made hostile at runtime, for example by\n\t\t\t// freezing it after construction. The transaction has committed, so\n\t\t\t// continue cleaning peers and report the failed acknowledgement rather\n\t\t\t// than rejecting a successful write or double-emitting peer events.\n\t\t\treportToObserver(() => deps.onPersistError?.(error, aggregate));\n\t\t}\n\t}\n\n\t// Application observers run only after every commit record has completed\n\t// its acknowledgement attempt, and only for successful acknowledgements.\n\t// A slow or failing observer can therefore never prevent peer cleanup. Each\n\t// observer receives the version captured before any observer ran, so an\n\t// earlier callback cannot rewrite a later callback's commit receipt.\n\tconst postCommitDeadlineAt = Date.now() + postCommitTimeoutMs;\n\tconst onPersisted = deps.onPersisted;\n\tif (onPersisted) {\n\t\tfor (const { aggregate, version } of persistedObservations) {\n\t\t\ttry {\n\t\t\t\tawait runBoundedExecution(\n\t\t\t\t\t\"withCommit.onPersisted\",\n\t\t\t\t\t{ signal: deps.signal, deadlineAt: postCommitDeadlineAt },\n\t\t\t\t\t(context) => onPersisted(aggregate, version, context),\n\t\t\t\t);\n\t\t\t} catch (error) {\n\t\t\t\treportToObserver(() => deps.onPersistError?.(error, aggregate));\n\t\t\t}\n\t\t}\n\t}\n\n\tconst bus = deps.bus;\n\tif (bus && events.length > 0) {\n\t\ttry {\n\t\t\tawait runBoundedExecution(\n\t\t\t\t\"withCommit.bus.publish\",\n\t\t\t\t{ signal: deps.signal, deadlineAt: postCommitDeadlineAt },\n\t\t\t\t(context) =>\n\t\t\t\t\tbus.publish(events, {\n\t\t\t\t\t\tsignal: context.signal,\n\t\t\t\t\t\ttimeoutMs: Math.max(0, context.deadlineAt - Date.now()),\n\t\t\t\t\t}),\n\t\t\t);\n\t\t} catch (error) {\n\t\t\t// The tx has committed and the outbox holds the events; an\n\t\t\t// outbox dispatcher will deliver them. Rejecting here would turn\n\t\t\t// a committed write into an apparent use-case failure (callers\n\t\t\t// would retry and double-execute). A throwing OR async-rejecting\n\t\t\t// observer is neutralised so it cannot break the invariant either.\n\t\t\treportToObserver(() => deps.onPublishError?.(error, events));\n\t\t}\n\t}\n\n\treturn result;\n}\n","import type { AnyDomainEvent } from \"../aggregate/domain-event\";\nimport {\n\tEventHarvestError,\n\tIdempotencyReconciliationRequiredError,\n} from \"../core/errors\";\nimport type { TransactionScope } from \"../repo/scope\";\nimport { reportToObserver } from \"../utils/observer\";\nimport {\n\ttype CommitEnrollment,\n\ttype WithCommitDeps,\n\ttype WithCommitWorkResult,\n\twithCommit,\n} from \"./handler\";\n\n/**\n * Result of `IdempotencyStore.claim()`: this execution owns the key and must\n * run the command (`claimed`), a previous execution completed and its outcome\n * is replayed (`completed`), or an expired staged outcome needs evidence from\n * the authoritative write model (`reconciliation-required`).\n *\n * The two FAILURE answers are thrown, not returned, following the kit's\n * error posture: a concurrent unfinished execution throws\n * `IdempotencyInFlightError` (retryable), and the same key arriving\n * with a different fingerprint throws `IdempotencyKeyReuseError`\n * (not retryable).\n */\nexport interface IdempotencyLease {\n\t/** Adapter-clock expiry as a canonical ISO-8601 timestamp. */\n\treadonly expiresAt: string;\n\t/** Delay after which the wrapper should renew this lease. */\n\treadonly renewAfterMs: number;\n}\n\n/** Store-minted ownership receipt for one successful claim. */\nexport interface IdempotencyClaimHandle {\n\treadonly key: string;\n\t/** Unique across ownership generations for this key; treat as opaque. */\n\treadonly token: string;\n\t/** Absent for a transactional store; required for a leased store. */\n\treadonly lease?: IdempotencyLease;\n}\n\n/** Receipt for an expired staged outcome that needs authoritative evidence. */\nexport interface IdempotencyReconciliation {\n\treadonly key: string;\n\treadonly fingerprint: string;\n\treadonly token: string;\n\treadonly expiredAt: string;\n}\n\nexport type IdempotencyReconciliationDecision =\n\t| \"committed\"\n\t| \"not-committed\"\n\t| \"unknown\";\n\nexport type IdempotencyClaim =\n\t| { readonly status: \"claimed\"; readonly claim: IdempotencyClaimHandle }\n\t| { readonly status: \"completed\"; readonly outcome: unknown }\n\t| {\n\t\t\treadonly status: \"reconciliation-required\";\n\t\t\treadonly reconciliation: IdempotencyReconciliation;\n\t };\n\n/**\n * Driven port for command idempotency and message-inbox deduplication.\n *\n * The store keeps one record per idempotency key: the key, a\n * fingerprint of the command that first claimed it, and, once the\n * execution completed, the stored outcome. The intended integration is\n * the SINGLE-TRANSACTION pattern via {@link withIdempotentCommit}: the\n * record is written in the same transaction as the aggregate and the\n * outbox, so a rollback releases the claim and there is no crash window\n * between claim and commit.\n *\n * Adapter contract (mirror of the repository/event-store delegation\n * model): the adapter maps its store's native signals onto the kit's\n * errors instead of leaking driver errors:\n *\n * - unique-constraint conflict from a CONCURRENT uncommitted claim ->\n * `IdempotencyInFlightError` (retryable; a retry replays the outcome\n * or claims fresh),\n * - existing COMPLETED record with the same fingerprint -> return\n * `{ status: \"completed\", outcome }`,\n * - existing record with a DIFFERENT fingerprint ->\n * `IdempotencyKeyReuseError`.\n *\n * **Transactional vs leased non-transactional stores.** A transactional\n * adapter (the record lives in the same database as the aggregate)\n * gets the commit boundary for free: `complete` is atomic with the\n * command's commit, a rollback releases everything, and `confirm` /\n * `abandon` / `renew` / `reconcile` are no-ops. This remains the recommended\n * production pattern and the only family that proves atomic command effect +\n * idempotency completion without reconciliation.\n *\n * A NON-transactional store (the in-memory reference, a separate durable\n * store) cannot see commits or rollbacks. Every fresh claim therefore returns\n * a store-minted token and bounded lease. The wrapper renews it while the\n * transaction runs; `complete`, `renew`, `confirm`, `abandon`, and `reconcile`\n * compare the token so a stale owner cannot mutate a successor claim. An\n * expired PENDING claim may be replaced. An expired STAGED outcome is never\n * replayed or released automatically: `claim` returns\n * `reconciliation-required`, and the application must consult the source of\n * truth. `unknown` keeps it blocked.\n *\n * A lease is coordination, not a security or exactly-once boundary. To return\n * `not-committed` safely, the source transaction must persist an idempotency\n * key or claim token (available as the callback's `execution` argument), or\n * offer equivalent durable fencing proving the old transaction cannot still\n * commit. Without that evidence, return `unknown`. A database row merely being\n * absent while an old transaction may still be in flight is not proof.\n * A takeover can overlap briefly with the stale worker, so `fn` must keep\n * irreversible external side effects out of the transaction. Persist an\n * outbox record and deliver after commit; token fencing can stop the stale\n * database commit, but it cannot undo an HTTP call already sent.\n *\n * The same store doubles as a message INBOX: use the message id as the\n * key and a constant fingerprint; a duplicate delivery replays the\n * stored (possibly `undefined`) outcome instead of re-running the\n * handler.\n *\n * The stored outcome must be PLAIN, serialisable data (the same\n * discipline as snapshots and event payloads): the record round-trips\n * through the adapter's storage, so class instances would silently lose\n * their prototype.\n *\n * @template TCtx - The transaction context the surrounding scope\n * exposes (Drizzle `tx`, Prisma `tx`, `undefined` for context-free\n * scopes). `claim` and `complete` run inside that transaction.\n */\nexport interface IdempotencyStore<TCtx = unknown> {\n\t/**\n\t * Claims the key for this execution, atomically with respect to\n\t * concurrent claimers (`INSERT ... ON CONFLICT` or equivalent).\n\t * Returns `claimed` when this execution owns the key, or\n\t * `completed` with the stored outcome when a previous execution\n\t * already finished under the same key and fingerprint. Throws\n\t * `IdempotencyInFlightError` / `IdempotencyKeyReuseError` for the\n\t * failure answers (see the port docs). A live staged outcome is in-flight;\n\t * after its lease expires it returns `reconciliation-required`, never a\n\t * replay or fresh claim.\n\t */\n\tclaim(ctx: TCtx, key: string, fingerprint: string): Promise<IdempotencyClaim>;\n\n\t/**\n\t * Stores the outcome for a key this execution claimed, in the same\n\t * transaction as the command's writes. On a transactional store the\n\t * commit makes it durable and replayable; on a non-transactional\n\t * store the outcome is only STAGED until {@link confirm} runs.\n\t * Throws `IdempotencyCompletionWithoutClaimError` when no claim exists, and\n\t * `IdempotencyClaimLostError` when the receipt is stale, already settled, or\n\t * expired. A stale completion must fail before the source transaction can\n\t * commit.\n\t */\n\tcomplete(\n\t\tctx: TCtx,\n\t\tclaim: IdempotencyClaimHandle,\n\t\toutcome: unknown,\n\t): Promise<void>;\n\n\t/**\n\t * Extends a non-transactional claim's lease and returns its new timing.\n\t * The update is compare-and-set on key + token. A transactional adapter\n\t * implements this as a no-op returning `undefined`; the wrapper never calls\n\t * it for a claim without a lease.\n\t */\n\trenew(claim: IdempotencyClaimHandle): Promise<IdempotencyLease | undefined>;\n\n\t/**\n\t * Finalizes a staged outcome AFTER the surrounding transaction\n\t * committed. Called by {@link withIdempotentCommit} post-commit on\n\t * every fresh execution. A transactional adapter implements this as\n\t * a no-op (the commit already finalized the record). Idempotent:\n\t * confirming an already-confirmed receipt is a no-op. A missing or stale\n\t * receipt is also a no-op and must never confirm its successor.\n\t */\n\tconfirm(claim: IdempotencyClaimHandle): Promise<void>;\n\n\t/**\n\t * Releases a claim whose attempt did not commit: a pending claim or\n\t * a staged, unconfirmed outcome. Called by\n\t * {@link withIdempotentCommit} once per failed attempt, best-effort.\n\t * A transactional adapter implements this as a no-op: the rollback\n\t * already removed the row, and the method must be SAFE to call when\n\t * the commit outcome is unknown; it never releases a confirmed\n\t * record. A stale receipt is a no-op and must never release its successor.\n\t */\n\tabandon(claim: IdempotencyClaimHandle): Promise<void>;\n\n\t/**\n\t * Resolves an EXPIRED staged outcome after the application consulted its\n\t * authoritative write model. `committed` makes the staged result replayable;\n\t * `not-committed` releases it for a fresh execution. `unknown` is\n\t * intentionally not accepted here: uncertainty must preserve the record.\n\t * The receipt is compare-and-set so a stale reconciler cannot settle a newer\n\t * owner. Transactional adapters implement this as a no-op because they never\n\t * return `reconciliation-required`.\n\t */\n\treconcile(\n\t\treconciliation: IdempotencyReconciliation,\n\t\tdecision: Exclude<IdempotencyReconciliationDecision, \"unknown\">,\n\t): Promise<void>;\n}\n\n/** Identifies one logical command execution for {@link withIdempotentCommit}. */\nexport interface IdempotentCommitRequest {\n\t/**\n\t * The idempotency key: client-supplied header, message id, or a key\n\t * derived from actor + intention. One key names one logical command.\n\t */\n\treadonly key: string;\n\t/**\n\t * Fingerprint of the command's content (a hash or canonical string\n\t * of the request payload). Detects the same key being reused for a\n\t * DIFFERENT command, which is rejected instead of replayed.\n\t */\n\treadonly fingerprint: string;\n}\n\n/**\n * Outcome of {@link withIdempotentCommit}: `replayed: false` carries the\n * fresh result of this execution; `replayed: true` carries the stored\n * outcome of the previous execution with the same key and fingerprint.\n * The replayed value is typed `R` on the strength of the fingerprint\n * match: the same command was executed, so the stored outcome has the\n * shape this command produces, provided the adapter round-trips plain\n * data faithfully.\n */\nexport interface IdempotentCommitResult<R> {\n\treadonly replayed: boolean;\n\treadonly result: R;\n}\n\n/** Claim identity visible to work that persists a source-of-truth marker. */\nexport interface IdempotentExecution extends IdempotentCommitRequest {\n\treadonly claimToken: string;\n}\n\nexport interface IdempotencyOperationErrorContext {\n\treadonly operation: \"abandon\" | \"confirm\" | \"renew\";\n\treadonly key: string;\n\treadonly token: string;\n}\n\nexport interface WithIdempotentCommitDeps<Evt extends AnyDomainEvent, TCtx>\n\textends WithCommitDeps<Evt, TCtx> {\n\tidempotency: IdempotencyStore<TCtx>;\n\t/**\n\t * Source-of-truth decision for an expired staged outcome. The callback must\n\t * return `committed` only when the command effect is durably visible, and\n\t * `not-committed` only when a durable marker proves the attempt cannot still\n\t * commit. `unknown` keeps the key blocked.\n\t */\n\treconcileIdempotency?: (\n\t\treconciliation: IdempotencyReconciliation,\n\t\tctx: TCtx,\n\t) => Promise<IdempotencyReconciliationDecision>;\n\t/**\n\t * Observer for best-effort post-commit confirm, rollback abandon, and a\n\t * secondary heartbeat failure masked by the primary work error.\n\t */\n\tonIdempotencyError?: (\n\t\terror: unknown,\n\t\tcontext: IdempotencyOperationErrorContext,\n\t) => void;\n}\n\ninterface LeaseHeartbeat {\n\tstop(): Promise<void>;\n\tfailure(): unknown | undefined;\n}\n\nfunction validRenewAfterMs(value: number): boolean {\n\treturn Number.isSafeInteger(value) && value > 0 && value <= 2_147_483_647;\n}\n\nfunction startLeaseHeartbeat<TCtx>(\n\tstore: IdempotencyStore<TCtx>,\n\tclaim: IdempotencyClaimHandle,\n): LeaseHeartbeat | undefined {\n\tif (!claim.lease) return undefined;\n\tlet stopped = false;\n\tlet timer: ReturnType<typeof setTimeout> | undefined;\n\tlet inFlight: Promise<void> = Promise.resolve();\n\tlet heartbeatFailure: unknown | undefined;\n\n\tconst schedule = (delayMs: number): void => {\n\t\tif (!validRenewAfterMs(delayMs)) {\n\t\t\theartbeatFailure = new TypeError(\n\t\t\t\t\"IdempotencyStore returned an invalid lease renewAfterMs; expected a positive safe integer no greater than 2147483647\",\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\t\ttimer = setTimeout(() => {\n\t\t\tinFlight = store\n\t\t\t\t.renew(claim)\n\t\t\t\t.then((lease) => {\n\t\t\t\t\tif (!lease) {\n\t\t\t\t\t\tthrow new TypeError(\n\t\t\t\t\t\t\t\"IdempotencyStore returned no lease while renewing a leased claim\",\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\tif (stopped) return;\n\t\t\t\t\tschedule(lease.renewAfterMs);\n\t\t\t\t})\n\t\t\t\t.catch((error: unknown) => {\n\t\t\t\t\theartbeatFailure = error;\n\t\t\t\t});\n\t\t}, delayMs);\n\t};\n\n\tschedule(claim.lease.renewAfterMs);\n\treturn {\n\t\tstop: async () => {\n\t\t\tstopped = true;\n\t\t\tif (timer !== undefined) clearTimeout(timer);\n\t\t\tawait inFlight;\n\t\t},\n\t\tfailure: () => heartbeatFailure,\n\t};\n}\n\nfunction scopeWorkEnrollment<Evt extends AnyDomainEvent>(\n\tparent: CommitEnrollment<Evt>,\n): { readonly enrollment: CommitEnrollment<Evt>; close(): void } {\n\tlet open = true;\n\tconst assertOpen = (): void => {\n\t\tif (!open) {\n\t\t\tthrow new EventHarvestError(\n\t\t\t\t\"withIdempotentCommit: commit enrollment was used after the \" +\n\t\t\t\t\t\"user work callback settled. Await every repository write before \" +\n\t\t\t\t\t\"returning from the callback.\",\n\t\t\t);\n\t\t}\n\t};\n\n\treturn {\n\t\tenrollment: Object.freeze({\n\t\t\tenrollSaved: (\n\t\t\t\taggregate: Parameters<CommitEnrollment<Evt>[\"enrollSaved\"]>[0],\n\t\t\t) => {\n\t\t\t\tassertOpen();\n\t\t\t\treturn parent.enrollSaved(aggregate);\n\t\t\t},\n\t\t\tenrollDeleted: (\n\t\t\t\taggregate: Parameters<CommitEnrollment<Evt>[\"enrollDeleted\"]>[0],\n\t\t\t) => {\n\t\t\t\tassertOpen();\n\t\t\t\treturn parent.enrollDeleted(aggregate);\n\t\t\t},\n\t\t}),\n\t\tclose: () => {\n\t\t\topen = false;\n\t\t},\n\t};\n}\n\n/**\n * {@link withCommit} with command idempotency: the duplicate-safe write\n * path for retryable deliveries (client retries, at-least-once\n * messages, scheduler re-runs).\n *\n * Order of operations:\n * 1. Inside the transaction, `store.claim(ctx, key, fingerprint)` runs\n * FIRST. A completed execution short-circuits without touching the domain.\n * An expired staged outcome invokes `reconcileIdempotency`; `committed`\n * replays it, `not-committed` releases and claims fresh, and `unknown` (or\n * no callback) throws `IdempotencyReconciliationRequiredError` without\n * changing the store.\n * 2. A fresh claim carries an opaque ownership token. For a leased store the\n * wrapper renews it at `renewAfterMs` until the transaction callback is\n * ready to commit. A renewal failure rejects before commit and releases\n * the claim. `fn(ctx, enrollment, execution)` receives the same token so a\n * source-side marker can make later reconciliation conclusive.\n * 3. `store.complete(ctx, claim, fn's result)` stages or completes the outcome\n * in the same transaction as aggregate writes and outbox. The enrollment\n * capability is sealed and its token array copied before `complete` can\n * yield, so leaked callback state cannot change the harvest receipt.\n * 4. After commit, `store.confirm(claim)` finalizes a leased store's staged\n * outcome; it is a no-op for transactional stores. A failure cannot reject\n * an already committed write, so it is sent to `onIdempotencyError` and the\n * record later enters reconciliation after lease expiry.\n * 5. Any pre-commit failure releases that exact token through\n * `store.abandon(claim)` before leaving the transactional region. A stale\n * abandon cannot release a successor. Secondary abandon/renew failures are\n * observable but never mask the primary error.\n *\n * Composes with `RetryingTransactionScope`: a retryable failure inside\n * one attempt releases that attempt's claim, and the retry either\n * executes fresh or, when a concurrent execution completed meanwhile,\n * replays its confirmed outcome. A concurrent duplicate while the first\n * execution is still running surfaces as `IdempotencyInFlightError`\n * (retryable); unwrapped, map it to a conflict/retry-later application\n * outcome.\n *\n * The stored outcome is `fn`'s `result` value; it must be plain, serialisable\n * data (see {@link IdempotencyStore}). Transactional storage remains the\n * production default. Leases make the non-transactional family recoverable;\n * they do not manufacture an atomic exactly-once boundary across two stores.\n */\nexport async function withIdempotentCommit<Evt extends AnyDomainEvent, R, TCtx>(\n\tdeps: WithIdempotentCommitDeps<Evt, TCtx>,\n\trequest: IdempotentCommitRequest,\n\tfn: (\n\t\tctx: TCtx,\n\t\tenrollment: CommitEnrollment<Evt>,\n\t\texecution: IdempotentExecution,\n\t) => Promise<WithCommitWorkResult<Evt, R>>,\n): Promise<IdempotentCommitResult<R>> {\n\tconst store = deps.idempotency;\n\tconst attempt: {\n\t\tclaim: IdempotencyClaimHandle | undefined;\n\t\theartbeat: LeaseHeartbeat | undefined;\n\t} = { claim: undefined, heartbeat: undefined };\n\n\t// Decorator around the caller's scope: releases the current\n\t// attempt's claim before an error leaves the transactional region.\n\t// This is the only place that sees EVERY failure point of one\n\t// attempt (the work, withCommit's harvest guards, the outbox write),\n\t// including the ones outside this module's own callback, and it runs\n\t// INSIDE a retrying scope's loop, so the next attempt starts clean.\n\tconst scope: TransactionScope<TCtx> = {\n\t\ttransactional: async (work, options) => {\n\t\t\ttry {\n\t\t\t\treturn await deps.scope.transactional(async (ctx) => {\n\t\t\t\tattempt.claim = undefined;\n\t\t\t\tattempt.heartbeat = undefined;\n\t\t\t\ttry {\n\t\t\t\t\tconst result = await work(ctx);\n\t\t\t\t\tconst currentHeartbeat = attempt.heartbeat as\n\t\t\t\t\t\t| LeaseHeartbeat\n\t\t\t\t\t\t| undefined;\n\t\t\t\t\tawait currentHeartbeat?.stop();\n\t\t\t\t\tconst heartbeatFailure = currentHeartbeat?.failure();\n\t\t\t\t\tif (heartbeatFailure !== undefined) throw heartbeatFailure;\n\t\t\t\t\treturn result;\n\t\t\t\t} catch (error) {\n\t\t\t\t\tconst currentHeartbeat = attempt.heartbeat as\n\t\t\t\t\t\t| LeaseHeartbeat\n\t\t\t\t\t\t| undefined;\n\t\t\t\t\tawait currentHeartbeat?.stop();\n\t\t\t\t\tconst heartbeatFailure = currentHeartbeat?.failure();\n\t\t\t\t\tconst currentClaim = attempt.claim as\n\t\t\t\t\t\t| IdempotencyClaimHandle\n\t\t\t\t\t\t| undefined;\n\t\t\t\t\tif (\n\t\t\t\t\t\theartbeatFailure !== undefined &&\n\t\t\t\t\t\theartbeatFailure !== error &&\n\t\t\t\t\t\tcurrentClaim\n\t\t\t\t\t) {\n\t\t\t\t\t\treportToObserver(() =>\n\t\t\t\t\t\t\tdeps.onIdempotencyError?.(heartbeatFailure, {\n\t\t\t\t\t\t\t\toperation: \"renew\",\n\t\t\t\t\t\t\t\tkey: currentClaim.key,\n\t\t\t\t\t\t\t\ttoken: currentClaim.token,\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\tconst abandoned = attempt.claim as IdempotencyClaimHandle | undefined;\n\t\t\t\t\tif (abandoned) {\n\t\t\t\t\t\tattempt.claim = undefined;\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tawait store.abandon(abandoned);\n\t\t\t\t\t\t} catch (abandonError) {\n\t\t\t\t\t\t\t// Best-effort release: the abandon failure must not\n\t\t\t\t\t\t\t// mask the attempt's error. Transactional stores\n\t\t\t\t\t\t\t// release via rollback anyway; a leased store can\n\t\t\t\t\t\t\t// recover after expiry. The observer keeps the\n\t\t\t\t\t\t\t// secondary operational failure visible.\n\t\t\t\t\t\t\treportToObserver(() =>\n\t\t\t\t\t\t\t\tdeps.onIdempotencyError?.(abandonError, {\n\t\t\t\t\t\t\t\t\toperation: \"abandon\",\n\t\t\t\t\t\t\t\t\tkey: abandoned.key,\n\t\t\t\t\t\t\t\t\ttoken: abandoned.token,\n\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t}, options);\n\t\t\t} catch (error) {\n\t\t\t\t// COMMIT-time failure: the driver rejected AFTER the callback\n\t\t\t\t// resolved, so the catch above never saw it and the staged\n\t\t\t\t// claim would stay wedged until lease expiry (and demand\n\t\t\t\t// reconciliation after). The store contract declares abandon\n\t\t\t\t// safe when the commit outcome is unknown: a transactional\n\t\t\t\t// store's claim died with the rollback anyway, and a leased\n\t\t\t\t// store releases the lease while the durable outcome record\n\t\t\t\t// still decides replay on the next attempt.\n\t\t\t\tconst staged = attempt.claim as IdempotencyClaimHandle | undefined;\n\t\t\t\tif (staged) {\n\t\t\t\t\tattempt.claim = undefined;\n\t\t\t\t\tattempt.heartbeat = undefined;\n\t\t\t\t\ttry {\n\t\t\t\t\t\tawait store.abandon(staged);\n\t\t\t\t\t} catch (abandonError) {\n\t\t\t\t\t\treportToObserver(() =>\n\t\t\t\t\t\t\tdeps.onIdempotencyError?.(abandonError, {\n\t\t\t\t\t\t\t\toperation: \"abandon\",\n\t\t\t\t\t\t\t\tkey: staged.key,\n\t\t\t\t\t\t\t\ttoken: staged.token,\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t},\n\t};\n\n\tconst outcome = await withCommit<Evt, IdempotentCommitResult<R>, TCtx>(\n\t\t{ ...deps, scope },\n\t\tasync (ctx, enrollment) => {\n\t\t\tlet claim = await store.claim(ctx, request.key, request.fingerprint);\n\t\t\tif (claim.status === \"reconciliation-required\") {\n\t\t\t\tconst decision = deps.reconcileIdempotency\n\t\t\t\t\t? await deps.reconcileIdempotency(claim.reconciliation, ctx)\n\t\t\t\t\t: \"unknown\";\n\t\t\t\tif (decision === \"unknown\") {\n\t\t\t\t\tthrow new IdempotencyReconciliationRequiredError(\n\t\t\t\t\t\tclaim.reconciliation,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tif (decision !== \"committed\" && decision !== \"not-committed\") {\n\t\t\t\t\tthrow new TypeError(\n\t\t\t\t\t\t\"reconcileIdempotency must return committed, not-committed, or unknown\",\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tawait store.reconcile(claim.reconciliation, decision);\n\t\t\t\tclaim = await store.claim(ctx, request.key, request.fingerprint);\n\t\t\t\tif (claim.status === \"reconciliation-required\") {\n\t\t\t\t\tthrow new IdempotencyReconciliationRequiredError(\n\t\t\t\t\t\tclaim.reconciliation,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (claim.status === \"completed\") {\n\t\t\t\treturn {\n\t\t\t\t\tresult: { replayed: true, result: claim.outcome as R },\n\t\t\t\t\tcommits: [],\n\t\t\t\t};\n\t\t\t}\n\t\t\tattempt.claim = claim.claim;\n\t\t\tattempt.heartbeat = startLeaseHeartbeat(store, claim.claim);\n\t\t\tconst workEnrollment = scopeWorkEnrollment(enrollment);\n\t\t\tlet work: WithCommitWorkResult<Evt, R>;\n\t\t\ttry {\n\t\t\t\twork = await fn(ctx, workEnrollment.enrollment, {\n\t\t\t\t\tkey: request.key,\n\t\t\t\t\tfingerprint: request.fingerprint,\n\t\t\t\t\tclaimToken: claim.claim.token,\n\t\t\t\t});\n\t\t\t} finally {\n\t\t\t\tworkEnrollment.close();\n\t\t\t}\n\t\t\t// Snapshot the user-controlled receipt before complete() yields. A\n\t\t\t// leaked mutable array must not be able to add or remove aggregate\n\t\t\t// commits while the idempotency adapter is persisting the outcome.\n\t\t\tconst result = work.result;\n\t\t\tconst commits = Array.isArray(work.commits)\n\t\t\t\t? Object.freeze([...work.commits])\n\t\t\t\t: work.commits;\n\t\t\tawait store.complete(ctx, claim.claim, result);\n\t\t\treturn {\n\t\t\t\tresult: { replayed: false, result },\n\t\t\t\tcommits,\n\t\t\t};\n\t\t},\n\t);\n\n\tif (!outcome.replayed) {\n\t\t// Post-commit finalize: flips a leased store's staged\n\t\t// outcome to confirmed so only committed outcomes ever replay.\n\t\t// No-op for transactional stores. Runs after the commit, so a\n\t\t// throw here must not reject the committed write. The staged record\n\t\t// remains in-flight until lease expiry and then requires an\n\t\t// authoritative reconciliation decision.\n\t\tconst committedClaim = attempt.claim as IdempotencyClaimHandle | undefined;\n\t\tif (!committedClaim) {\n\t\t\tthrow new EventHarvestError(\n\t\t\t\t\"withIdempotentCommit: a fresh result committed without its claim receipt.\",\n\t\t\t);\n\t\t}\n\t\ttry {\n\t\t\tawait store.confirm(committedClaim);\n\t\t} catch (confirmError) {\n\t\t\t// Swallowed by the post-commit invariant: the write has committed.\n\t\t\t// Report it so the staged record enters the reconciliation path\n\t\t\t// visibly instead of becoming a silent permanent blockage.\n\t\t\treportToObserver(() =>\n\t\t\t\tdeps.onIdempotencyError?.(confirmError, {\n\t\t\t\t\toperation: \"confirm\",\n\t\t\t\t\tkey: committedClaim.key,\n\t\t\t\t\ttoken: committedClaim.token,\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\t}\n\treturn outcome;\n}\n","import {\n\tIdempotencyClaimLostError,\n\tIdempotencyCompletionWithoutClaimError,\n\tIdempotencyInFlightError,\n\tIdempotencyKeyReuseError,\n\tInMemoryCapacityExceededError,\n} from \"../core/errors\";\nimport { assertPositiveSafeInteger } from \"../utils/validate\";\nimport type {\n\tIdempotencyClaim,\n\tIdempotencyClaimHandle,\n\tIdempotencyLease,\n\tIdempotencyReconciliation,\n\tIdempotencyReconciliationDecision,\n\tIdempotencyStore,\n} from \"./idempotency\";\n\ninterface PendingEntry {\n\treadonly fingerprint: string;\n\treadonly status: \"pending\";\n\treadonly token: string;\n\treadonly expiresAtMs: number;\n}\n\ninterface StagedEntry {\n\treadonly fingerprint: string;\n\treadonly status: \"staged\";\n\treadonly token: string;\n\treadonly expiresAtMs: number;\n\treadonly outcome: unknown;\n}\n\ninterface ConfirmedEntry {\n\treadonly fingerprint: string;\n\treadonly status: \"confirmed\";\n\treadonly token: string;\n\treadonly outcome: unknown;\n}\n\ntype IdempotencyEntry = PendingEntry | StagedEntry | ConfirmedEntry;\n\nexport interface InMemoryIdempotencyStoreOptions {\n\t/** Store-local clock. Durable adapters should prefer server/database time. */\n\treadonly clock?: () => Date;\n\t/** Token component source; an internal generation keeps ownership unique. */\n\treadonly claimTokenFactory?: () => string;\n\t/** Lease lifetime for pending and staged records. Default: 30 seconds. */\n\treadonly leaseDurationMs?: number;\n\t/** Heartbeat delay advertised to the wrapper. Default: half the lease. */\n\treadonly renewAfterMs?: number;\n\t/** Maximum number of pending, staged, and confirmed records. */\n\treadonly maxEntries?: number;\n}\n\nconst DEFAULT_LEASE_DURATION_MS = 30_000;\n\nfunction positiveSafeInteger(value: number): boolean {\n\treturn Number.isSafeInteger(value) && value > 0;\n}\n\n/**\n * In-memory reference implementation of {@link IdempotencyStore} for\n * finite-lifetime tests and demos. Without `maxEntries`, every confirmed\n * receipt remains reachable for the lifetime of the instance. A long-lived\n * process must configure the limit or use a durable adapter; exhaustion\n * rejects new keys before mutation and never forgets an idempotency decision.\n *\n * It is deliberately not transaction-aware. Claims and staged outcomes carry\n * bounded leases, while every mutation compares the store-minted token. An\n * expired pending claim may be replaced; an expired staged outcome cannot be\n * guessed away and instead returns `reconciliation-required`. Only an\n * authoritative `committed` / `not-committed` decision can settle it.\n */\nexport class InMemoryIdempotencyStore<TCtx = unknown>\n\timplements IdempotencyStore<TCtx>\n{\n\tprivate readonly entries = new Map<string, IdempotencyEntry>();\n\tprivate readonly clock: () => Date;\n\tprivate readonly claimTokenFactory: () => string;\n\tprivate readonly leaseDurationMs: number;\n\tprivate readonly renewAfterMs: number;\n\tprivate readonly maxEntries: number | undefined;\n\tprivate tokenGeneration = 0;\n\n\tconstructor(options: InMemoryIdempotencyStoreOptions = {}) {\n\t\tthis.clock = options.clock ?? (() => new Date());\n\t\tthis.claimTokenFactory =\n\t\t\toptions.claimTokenFactory ?? (() => globalThis.crypto.randomUUID());\n\t\tthis.leaseDurationMs = options.leaseDurationMs ?? DEFAULT_LEASE_DURATION_MS;\n\t\tthis.renewAfterMs =\n\t\t\toptions.renewAfterMs ?? Math.floor(this.leaseDurationMs / 2);\n\t\tif (options.maxEntries !== undefined) {\n\t\t\tassertPositiveSafeInteger(\n\t\t\t\t\"InMemoryIdempotencyStore\",\n\t\t\t\t\"maxEntries\",\n\t\t\t\toptions.maxEntries,\n\t\t\t);\n\t\t}\n\t\tthis.maxEntries = options.maxEntries;\n\t\tif (\n\t\t\t!positiveSafeInteger(this.leaseDurationMs) ||\n\t\t\tthis.leaseDurationMs > 2_147_483_647\n\t\t) {\n\t\t\tthrow new RangeError(\n\t\t\t\t\"leaseDurationMs must be a positive safe integer no greater than 2147483647\",\n\t\t\t);\n\t\t}\n\t\tif (\n\t\t\t!positiveSafeInteger(this.renewAfterMs) ||\n\t\t\tthis.renewAfterMs >= this.leaseDurationMs ||\n\t\t\tthis.renewAfterMs > 2_147_483_647\n\t\t) {\n\t\t\tthrow new RangeError(\n\t\t\t\t\"renewAfterMs must be a positive safe integer below leaseDurationMs and no greater than 2147483647\",\n\t\t\t);\n\t\t}\n\t}\n\n\tasync claim(\n\t\t_ctx: TCtx,\n\t\tkey: string,\n\t\tfingerprint: string,\n\t): Promise<IdempotencyClaim> {\n\t\tconst now = this.nowMs();\n\t\tconst existing = this.entries.get(key);\n\t\tif (existing === undefined) {\n\t\t\tif (\n\t\t\t\tthis.maxEntries !== undefined &&\n\t\t\t\tthis.entries.size >= this.maxEntries\n\t\t\t) {\n\t\t\t\tthrow new InMemoryCapacityExceededError({\n\t\t\t\t\tstore: \"InMemoryIdempotencyStore\",\n\t\t\t\t\tresource: \"entries\",\n\t\t\t\t\tlimit: this.maxEntries,\n\t\t\t\t\tcurrent: this.entries.size,\n\t\t\t\t\tattempted: 1,\n\t\t\t\t});\n\t\t\t}\n\t\t\treturn this.createPending(key, fingerprint, now);\n\t\t}\n\t\tif (existing.fingerprint !== fingerprint) {\n\t\t\tthrow new IdempotencyKeyReuseError({\n\t\t\t\tkey,\n\t\t\t\tstoredFingerprint: existing.fingerprint,\n\t\t\t\treceivedFingerprint: fingerprint,\n\t\t\t});\n\t\t}\n\t\tif (existing.status === \"confirmed\") {\n\t\t\treturn {\n\t\t\t\tstatus: \"completed\",\n\t\t\t\toutcome: structuredClone(existing.outcome),\n\t\t\t};\n\t\t}\n\t\tif (now < existing.expiresAtMs) {\n\t\t\tthrow new IdempotencyInFlightError({ key });\n\t\t}\n\t\tif (existing.status === \"staged\") {\n\t\t\treturn {\n\t\t\t\tstatus: \"reconciliation-required\",\n\t\t\t\treconciliation: Object.freeze({\n\t\t\t\t\tkey,\n\t\t\t\t\tfingerprint,\n\t\t\t\t\ttoken: existing.token,\n\t\t\t\t\texpiredAt: new Date(existing.expiresAtMs).toISOString(),\n\t\t\t\t}),\n\t\t\t};\n\t\t}\n\t\treturn this.createPending(key, fingerprint, now);\n\t}\n\n\tasync complete(\n\t\t_ctx: TCtx,\n\t\tclaim: IdempotencyClaimHandle,\n\t\toutcome: unknown,\n\t): Promise<void> {\n\t\tconst now = this.nowMs();\n\t\tconst existing = this.entries.get(claim.key);\n\t\tif (existing === undefined) {\n\t\t\tthrow new IdempotencyCompletionWithoutClaimError(claim.key);\n\t\t}\n\t\tif (\n\t\t\texisting.status !== \"pending\" ||\n\t\t\texisting.token !== claim.token ||\n\t\t\tnow >= existing.expiresAtMs\n\t\t) {\n\t\t\tthrow this.claimLost(claim);\n\t\t}\n\t\tconst expiresAtMs = now + this.leaseDurationMs;\n\t\tthis.lease(expiresAtMs);\n\t\tthis.entries.set(claim.key, {\n\t\t\tfingerprint: existing.fingerprint,\n\t\t\tstatus: \"staged\",\n\t\t\ttoken: existing.token,\n\t\t\texpiresAtMs,\n\t\t\toutcome: structuredClone(outcome),\n\t\t});\n\t}\n\n\tasync renew(\n\t\tclaim: IdempotencyClaimHandle,\n\t): Promise<IdempotencyLease | undefined> {\n\t\tconst now = this.nowMs();\n\t\tconst existing = this.entries.get(claim.key);\n\t\tif (\n\t\t\texisting === undefined ||\n\t\t\texisting.status === \"confirmed\" ||\n\t\t\texisting.token !== claim.token ||\n\t\t\tnow >= existing.expiresAtMs\n\t\t) {\n\t\t\tthrow this.claimLost(claim);\n\t\t}\n\t\tconst expiresAtMs = now + this.leaseDurationMs;\n\t\tconst lease = this.lease(expiresAtMs);\n\t\tthis.entries.set(claim.key, { ...existing, expiresAtMs });\n\t\treturn lease;\n\t}\n\n\tasync confirm(claim: IdempotencyClaimHandle): Promise<void> {\n\t\tconst existing = this.entries.get(claim.key);\n\t\tif (existing?.status === \"staged\" && existing.token === claim.token) {\n\t\t\tthis.entries.set(claim.key, {\n\t\t\t\tfingerprint: existing.fingerprint,\n\t\t\t\tstatus: \"confirmed\",\n\t\t\t\ttoken: existing.token,\n\t\t\t\toutcome: existing.outcome,\n\t\t\t});\n\t\t}\n\t}\n\n\tasync abandon(claim: IdempotencyClaimHandle): Promise<void> {\n\t\tconst existing = this.entries.get(claim.key);\n\t\tif (\n\t\t\texisting !== undefined &&\n\t\t\texisting.status !== \"confirmed\" &&\n\t\t\texisting.token === claim.token\n\t\t) {\n\t\t\tthis.entries.delete(claim.key);\n\t\t}\n\t}\n\n\tasync reconcile(\n\t\treconciliation: IdempotencyReconciliation,\n\t\tdecision: Exclude<IdempotencyReconciliationDecision, \"unknown\">,\n\t): Promise<void> {\n\t\tif (decision !== \"committed\" && decision !== \"not-committed\") {\n\t\t\tthrow new TypeError(\n\t\t\t\t\"reconcile decision must be committed or not-committed; uncertainty must leave the record untouched\",\n\t\t\t);\n\t\t}\n\t\tconst existing = this.entries.get(reconciliation.key);\n\t\tif (\n\t\t\texisting === undefined ||\n\t\t\texisting.status !== \"staged\" ||\n\t\t\texisting.token !== reconciliation.token ||\n\t\t\texisting.fingerprint !== reconciliation.fingerprint ||\n\t\t\tnew Date(existing.expiresAtMs).toISOString() !==\n\t\t\t\treconciliation.expiredAt ||\n\t\t\tthis.nowMs() < existing.expiresAtMs\n\t\t) {\n\t\t\tthrow new IdempotencyClaimLostError({\n\t\t\t\tkey: reconciliation.key,\n\t\t\t\ttoken: reconciliation.token,\n\t\t\t});\n\t\t}\n\t\tif (decision === \"committed\") {\n\t\t\tthis.entries.set(reconciliation.key, {\n\t\t\t\tfingerprint: existing.fingerprint,\n\t\t\t\tstatus: \"confirmed\",\n\t\t\t\ttoken: existing.token,\n\t\t\t\toutcome: existing.outcome,\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\t\tthis.entries.delete(reconciliation.key);\n\t}\n\n\t/** Test hook: number of stored records in any state. */\n\tget size(): number {\n\t\treturn this.entries.size;\n\t}\n\n\t/** Test hook: drops every record. */\n\tclear(): void {\n\t\tthis.entries.clear();\n\t}\n\n\tprivate createPending(\n\t\tkey: string,\n\t\tfingerprint: string,\n\t\tnow: number,\n\t): IdempotencyClaim {\n\t\tconst tokenPart = this.claimTokenFactory();\n\t\tif (typeof tokenPart !== \"string\" || tokenPart.length === 0) {\n\t\t\tthrow new TypeError(\"claimTokenFactory must return a non-empty string\");\n\t\t}\n\t\tthis.tokenGeneration += 1;\n\t\tif (!Number.isSafeInteger(this.tokenGeneration)) {\n\t\t\tthrow new RangeError(\"idempotency claim-token generation exhausted\");\n\t\t}\n\t\tconst token = `${this.tokenGeneration}:${tokenPart}`;\n\t\tconst expiresAtMs = now + this.leaseDurationMs;\n\t\tconst lease = this.lease(expiresAtMs);\n\t\tthis.entries.set(key, {\n\t\t\tfingerprint,\n\t\t\tstatus: \"pending\",\n\t\t\ttoken,\n\t\t\texpiresAtMs,\n\t\t});\n\t\treturn {\n\t\t\tstatus: \"claimed\",\n\t\t\tclaim: Object.freeze({ key, token, lease }),\n\t\t};\n\t}\n\n\tprivate lease(expiresAtMs: number): IdempotencyLease {\n\t\treturn Object.freeze({\n\t\t\texpiresAt: new Date(expiresAtMs).toISOString(),\n\t\t\trenewAfterMs: this.renewAfterMs,\n\t\t});\n\t}\n\n\tprivate nowMs(): number {\n\t\tconst now = this.clock();\n\t\tconst value = now instanceof Date ? now.getTime() : Number.NaN;\n\t\tif (!Number.isFinite(value)) {\n\t\t\tthrow new TypeError(\"idempotency clock must return a valid Date\");\n\t\t}\n\t\treturn value;\n\t}\n\n\tprivate claimLost(claim: IdempotencyClaimHandle): IdempotencyClaimLostError {\n\t\treturn new IdempotencyClaimLostError({\n\t\t\tkey: claim.key,\n\t\t\ttoken: claim.token,\n\t\t});\n\t}\n}\n","import { ok, type Result } from \"@shirudo/result\";\nimport {\n\ttype ExpectedErrorMapper,\n\thandlerOrThrow,\n\tmapHandlerFailure,\n\tregisterOnce,\n\ttype UntypedMapDispatch,\n} from \"./bus-internals\";\nimport type { Query, QueryHandler } from \"./query\";\n\n/**\n * Internal adapter shape for handlers stored in the map.\n *\n * Registered handlers are typed as `QueryHandler<Q, TMap[K]>` (narrower\n * input, specific return) and cannot be stored directly in a heterogeneous\n * map (function-parameter contravariance). The closure in `register`\n * downcasts `Query` to the handler's expected `Q` based on the\n * dispatch-key invariant (we only call this entry when `query.type` matches\n * the key it was registered under). Result is widened to `unknown` here\n * and narrowed back via the public overloads on `execute` / `executeUnsafe`.\n */\ntype StoredQueryHandler = (query: Query) => Promise<unknown>;\n\n/**\n * Type map for query types to their return types.\n * Used to improve type inference in QueryBus.\n *\n * @example\n * ```typescript\n * type MyQueryMap = {\n * GetOrder: Order | null;\n * ListOrders: Order[];\n * };\n *\n * const bus = new QueryBus<MyQueryMap>();\n * const result = await bus.execute({ type: \"GetOrder\", orderId: \"123\" });\n * // result: Result<Order | null, string> ← automatically inferred\n * ```\n */\ntype QueryTypeMap = Record<string, unknown>;\n\n/**\n * Construction options for {@link QueryBus}.\n *\n * @template E - The error channel type of the bus.\n */\nexport interface QueryBusOptions<E = string> {\n\t/**\n\t * Explicitly recognizes an expected handler failure and maps it into the\n\t * bus's error channel. Return `{ error }` only for failures this boundary\n\t * owns; return `undefined` to rethrow the exact original value. With no\n\t * mapper, every handler throw propagates. Unregistered-handler and nested\n\t * bus wiring errors always propagate.\n\t */\n\tmapExpectedError?: (thrown: unknown) => { readonly error: E } | undefined;\n}\n\n/**\n * Query Bus interface for dispatching queries to their handlers.\n * Provides a centralized way to execute queries with handler registration.\n *\n * Supports an optional type map (`TMap`) for automatic return type inference.\n * Without a type map, the return type must be specified manually or defaults to `unknown`.\n * With a concrete result map, its entry is the only result type for that\n * query; the loose explicit-result overloads are unavailable.\n *\n * @template TMap - Optional mapping from query type strings to return types\n *\n * @example\n * ```typescript\n * // With a type map (recommended): the return type is inferred\n * type MyQueries = { GetOrder: Order | null; ListOrders: Order[] };\n * const bus = new QueryBus<MyQueries>();\n * const result = await bus.execute({ type: \"GetOrder\", orderId: \"123\" });\n * // result: Result<Order | null, string>\n *\n * // Without a type map: the return type defaults to `unknown`\n * const bus = new QueryBus();\n * const result = await bus.execute({ type: \"GetOrder\", orderId: \"123\" });\n * // result: Result<unknown, string>\n * ```\n */\nexport interface IQueryBus<\n\tTMap extends QueryTypeMap = QueryTypeMap,\n\tE = string,\n> {\n\t/**\n\t * Executes a query by dispatching it to the registered handler.\n\t * When a type map is provided, the return type is inferred from the query type.\n\t *\n\t * @param query - The query to execute\n\t * @returns Result containing the query result if successful, or an error of type `E`\n\t * @throws UnregisteredHandlerError when no handler is registered for\n\t * `query.type` (a wiring bug; never delivered through the channel)\n\t * @throws The exact handler failure when `mapExpectedError` is absent or\n\t * returns `undefined`\n\t * @throws ErrorMapperFailedError when `mapExpectedError` fails\n\t */\n\texecute<Q extends Query & { type: keyof TMap & string }>(\n\t\tquery: Q,\n\t): Promise<Result<TMap[Q[\"type\"]], E>>;\n\t// Manual result typing belongs only to the default untyped map shape.\n\texecute<Q extends Query, R>(\n\t\tquery: UntypedMapDispatch<TMap, Q>,\n\t): Promise<Result<R, E>>;\n\n\t/**\n\t * Executes a query by dispatching it to the registered handler.\n\t * Throws an error if no handler is registered.\n\t *\n\t * @param query - The query to execute\n\t * @returns The query result\n\t * @throws The exact handler failure or UnregisteredHandlerError\n\t */\n\texecuteUnsafe<Q extends Query & { type: keyof TMap & string }>(\n\t\tquery: Q,\n\t): Promise<TMap[Q[\"type\"]]>;\n\texecuteUnsafe<Q extends Query, R>(\n\t\tquery: UntypedMapDispatch<TMap, Q>,\n\t): Promise<R>;\n\n\t/**\n\t * Registers a handler for a specific query type.\n\t *\n\t * When `TMap` is supplied, the `queryType` argument is restricted to its\n\t * keys and the handler signature is forced to match `TMap[K]` for the\n\t * return value: typos and wrong-typed handlers are compile errors.\n\t * Without `TMap` the registration is loose (any string key, any return\n\t * type) so the no-config path keeps working.\n\t *\n\t * @param queryType - The query type to register the handler for\n\t * @param handler - The handler function for this query type\n\t */\n\tregister<\n\t\tK extends keyof TMap & string,\n\t\tQ extends Query & { type: K } = Query & { type: K },\n\t>(queryType: K, handler: QueryHandler<Q, TMap[K]>): void;\n}\n\n/**\n * Simple in-memory query bus implementation.\n * Handlers are stored in a Map and dispatched based on query type.\n *\n * Supports an optional type map (`TMap`) for automatic return type inference.\n * When `TMap` is concrete, `execute()` and `executeUnsafe()` infer the result type from the query type.\n * Explicit competing result generics cannot override that map.\n * Without `TMap`, the return type defaults to `unknown` or is specified per call.\n *\n * **Note:** This is a basic implementation suitable for development and simple use cases.\n * For production environments, consider implementing or using a more feature-rich bus that includes:\n * - Middleware/Pipeline support (logging, caching, rate limiting)\n * - Error handling\n * - Timeout handling\n * - Metrics and observability\n * - Query result caching\n * - Rate limiting\n *\n * The `QueryHandler` type can still be used with external production-grade buses\n * (e.g., RabbitMQ, AWS SQS) while maintaining type safety.\n *\n * @template TMap - Optional mapping from query type strings to return types\n *\n * @example\n * ```typescript\n * // With a type map: full inference\n * type Queries = { GetOrder: Order | null; ListOrders: Order[] };\n * const bus = new QueryBus<Queries>();\n * const result = await bus.execute({ type: \"GetOrder\", orderId: \"123\" });\n * // result: Result<Order | null, string>\n *\n * // Without a type map: specify the return type per call\n * const bus = new QueryBus();\n * bus.register(\"GetOrder\", async (query) => repository.findById(query.orderId));\n * const result = await bus.execute({ type: \"GetOrder\", orderId: \"123\" });\n * ```\n */\nexport class QueryBus<TMap extends QueryTypeMap = QueryTypeMap, E = string>\n\timplements IQueryBus<TMap, E>\n{\n\tprivate readonly handlers = new Map<string, StoredQueryHandler>();\n\tprivate readonly mapExpectedError: ExpectedErrorMapper<E> | undefined;\n\n\tconstructor(options?: QueryBusOptions<E>) {\n\t\tthis.mapExpectedError = options?.mapExpectedError;\n\t}\n\n\tregister<\n\t\tK extends keyof TMap & string,\n\t\tQ extends Query & { type: K } = Query & { type: K },\n\t>(queryType: K, handler: QueryHandler<Q, TMap[K]>): void {\n\t\tregisterOnce(this.handlers, \"query\", queryType, (query: Query) =>\n\t\t\thandler(query as Q),\n\t\t);\n\t}\n\n\tasync execute<Q extends Query & { type: keyof TMap & string }>(\n\t\tquery: Q,\n\t): Promise<Result<TMap[Q[\"type\"]], E>>;\n\t// Keep the class surface identical to IQueryBus's untyped fallback.\n\tasync execute<Q extends Query, R>(\n\t\tquery: UntypedMapDispatch<TMap, Q>,\n\t): Promise<Result<R, E>>;\n\tasync execute<Q extends Query, R>(query: Q): Promise<Result<R, E>> {\n\t\tconst handler = handlerOrThrow(this.handlers, \"query\", query.type);\n\t\ttry {\n\t\t\tconst result = (await handler(query)) as R;\n\t\t\treturn ok(result);\n\t\t} catch (error) {\n\t\t\treturn mapHandlerFailure(error, this.mapExpectedError, \"query\");\n\t\t}\n\t}\n\n\tasync executeUnsafe<Q extends Query & { type: keyof TMap & string }>(\n\t\tquery: Q,\n\t): Promise<TMap[Q[\"type\"]]>;\n\tasync executeUnsafe<Q extends Query, R>(\n\t\tquery: UntypedMapDispatch<TMap, Q>,\n\t): Promise<R>;\n\tasync executeUnsafe<Q extends Query, R>(query: Q): Promise<R> {\n\t\t// Same no-handler gate as execute: one implementation so the two\n\t\t// paths cannot drift.\n\t\tconst handler = handlerOrThrow(this.handlers, \"query\", query.type);\n\t\treturn (await handler(query)) as R;\n\t}\n}\n","import type { IAggregateRoot } from \"../aggregate/aggregate\";\nimport type {\n\tAnyDomainEvent,\n\tDomainEventFactory,\n\tDomainEventStamp,\n\tUncommittedDomainEventOf,\n} from \"../aggregate/domain-event\";\nimport { pendingEventRecordingCapabilityFor } from \"../aggregate/pending-event-recording\";\nimport type { Id } from \"../core/id\";\n\n/** Minimal shell role accepted by {@link recordPendingEvents}. */\nexport type DomainEventStampFactory = Pick<DomainEventFactory, \"createStamp\">;\n\n/** Per-decision stamp provider for metadata that depends on the event. */\nexport type DomainEventStampProvider<TEvent extends AnyDomainEvent> = (\n\tevent: UncommittedDomainEventOf<TEvent>,\n\tindex: number,\n) => DomainEventStamp;\n\n/**\n * Records every still-unstamped event accepted by an aggregate.\n *\n * Recording is atomic with respect to the aggregate's pending list: if stamp\n * creation or validation fails, every decision remains unrecorded. A\n * successful second call returns the same event objects and does not read the\n * factory again, which keeps event identity stable across transaction retries.\n *\n * Pass a `DomainEventFactory` (only its `createStamp` role is required) for one\n * uniform recording policy, or a callback when metadata depends on the\n * concrete decision.\n */\nexport function recordPendingEvents<\n\tTId extends Id<string>,\n\tTEvent extends AnyDomainEvent,\n>(\n\taggregate: IAggregateRoot<TId, TEvent>,\n\tfactory: DomainEventStampFactory,\n): ReadonlyArray<TEvent>;\nexport function recordPendingEvents<\n\tTId extends Id<string>,\n\tTEvent extends AnyDomainEvent,\n>(\n\taggregate: IAggregateRoot<TId, TEvent>,\n\tcreateStamp: DomainEventStampProvider<TEvent>,\n): ReadonlyArray<TEvent>;\nexport function recordPendingEvents<\n\tTId extends Id<string>,\n\tTEvent extends AnyDomainEvent,\n>(\n\taggregate: IAggregateRoot<TId, TEvent>,\n\tsource: DomainEventStampFactory | DomainEventStampProvider<TEvent>,\n): ReadonlyArray<TEvent> {\n\tconst capability = pendingEventRecordingCapabilityFor(aggregate);\n\tif (!capability) {\n\t\tthrow new TypeError(\n\t\t\t\"recordPendingEvents requires an aggregate created by this package\",\n\t\t);\n\t}\n\tconst createStamp: DomainEventStampProvider<TEvent> =\n\t\ttypeof source === \"function\" ? source : () => source.createStamp();\n\treturn capability.record((event, index) =>\n\t\tcreateStamp(event as UncommittedDomainEventOf<TEvent>, index),\n\t) as ReadonlyArray<TEvent>;\n}\n","import { pendingEventLifecycleCapabilityFor } from \"../aggregate/pending-event-lifecycle\";\nimport { AggregateDeletedError } from \"../core/errors\";\nimport type { Id } from \"../core/id\";\n\n/**\n * A class reference used as the type key of the identity map. Keying\n * on the CLASS (not a name string) makes collisions impossible by\n * construction: `Restaurant` and `Booking` are different keys even if\n * someone names two aggregates identically across modules, and there\n * is no string-discipline to maintain.\n *\n * The `Function & { prototype: TAgg }` branch is load-bearing: the\n * kit's aggregate convention is a **protected constructor** plus\n * static factories, and TypeScript rejects assigning a class with a\n * protected constructor to a construct-signature type. The prototype\n * witness accepts those classes while still inferring `TAgg`.\n */\nexport type AggregateClass<TAgg> =\n\t| (abstract new (\n\t\t\t// biome-ignore lint/suspicious/noExplicitAny: variance; a class reference is only used as a map key and instance witness here.\n\t\t\t...args: any[]\n\t ) => TAgg)\n\t// biome-ignore lint/complexity/noBannedTypes: Function is deliberate; a construct signature cannot accept protected-constructor classes (the kit's aggregate convention); the prototype witness keeps TAgg inference.\n\t| (Function & { prototype: TAgg });\n\n/**\n * Per-unit-of-work Identity Map (Fowler, PoEAA): within one operation,\n * one aggregate type+id maps to exactly ONE in-memory instance.\n *\n * This is the shipped implementation of the contract the\n * [Repository guide](../../docs/guide/repository.md) places on\n * `AggregatePersistence` implementations: two `findById(id)` calls in the same\n * unit of work MUST return the same instance, because commit-token\n * write registration dedupes by JavaScript object identity. Two instances for\n * one logical aggregate can otherwise produce two tokens, two harvests,\n * and two post-commit lifecycle calls.\n *\n * Storage is two-level (per-type stores created lazily), so\n * `Restaurant:123` and `Booking:123` can never collide: the type key\n * is the aggregate CLASS, not the id alone and not a name string.\n *\n * Repository read-path contract:\n *\n * ```ts\n * async findById(id: OrderId): Promise<Order | undefined> {\n * const cached = this.tracking.identityMap.get(Order, id);\n * if (cached) return cached;\n * // Deleted in this unit of work = gone, even if the physical\n * // delete is deferred and the row is still visible in the tx.\n * if (this.tracking.identityMap.isDeleted(Order, id)) return undefined;\n *\n * const row = await this.loadRow(id);\n * if (!row) return undefined;\n * const order = Order.reconstitute(row.id, row.state, row.version);\n * return this.tracking.trackLoaded(order);\n * }\n * ```\n *\n * Deletion is final within an operation: {@link delete} removes the\n * entry AND records a tombstone, so a later {@link set} of the same\n * type+id throws `AggregateDeletedError`: a second instance of a\n * deleted aggregate can never sneak back into the unit of work, even\n * through a repository whose row delete is deferred.\n *\n * Lifetime is ONE unit of work: the `UnitOfWork` creates a fresh map\n * per `run()` and clears it on close. Never cache across operations;\n * that would silently bypass optimistic concurrency control.\n */\nexport class IdentityMap {\n\tprivate readonly _stores = new Map<\n\t\tAggregateClass<unknown>,\n\t\tMap<string, unknown>\n\t>();\n\tprivate readonly _deleted = new Map<AggregateClass<unknown>, Set<string>>();\n\t// pendingEvents length captured when an instance was first registered\n\t// (load time), so the unit of work can tell events RECORDED AFTER load\n\t// apart from a \"dirty\" reconstitution that already carried events.\n\tprivate _pendingAtRegistration = new WeakMap<object, number>();\n\n\t/** The cached instance for type+id, or `undefined` (also after {@link delete}). */\n\tpublic get<TAgg>(\n\t\ttype: AggregateClass<TAgg>,\n\t\tid: Id<string>,\n\t): TAgg | undefined {\n\t\treturn this._stores.get(type)?.get(id) as TAgg | undefined;\n\t}\n\n\t/** Whether an instance is registered for type+id (false after {@link delete}). */\n\tpublic has<TAgg>(type: AggregateClass<TAgg>, id: Id<string>): boolean {\n\t\treturn this._stores.get(type)?.has(id) ?? false;\n\t}\n\n\t/**\n\t * Whether type+id was {@link delete}d in this unit of work. The\n\t * read path checks this BEFORE hydrating and returns `null`, so\n\t * \"deleted in this operation\" reads uniformly as not-found,\n\t * regardless of whether the repository's physical delete already\n\t * removed the row or is deferred within the transaction. Without\n\t * the check, a read-only probe of a deleted aggregate would crash\n\t * in {@link set} for deferred-write repositories and return `null`\n\t * for immediate-write ones.\n\t */\n\tpublic isDeleted<TAgg>(type: AggregateClass<TAgg>, id: Id<string>): boolean {\n\t\treturn this._deleted.get(type)?.has(id) ?? false;\n\t}\n\n\t/**\n\t * Registers the hydrated instance for type+id.\n\t *\n\t * - Re-registering the SAME instance is a no-op (idempotent).\n\t * - Registering a DIFFERENT instance for an occupied type+id throws:\n\t * that is precisely the identity-map violation this class exists\n\t * to prevent (the repository hydrated twice instead of checking\n\t * {@link get} first), and letting it pass would double-harvest\n\t * events downstream.\n\t * - Registering a type+id that was {@link delete}d in this unit of\n\t * work throws `AggregateDeletedError`: deletion is final within\n\t * the operation.\n\t */\n\tpublic set<TAgg>(\n\t\ttype: AggregateClass<TAgg>,\n\t\tid: Id<string>,\n\t\taggregate: TAgg,\n\t): void {\n\t\tif (this._deleted.get(type)?.has(id)) {\n\t\t\tthrow new AggregateDeletedError(String(id));\n\t\t}\n\t\tlet store = this._stores.get(type);\n\t\tif (store === undefined) {\n\t\t\tstore = new Map<string, unknown>();\n\t\t\tthis._stores.set(type, store);\n\t\t}\n\t\tconst existing = store.get(id);\n\t\tif (existing !== undefined && existing !== aggregate) {\n\t\t\tthrow new Error(\n\t\t\t\t`IdentityMap: a different instance is already registered for ` +\n\t\t\t\t\t`${type.name}(${String(id)}). Check get() before hydrating - ` +\n\t\t\t\t\t`two live instances of one aggregate break the one-instance-per-` +\n\t\t\t\t\t`unit-of-work contract that exactly-once event harvest relies on.`,\n\t\t\t);\n\t\t}\n\t\tstore.set(id, aggregate);\n\t\t// Capture the load-time pending count once (idempotent re-set keeps\n\t\t// the first value), so the unit of work can later tell events\n\t\t// RECORDED AFTER load apart from a reconstitution that already\n\t\t// carried events. Assumes pendingEvents is append-only between load\n\t\t// and commit (the kit's recordEvent model); only the internal\n\t\t// post-commit capability shrinks it.\n\t\tif (\n\t\t\taggregate !== null &&\n\t\t\ttypeof aggregate === \"object\" &&\n\t\t\t!this._pendingAtRegistration.has(aggregate as object)\n\t\t) {\n\t\t\tconst pending = pendingEventCountOf(aggregate);\n\t\t\tif (pending !== undefined) {\n\t\t\t\tthis._pendingAtRegistration.set(aggregate as object, pending);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Registered instances that have recorded MORE pending events than they\n\t * carried when first registered (loaded). Used by the unit of work's\n\t * end-of-run guard: an aggregate that gained events after load but was\n\t * never enrolled would silently drop them. A read-only load, or a\n\t * reconstitution that already carried events, shows no increase and is\n\t * not reported.\n\t */\n\tpublic instancesWithNewPendingEvents(): unknown[] {\n\t\tconst result: unknown[] = [];\n\t\tfor (const store of this._stores.values()) {\n\t\t\tfor (const instance of store.values()) {\n\t\t\t\tconst pending = pendingEventCountOf(instance);\n\t\t\t\tif (pending === undefined) continue;\n\t\t\t\tconst atRegistration =\n\t\t\t\t\tthis._pendingAtRegistration.get(instance as object) ?? 0;\n\t\t\t\tif (pending > atRegistration) {\n\t\t\t\t\tresult.push(instance);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\t/**\n\t * Takes back a registration WITHOUT a tombstone: the entry is removed\n\t * only when the stored instance IS the given one, and a later\n\t * {@link set} of the same type+id stays legal. The Unit of Work calls\n\t * this when a registration step fails after {@link set} already ran, so\n\t * the failed instance cannot be served by `findById` as a phantom.\n\t * This is rollback, not deletion; deletion finality belongs to\n\t * {@link delete}.\n\t */\n\tpublic discard<TAgg>(\n\t\ttype: AggregateClass<TAgg>,\n\t\tid: Id<string>,\n\t\taggregate: TAgg,\n\t): void {\n\t\tconst store = this._stores.get(type);\n\t\tif (store?.get(id) === aggregate) {\n\t\t\tstore.delete(id);\n\t\t}\n\t}\n\n\t/**\n\t * Removes the entry for type+id and records a tombstone: subsequent\n\t * {@link get} / {@link has} report absence, and a subsequent\n\t * {@link set} of the same type+id throws `AggregateDeletedError`.\n\t * The Unit of Work calls this as part of `repository.remove(aggregate)`;\n\t * repository adapters receive only the read-only\n\t * identity-map view.\n\t */\n\tpublic delete<TAgg>(type: AggregateClass<TAgg>, id: Id<string>): void {\n\t\tthis._stores.get(type)?.delete(id);\n\t\tlet tombstones = this._deleted.get(type);\n\t\tif (tombstones === undefined) {\n\t\t\ttombstones = new Set<string>();\n\t\t\tthis._deleted.set(type, tombstones);\n\t\t}\n\t\ttombstones.add(id);\n\t}\n\n\t/** Empties all stores and tombstones. Called by the unit of work on close. */\n\tpublic clear(): void {\n\t\tthis._stores.clear();\n\t\tthis._deleted.clear();\n\t\t// A WeakMap cannot be emptied in place; replace it so a reused map\n\t\t// captures FRESH pending-event baselines. A stale (higher) baseline\n\t\t// would make instancesWithNewPendingEvents under-report and defeat\n\t\t// the UnenrolledChangesError safety net.\n\t\tthis._pendingAtRegistration = new WeakMap<object, number>();\n\t}\n}\n\n/**\n * Pending-event count of a stored value, or `undefined` for anything that is\n * not aggregate-shaped. Single source of truth so the load-time capture in\n * {@link IdentityMap.set} and the end-of-run scan in\n * {@link IdentityMap.instancesWithNewPendingEvents} cannot drift apart.\n * The kit-internal count capability avoids the public `pendingEvents`\n * getter, which allocates and freezes a defensive copy per read; the getter\n * stays as the fallback for structural lookalikes.\n */\nfunction pendingEventCountOf(value: unknown): number | undefined {\n\tif (value === null || typeof value !== \"object\") return undefined;\n\tconst capability = pendingEventLifecycleCapabilityFor(value);\n\tif (capability?.pendingEventCount) return capability.pendingEventCount();\n\tconst pending = (value as { pendingEvents?: unknown }).pendingEvents;\n\treturn Array.isArray(pending) ? pending.length : undefined;\n}\n","import { deepEqual } from \"../utils/array/deep-equal\";\n\n/** Whether a baseline represents an existing row or a pending insert. */\nexport type PersistenceLifecycle = \"loaded\" | \"new\";\n\n/**\n * Adapter-owned projection and change derivation for one aggregate type.\n *\n * The domain model does not implement this contract. A repository adapter\n * chooses what it persists, how that projection is captured at load, and\n * whether a change set is a partial diff or a full replacement.\n */\nexport interface PersistenceModel<TAggregate, TBaseline, TChangeSet> {\n\t/**\n\t * Captures the adapter's persistence projection at the current moment.\n\t * Return a detached value or an immutable value object: the Unit of Work\n\t * retains it as a baseline and cannot make an arbitrary adapter type safe.\n\t *\n\t * Capture must be deterministic for an unchanged aggregate: the Unit of\n\t * Work compares successive captures to detect mutation after write\n\t * registration. A capture that embeds ambient values (clock reads,\n\t * random ids) would make every commit look mutated. The default\n\t * comparison is the package's structural deep equality, which matches\n\t * `Set` members and `Map` keys by reference (JS `SameValueZero`\n\t * semantics): a capture that re-materializes object Set members or Map\n\t * keys on every call must supply {@link captureEquals}.\n\t */\n\tcapture(aggregate: TAggregate): TBaseline;\n\n\t/**\n\t * Adapter-owned equality for two captures of the persistence projection.\n\t * Optional: the default is the package's structural deep equality (Set\n\t * members and Map keys by reference). Supply it when the capture shape\n\t * needs domain-specific comparison, for example rebuilt value-object Set\n\t * members compared by value.\n\t */\n\treadonly captureEquals?: (a: TBaseline, b: TBaseline) => boolean;\n\n\t/**\n\t * Derives the adapter's write payload from its own baseline.\n\t *\n\t * `baseline` is absent for a new aggregate. `lifecycle` disambiguates that\n\t * case from an adapter whose loaded baseline type itself admits `undefined`.\n\t * The returned payload must not share mutable references with the aggregate;\n\t * it is the exact value later handed to `flush`.\n\t */\n\tchanges(\n\t\tbaseline: TBaseline | undefined,\n\t\taggregate: TAggregate,\n\t\tlifecycle: PersistenceLifecycle,\n\t): TChangeSet;\n\n\t/** Tells orchestration whether the derived state write is empty. */\n\tisEmpty(changes: TChangeSet): boolean;\n}\n\ndeclare const persistenceBaselineBrand: unique symbol;\n\n/**\n * Opaque, typed receipt for an adapter-owned persistence baseline.\n *\n * It intentionally exposes no data. The Unit of Work may retain the token and\n * ask the owning adapter capability to derive changes, but cannot branch on or\n * couple itself to the baseline's shape.\n */\nexport interface PersistenceBaseline<TAggregate, TChangeSet> {\n\treadonly [persistenceBaselineBrand]: (aggregate: TAggregate) => TChangeSet;\n}\n\n/** A derived adapter change set plus its adapter-defined emptiness result. */\nexport interface PersistenceChanges<TChangeSet> {\n\treadonly value: TChangeSet;\n\treadonly empty: boolean;\n}\n\ninterface BaselineCapability {\n\treadonly baseline: unknown;\n\treadonly lifecycle: PersistenceLifecycle;\n\tcapture(aggregate: unknown): unknown;\n\tcaptureEquals(a: unknown, b: unknown): boolean;\n\tchanges(\n\t\tbaseline: unknown,\n\t\taggregate: unknown,\n\t\tlifecycle: PersistenceLifecycle,\n\t): unknown;\n\tisEmpty(changes: unknown): boolean;\n}\n\nconst capabilities = new WeakMap<object, BaselineCapability>();\n\n/** Captures a baseline for an aggregate restored by a repository adapter. */\nexport function capturePersistenceBaseline<TAggregate, TBaseline, TChangeSet>(\n\tmodel: PersistenceModel<TAggregate, TBaseline, TChangeSet>,\n\taggregate: TAggregate,\n): PersistenceBaseline<TAggregate, TChangeSet> {\n\treturn createBaselineToken(model, model.capture(aggregate), \"loaded\");\n}\n\n/** Creates the explicit no-row baseline for a newly added aggregate. */\nexport function insertPersistenceBaseline<TAggregate, TBaseline, TChangeSet>(\n\tmodel: PersistenceModel<TAggregate, TBaseline, TChangeSet>,\n): PersistenceBaseline<TAggregate, TChangeSet> {\n\treturn createBaselineToken(model, undefined, \"new\");\n}\n\n/**\n * Captures the aggregate's current adapter projection using the capability\n * carried by an existing baseline. Used to seal persistence-last registration.\n */\nexport function recapturePersistenceBaseline<TAggregate, TChangeSet>(\n\tbaseline: PersistenceBaseline<TAggregate, TChangeSet>,\n\taggregate: TAggregate,\n): PersistenceBaseline<TAggregate, TChangeSet> {\n\tconst capability = capabilityFor(baseline);\n\treturn createErasedBaselineToken({\n\t\t...capability,\n\t\tbaseline: capability.capture(aggregate),\n\t\tlifecycle: \"loaded\",\n\t});\n}\n\n/**\n * Recaptures the adapter projection and reports whether it drifted from the\n * baseline's stored capture, using the model's `captureEquals` when supplied\n * and structural deep equality otherwise.\n *\n * This, not `changes()`/`isEmpty()`, is the mutation detector: the\n * `PersistenceModel` contract explicitly permits a full-replacement change\n * set whose `isEmpty` is never true, so a non-empty change set proves\n * nothing about mutation. Comparing capture to capture asks the honest\n * question independent of the model's diffing strategy. A `\"new\"` lifecycle\n * baseline has no stored capture and never reports drift.\n */\nexport function persistenceProjectionDrifted<TAggregate, TChangeSet>(\n\tbaseline: PersistenceBaseline<TAggregate, TChangeSet>,\n\taggregate: TAggregate,\n): boolean {\n\tconst capability = capabilityFor(baseline);\n\tif (capability.lifecycle === \"new\") return false;\n\treturn !capability.captureEquals(\n\t\tcapability.baseline,\n\t\tcapability.capture(aggregate),\n\t);\n}\n\n/** Derives a typed adapter change set without exposing the stored baseline. */\nexport function derivePersistenceChanges<TAggregate, TChangeSet>(\n\tbaseline: PersistenceBaseline<TAggregate, TChangeSet>,\n\taggregate: TAggregate,\n): PersistenceChanges<TChangeSet> {\n\tconst capability = capabilityFor(baseline);\n\tconst value = capability.changes(\n\t\tcapability.baseline,\n\t\taggregate,\n\t\tcapability.lifecycle,\n\t) as TChangeSet;\n\treturn Object.freeze({ value, empty: capability.isEmpty(value) });\n}\n\nfunction createBaselineToken<TAggregate, TBaseline, TChangeSet>(\n\tmodel: PersistenceModel<TAggregate, TBaseline, TChangeSet>,\n\tbaseline: TBaseline | undefined,\n\tlifecycle: PersistenceLifecycle,\n): PersistenceBaseline<TAggregate, TChangeSet> {\n\treturn createErasedBaselineToken({\n\t\tbaseline,\n\t\tlifecycle,\n\t\tcapture: (aggregate) => model.capture(aggregate as TAggregate),\n\t\tcaptureEquals: (a, b) =>\n\t\t\tmodel.captureEquals\n\t\t\t\t? model.captureEquals(a as TBaseline, b as TBaseline)\n\t\t\t\t: deepEqual(a, b),\n\t\tchanges: (stored, aggregate, currentLifecycle) =>\n\t\t\tmodel.changes(\n\t\t\t\tstored as TBaseline | undefined,\n\t\t\t\taggregate as TAggregate,\n\t\t\t\tcurrentLifecycle,\n\t\t\t),\n\t\tisEmpty: (changes) => model.isEmpty(changes as TChangeSet),\n\t});\n}\n\nfunction createErasedBaselineToken<TAggregate, TChangeSet>(\n\tcapability: BaselineCapability,\n): PersistenceBaseline<TAggregate, TChangeSet> {\n\tconst token = Object.freeze(Object.create(null)) as PersistenceBaseline<\n\t\tTAggregate,\n\t\tTChangeSet\n\t>;\n\tcapabilities.set(token as object, capability);\n\treturn token;\n}\n\nfunction capabilityFor<TAggregate, TChangeSet>(\n\tbaseline: PersistenceBaseline<TAggregate, TChangeSet>,\n): BaselineCapability {\n\tconst capability = capabilities.get(baseline as object);\n\tif (!capability) {\n\t\tthrow new TypeError(\n\t\t\t\"Persistence baseline was not created by this package instance.\",\n\t\t);\n\t}\n\treturn capability;\n}\n","import type { IAggregateRoot, Version } from \"../aggregate/aggregate\";\nimport type {\n\tAnyDomainEvent,\n\tPendingDomainEvent,\n} from \"../aggregate/domain-event\";\nimport {\n\tAggregateDeletedError,\n\tEventHarvestError,\n\tInfrastructureError,\n\tisInfrastructureErrorLike,\n\tKitWiringError,\n\tUnenrolledChangesError,\n} from \"../core/errors\";\nimport type { Id } from \"../core/id\";\nimport type { EventBus, OutboxWriter } from \"../events/ports\";\nimport { type AggregateClass, IdentityMap } from \"../repo/identity-map\";\nimport {\n\tcapturePersistenceBaseline,\n\tderivePersistenceChanges,\n\tinsertPersistenceBaseline,\n\ttype PersistenceBaseline,\n\ttype PersistenceChanges,\n\ttype PersistenceModel,\n\tpersistenceProjectionDrifted,\n\trecapturePersistenceBaseline,\n} from \"../repo/persistence-model\";\nimport type { TransactionScope } from \"../repo/scope\";\nimport { abortReason } from \"../utils/abort\";\nimport type { ExecutionContext } from \"../utils/execution\";\nimport {\n\ttype AggregateCommitToken,\n\ttype CommitEnrollment,\n\twithCommit,\n} from \"./handler\";\n\n/**\n * Thrown when `UnitOfWork.run()` is called while the same instance is\n * already executing a unit of work: either a genuinely nested `run()`\n * inside the work callback, or two concurrent operations sharing one\n * instance.\n *\n * Both are contract violations, not recoverable infrastructure\n * failures, so this carries the `WIRING` category (same reasoning as\n * `MissingHandlerError`): a generic `catch (e instanceof\n * InfrastructureError)` handler must not mask it.\n *\n * A nested `run()` would NOT join the outer transaction; it would open\n * an independent one, silently breaking the all-or-nothing guarantee.\n * If two operations must commit together, they are ONE unit of work:\n * merge them into a single `run()` callback. For concurrent requests,\n * construct one `UnitOfWork` per operation (construction is trivially\n * cheap; the dependency object is the thing you share).\n */\nexport class NestedUnitOfWorkError extends KitWiringError<\"NESTED_UNIT_OF_WORK\"> {\n\tconstructor() {\n\t\tsuper(\n\t\t\t\"NESTED_UNIT_OF_WORK\",\n\t\t\t\"UnitOfWork.run() was called while this instance is already running. \" +\n\t\t\t\t\"A nested run() would open an independent transaction, not join the \" +\n\t\t\t\t\"outer one - merge the work into a single run() callback. For \" +\n\t\t\t\t\"concurrent operations, construct one UnitOfWork per operation.\",\n\t\t);\n\t}\n}\n\ninterface RuntimePersistenceDefinition<Evt extends AnyDomainEvent> {\n\treadonly aggregate: AggregateClass<IAggregateRoot<Id<string>, Evt>>;\n\treadonly persistence: PersistenceModel<\n\t\tIAggregateRoot<Id<string>, Evt>,\n\t\tunknown,\n\t\tunknown\n\t>;\n\treadonly flush: (\n\t\ttransaction: unknown,\n\t\twrite: AggregatePersistenceWrite<IAggregateRoot<Id<string>, Evt>, unknown>,\n\t) => void | Promise<void>;\n\treadonly mapError: (\n\t\terror: unknown,\n\t\twrite: AggregatePersistenceWrite<IAggregateRoot<Id<string>, Evt>, unknown>,\n\t) => InfrastructureError;\n\treadonly physicalRemoval?: boolean;\n}\n\ninterface RuntimeRepositoryDefinition<Evt extends AnyDomainEvent, TCtx>\n\textends RuntimePersistenceDefinition<Evt> {\n\treadonly create: (\n\t\ttransaction: TCtx,\n\t\ttracking: RepositoryTracking<IAggregateRoot<Id<string>, Evt>>,\n\t) => unknown;\n}\n\n/**\n * Thrown when the unit-of-work context is used after `run()` has\n * settled: reading `context.repositories`, calling an adapter-held\n * `tracking.trackLoaded`, or using a repository facade after the transaction\n * has committed or rolled back.\n *\n * Use-after-close is a programming bug (typically a leaked context\n * reference or a fire-and-forget promise outliving the callback), so\n * this carries the `WIRING` category and should crash loud.\n *\n * **Honest scope of this guard:** the kit can only invalidate what it\n * controls: context getters, repository-facade operations, and the tracking\n * capability. An adapter that captures its raw transaction handle can still call\n * it as far as the kit can see;\n * whether the driver rejects after close is ORM-specific. Adapter factories\n * must not let that handle escape into application code.\n */\nexport class TransactionClosedError extends KitWiringError<\"TRANSACTION_CLOSED\"> {\n\tconstructor(public readonly operation: string) {\n\t\tsuper(\n\t\t\t\"TRANSACTION_CLOSED\",\n\t\t\t`Unit of work is closed: ${operation} was called after the ` +\n\t\t\t\t\"transaction committed or rolled back. Do not use the context or \" +\n\t\t\t\t\"repository facade or tracking capability outside the run() callback.\",\n\t\t);\n\t}\n}\n\n/** A repository factory returned a value that cannot be wrapped as a facade. */\nexport class InvalidRepositoryAdapterError extends KitWiringError<\"INVALID_REPOSITORY_ADAPTER\"> {\n\tconstructor(\n\t\tpublic readonly repository: string,\n\t\tpublic readonly receivedType: string,\n\t) {\n\t\tsuper(\n\t\t\t\"INVALID_REPOSITORY_ADAPTER\",\n\t\t\t`Repository factory \"${repository}\" returned ${receivedType}; ` +\n\t\t\t\t\"it must return an adapter object.\",\n\t\t);\n\t}\n}\n\n/** A Unit of Work received repository wiring that bypassed {@link defineRepository}. */\nexport class InvalidRepositoryDefinitionError extends KitWiringError<\"INVALID_REPOSITORY_DEFINITION\"> {\n\tconstructor(public readonly repository: string) {\n\t\tsuper(\n\t\t\t\"INVALID_REPOSITORY_DEFINITION\",\n\t\t\t`Repository \"${repository}\" was not created by defineRepository. ` +\n\t\t\t\t\"Declare the application port explicitly and pass the helper-created \" +\n\t\t\t\t\"definition to UnitOfWork.\",\n\t\t);\n\t}\n}\n\n/** A repository's persistence-error policy threw or returned a non-kit error. */\nexport class RepositoryErrorMappingFailedError extends KitWiringError<\"REPOSITORY_ERROR_MAPPING_FAILED\"> {\n\treadonly aggregateId: string;\n\treadonly intent: AggregateWriteIntent;\n\treadonly mapperCause: unknown;\n\n\tconstructor(options: {\n\t\treadonly aggregateId: string;\n\t\treadonly intent: AggregateWriteIntent;\n\t\treadonly persistenceError: unknown;\n\t\treadonly mapperError: unknown;\n\t}) {\n\t\tsuper(\n\t\t\t\"REPOSITORY_ERROR_MAPPING_FAILED\",\n\t\t\t`The repository error mapper failed for ${options.intent} of aggregate ` +\n\t\t\t\t`${options.aggregateId}. The original persistence failure is preserved ` +\n\t\t\t\t\"as cause; the mapper failure is available as mapperCause.\",\n\t\t\toptions.persistenceError,\n\t\t);\n\t\tthis.aggregateId = options.aggregateId;\n\t\tthis.intent = options.intent;\n\t\tthis.mapperCause = options.mapperError;\n\t}\n}\n\n/** The explicit persistence intent registered for one tracked aggregate. */\nexport type AggregateWriteIntent = \"add\" | \"update\" | \"remove\";\n\n/** Why an aggregate lifecycle registration was rejected. */\nexport type AggregateTrackingFailure =\n\t| \"not_loaded\"\n\t| \"loaded_as_new\"\n\t| \"different_repository\"\n\t| \"conflicting_intent\"\n\t| \"mutated_after_registration\";\n\n/**\n * A deterministic violation of the Unit of Work's aggregate lifecycle.\n *\n * This is a wiring error rather than a domain or infrastructure failure: the\n * application registered persistence intent in an order the Unit of Work\n * cannot execute truthfully. Retrying the same callback cannot repair it.\n */\nexport class AggregateTrackingError extends KitWiringError<\"AGGREGATE_TRACKING\"> {\n\tconstructor(\n\t\tpublic readonly aggregateId: string,\n\t\tpublic readonly operation: AggregateWriteIntent | \"load\" | \"commit\",\n\t\tpublic readonly reason: AggregateTrackingFailure,\n\t\tpublic readonly registeredIntent?: AggregateWriteIntent,\n\t) {\n\t\tsuper(\n\t\t\t\"AGGREGATE_TRACKING\",\n\t\t\ttrackingFailureMessage(aggregateId, operation, reason, registeredIntent),\n\t\t);\n\t}\n}\n\nfunction trackingFailureMessage(\n\taggregateId: string,\n\toperation: AggregateWriteIntent | \"load\" | \"commit\",\n\treason: AggregateTrackingFailure,\n\tregisteredIntent: AggregateWriteIntent | undefined,\n): string {\n\tswitch (reason) {\n\t\tcase \"not_loaded\":\n\t\t\treturn (\n\t\t\t\t`Aggregate ${aggregateId} cannot be registered for ${operation}: ` +\n\t\t\t\t\"it was not loaded into this unit of work. Load it through the \" +\n\t\t\t\t\"repository before updating or removing it.\"\n\t\t\t);\n\t\tcase \"loaded_as_new\":\n\t\t\treturn (\n\t\t\t\t`Aggregate ${aggregateId} cannot be added as new because it was ` +\n\t\t\t\t\"loaded by this unit of work. Use update for a loaded aggregate.\"\n\t\t\t);\n\t\tcase \"different_repository\":\n\t\t\treturn (\n\t\t\t\t`Aggregate ${aggregateId} cannot be registered for ${operation} through ` +\n\t\t\t\t\"a different repository in the same unit of work. One aggregate instance \" +\n\t\t\t\t\"must remain owned by the repository definition that first tracked it.\"\n\t\t\t);\n\t\tcase \"conflicting_intent\":\n\t\t\treturn (\n\t\t\t\t`Aggregate ${aggregateId} is already registered for ` +\n\t\t\t\t`${registeredIntent ?? \"another write\"}; ${operation} would create ` +\n\t\t\t\t\"conflicting persistence intent in one unit of work. Decide the final \" +\n\t\t\t\t\"lifecycle outcome before registering it.\"\n\t\t\t);\n\t\tcase \"mutated_after_registration\":\n\t\t\treturn (\n\t\t\t\t`Aggregate ${aggregateId} changed after ${registeredIntent ?? \"write\"} ` +\n\t\t\t\t\"was registered. Make domain decisions first and call add, update, or \" +\n\t\t\t\t\"remove last so persisted state and recorded events cannot diverge.\"\n\t\t\t);\n\t}\n}\n\n/**\n * The unit of work failed AFTER the work callback completed\n * successfully, at the persistence boundary: the outbox write or the\n * transaction commit itself rejected. The kit cannot see inside\n * `TransactionScope.transactional`, so these are deliberately one error\n * class; the underlying failure is attached as `cause`.\n *\n * `InfrastructureError`: the business logic ran to completion; the\n * persistence boundary failed. The transaction rolled back (or never\n * committed), no aggregate was marked persisted, and pending events\n * survive on the aggregates; the operation left no partial state behind.\n * A `CommitError` is the **potentially transient** post-completion\n * failure (a commit-time serialization failure is the classic case), so\n * it is the one a retrying caller should consider re-running. The\n * deterministic post-completion failure, a harvest-guard violation (an\n * event missing `aggregateId` / `aggregateType`, or an eventful persisted\n * aggregate that did not advance its version), is a programming bug and surfaces as\n * {@link EventHarvestError} instead, which does NOT extend\n * `InfrastructureError`, so it stays out of retry paths by construction.\n */\nexport class CommitError extends InfrastructureError<\"COMMIT_FAILED\"> {\n\tconstructor(cause: unknown) {\n\t\tsuper({\n\t\t\tcode: \"COMMIT_FAILED\",\n\t\t\tmessage:\n\t\t\t\t\"Unit of work failed after the work callback completed: the outbox \" +\n\t\t\t\t\"write or the transaction commit rejected. The transaction did \" +\n\t\t\t\t\"not commit; this failure may be transient, inspect the cause \" +\n\t\t\t\t\"(e.g. someChainRetryable) before retrying.\",\n\t\t\tcause,\n\t\t});\n\t}\n}\n\n/**\n * The work callback threw AND the transaction scope rejected with a\n * DIFFERENT error that does not wrap the callback's error in its cause\n * chain - the strongest available signal that the rollback itself\n * failed. The callback's (primary) error is preserved as `cause`, so\n * cause-chain helpers (`someChainRetryable`, `findInCauseChain`) still\n * see a wrapped `ConcurrencyConflictError` & co.; the scope's error is\n * carried in {@link rollbackCause}.\n *\n * Scopes that rethrow the original error (Drizzle, Prisma do) never\n * produce this; scopes that WRAP the original are detected via the\n * cause chain and passed through unchanged instead.\n */\nexport class RollbackError extends InfrastructureError<\"ROLLBACK_FAILED\"> {\n\tconstructor(\n\t\tcause: unknown,\n\t\tpublic readonly rollbackCause: unknown,\n\t) {\n\t\tsuper({\n\t\t\tcode: \"ROLLBACK_FAILED\",\n\t\t\tmessage:\n\t\t\t\t\"The work callback failed and the transaction scope rejected with a \" +\n\t\t\t\t\"different error (possible rollback failure). The callback's error \" +\n\t\t\t\t\"is the cause; the scope's error is in rollbackCause.\",\n\t\t\tcause,\n\t\t});\n\t}\n}\n\n/** Read-only Identity Map operations available to repository adapters. */\nexport type UnitOfWorkIdentityMap = Pick<\n\tIdentityMap,\n\t\"get\" | \"has\" | \"isDeleted\"\n>;\n\n/**\n * Repository-specific tracking capability handed only to its adapter.\n *\n * Read paths call {@link RepositoryTracking.trackLoaded} before returning a\n * restored aggregate.\n * Write methods exposed to application code are replaced by Unit-of-Work-owned\n * `add`, `update`, and `remove` registrations, so an adapter implementation of\n * those methods cannot perform durable I/O early or skip event harvesting.\n *\n * Contract for repository implementations:\n * - `findById(id)` checks `identityMap.get` BEFORE hydrating, treats\n * `identityMap.isDeleted` as not-found (`undefined`), and returns\n * `tracking.trackLoaded(aggregate)` after hydration. This captures the\n * expected version before application code can mutate the instance.\n * - Adapter objects do not need lifecycle methods; the facade installs the\n * Unit-of-Work-owned `add`, `update`, and optional `remove`. If a concrete\n * adapter has same-named methods anyway, the facade masks them.\n * - Other repository methods are reads. A custom method that performs a write\n * would bypass the Unit of Work and violates the adapter contract.\n */\nexport interface RepositoryTracking<\n\tTAggregate extends IAggregateRoot<Id<string>, AnyDomainEvent>,\n> {\n\t/**\n\t * Registers an aggregate restored by a repository before returning it to\n\t * application code. The Unit of Work identity-maps the instance and captures\n\t * its current version as the optimistic-concurrency expectation.\n\t */\n\ttrackLoaded(aggregate: TAggregate): TAggregate;\n\n\t/**\n\t * Read-only view of the per-operation Identity Map (Fowler): one aggregate type+id,\n\t * one in-memory instance. Created fresh per `run()`, cleared on\n\t * close; accessing it after close throws\n\t * {@link TransactionClosedError}.\n\t */\n\treadonly identityMap: UnitOfWorkIdentityMap;\n}\n\n/**\n * What the application work callback receives: repositories already bound to\n * the live Unit of Work plus cooperative cancellation.\n *\n * The adapter-only transaction and tracking capability are deliberately absent.\n * Exposing either would let application code bypass repository lifecycle\n * registration and would leak infrastructure types into the use case.\n */\nexport interface UnitOfWorkContext<TRepos> {\n\treadonly repositories: TRepos;\n\n\t/**\n\t * The cooperative-cancellation signal passed to {@link UnitOfWork.run},\n\t * or `undefined` if none was given. Poll `signal?.aborted` between\n\t * steps of a long operation and throw `signal.reason` to bail out; the\n\t * throw rolls the unit of work back like any other callback error. The\n\t * kit does not interrupt an in-flight query for you: actual query\n\t * cancellation depends on the `TransactionScope` honoring the signal.\n\t */\n\treadonly signal?: AbortSignal;\n}\n\n/** Options for a single {@link UnitOfWork.run} call. */\nexport interface RunOptions {\n\t/**\n\t * Cooperative-cancellation signal. If already aborted, `run()` rejects\n\t * with the signal's `reason` before opening a transaction. Otherwise it\n\t * is exposed on the context (poll `context.signal`) and forwarded to the\n\t * `TransactionScope`. Use `AbortSignal.timeout(ms)` for a deadline.\n\t */\n\treadonly signal?: AbortSignal;\n}\n\n// Shared across package copies like every other kit brand: a definition\n// built by a bundled plugin copy's defineRepository must be accepted by the\n// host copy's UnitOfWork. The key version stamps the definition SHAPE; bump\n// it when the definition contract changes so an incompatible copy fails the\n// generic not-a-definition check instead of half-working.\nconst repositoryDefinitionBrand: unique symbol = Symbol.for(\n\t\"@shirudo/ddd-kit/repository-definition/v1\",\n);\n\n/** Adapter wiring accepted by {@link defineRepository}. */\nexport interface RepositoryDefinitionOptions<\n\tTCtx,\n\tTRepositoryPort extends object,\n\tTAggregate extends IAggregateRoot<Id<string>, AnyDomainEvent>,\n\tTBaseline,\n\tTChangeSet,\n\tTRemoval extends boolean = false,\n> {\n\t/** Concrete aggregate class used as the Identity Map key. */\n\treadonly aggregate: AggregateClass<TAggregate>;\n\t/** Adapter-owned projection, baseline, and change-set policy. */\n\treadonly persistence: PersistenceModel<TAggregate, TBaseline, TChangeSet>;\n\t/**\n\t * Creates the transaction-bound adapter for the port's non-lifecycle\n\t * methods. The Unit of Work supplies `add`, `update`, and optional `remove`.\n\t */\n\treadonly create: (\n\t\ttransaction: TCtx,\n\t\ttracking: RepositoryTracking<TAggregate>,\n\t) => Omit<TRepositoryPort, \"add\" | \"update\" | \"remove\">;\n\t/**\n\t * Performs the registered write during the Unit of Work's commit phase.\n\t *\n\t * The receipt contains adapter-owned changes and immutable persistence\n\t * facts, never the mutable aggregate instance. The transaction remains open\n\t * while this function and the outbox write run.\n\t */\n\treadonly flush: (\n\t\ttransaction: NoInfer<TCtx>,\n\t\twrite: AggregatePersistenceWrite<TAggregate, TChangeSet>,\n\t) => void | Promise<void>;\n\t/**\n\t * Translates every adapter/driver failure from `flush` into an explicit\n\t * application-facing infrastructure error. Returning or throwing a raw\n\t * driver error is a wiring failure and is rejected by the Unit of Work.\n\t */\n\treadonly mapError: (\n\t\terror: unknown,\n\t\twrite: AggregatePersistenceWrite<TAggregate, TChangeSet>,\n\t) => InfrastructureError;\n\t/** Adds Unit-of-Work-owned `remove` to the application-facing repository. */\n\treadonly physicalRemoval?: TRemoval;\n}\n\n/** Complete, helper-created definition for one Unit-of-Work repository. */\nexport interface RepositoryDefinition<\n\tTCtx,\n\tTRepositoryPort extends object,\n\tTAggregate extends IAggregateRoot<Id<string>, AnyDomainEvent>,\n\tTBaseline,\n\tTChangeSet,\n\tTRemoval extends boolean = false,\n> extends RepositoryDefinitionOptions<\n\t\tTCtx,\n\t\tTRepositoryPort,\n\t\tTAggregate,\n\t\tTBaseline,\n\t\tTChangeSet,\n\t\tTRemoval\n\t> {\n\t/** Nominal marker installed by {@link defineRepository}. */\n\treadonly [repositoryDefinitionBrand]: true;\n}\n\n/**\n * Immutable adapter input for one registered aggregate write.\n *\n * `expectedVersion` is captured when a loaded aggregate joins the Unit of\n * Work and is absent for `add`. `version`, `changes`, and `events` describe\n * the exact moment at which the application registered its write intent.\n * Adapters must use the expected/current version pair for their OCC predicate\n * and must not read mutable write state back from an aggregate reference.\n */\nexport interface AggregatePersistenceWrite<\n\tTAggregate extends IAggregateRoot<Id<string>, AnyDomainEvent>,\n\tTChangeSet,\n> {\n\treadonly intent: AggregateWriteIntent;\n\treadonly aggregateId: TAggregate[\"id\"];\n\treadonly expectedVersion: Version | undefined;\n\treadonly version: Version;\n\treadonly changes: PersistenceChanges<TChangeSet>;\n\treadonly events: TAggregate[\"pendingEvents\"];\n}\n\n/** @inline */\ntype CallableValue = (...args: never[]) => unknown;\n\n/** @inline */\ntype RepositoryDefinitionBuilder<TRepositoryPort extends object> = <\n\tTAggregate extends IAggregateRoot<Id<string>, AnyDomainEvent>,\n\tTCreate extends (\n\t\ttransaction: never,\n\t\ttracking: RepositoryTracking<TAggregate>,\n\t) => Omit<TRepositoryPort, \"add\" | \"update\" | \"remove\">,\n\tTBaseline,\n\tTChangeSet,\n\tTRemoval extends boolean = false,\n>(\n\tdefinition: RepositoryDefinitionOptions<\n\t\tParameters<TCreate>[0],\n\t\tTRepositoryPort,\n\t\tTAggregate,\n\t\tTBaseline,\n\t\tTChangeSet,\n\t\tTRemoval\n\t> & {\n\t\treadonly create: TCreate;\n\t} & (TRepositoryPort extends AggregateWriteRegistration<TAggregate>\n\t\t\t? TRemoval extends true\n\t\t\t\t? TRepositoryPort extends PhysicalRemovalRegistration<TAggregate>\n\t\t\t\t\t? unknown\n\t\t\t\t\t: never\n\t\t\t\t: TRepositoryPort extends PhysicalRemovalRegistration<TAggregate>\n\t\t\t\t\t? never\n\t\t\t\t\t: unknown\n\t\t\t: never),\n) => RepositoryDefinition<\n\tParameters<TCreate>[0],\n\tTRepositoryPort,\n\tTAggregate,\n\tTBaseline,\n\tTChangeSet,\n\tTRemoval\n>;\n\n/**\n * Defines repository wiring for an application-owned driven port.\n *\n * The first call makes the port explicit; the second infers the transaction,\n * aggregate, persistence, event, and removal types from the adapter wiring.\n * The port must declare `add` and `update`; if it declares `remove`, the\n * definition must set `physicalRemoval: true`. The adapter created by the\n * definition implements only the remaining methods because lifecycle writes\n * are installed by the Unit of Work.\n * The returned definition is the only form accepted by {@link UnitOfWork}; a\n * raw adapter-shaped object cannot silently turn its concrete surface into the\n * application contract.\n */\nfunction assertRepositoryDefinitionMembers(\n\tdefinition: Record<PropertyKey, unknown>,\n): void {\n\tfor (const key of [\"create\", \"flush\", \"mapError\"] as const) {\n\t\tif (typeof definition[key] !== \"function\") {\n\t\t\tthrow new TypeError(\n\t\t\t\t`defineRepository: \"${key}\" is missing or not a function on the ` +\n\t\t\t\t\t\"definition. The builder copies own enumerable properties only; \" +\n\t\t\t\t\t\"prototype methods and non-enumerable members are not carried. \" +\n\t\t\t\t\t\"Pass a plain object literal.\",\n\t\t\t);\n\t\t}\n\t}\n\tif (typeof definition.aggregate !== \"function\") {\n\t\tthrow new TypeError(\n\t\t\t'defineRepository: \"aggregate\" is missing or not a class reference ' +\n\t\t\t\t\"on the definition. Pass a plain object literal with own \" +\n\t\t\t\t\"enumerable properties.\",\n\t\t);\n\t}\n\tif (\n\t\tdefinition.persistence === null ||\n\t\ttypeof definition.persistence !== \"object\"\n\t) {\n\t\tthrow new TypeError(\n\t\t\t'defineRepository: \"persistence\" is missing or not a ' +\n\t\t\t\t\"PersistenceModel on the definition. Pass a plain object literal \" +\n\t\t\t\t\"with own enumerable properties.\",\n\t\t);\n\t}\n}\n\nexport function defineRepository<TRepositoryPort extends object>(): Extract<\n\tTRepositoryPort,\n\tCallableValue\n> extends never\n\t? RepositoryDefinitionBuilder<TRepositoryPort>\n\t: never {\n\tconst builder = (definition: object): object => {\n\t\tconst branded = { ...definition };\n\t\t// Validated AFTER the spread, on what actually survives it: the\n\t\t// spread copies own enumerable properties only, so create/flush/\n\t\t// mapError carried on a prototype (class instance) or as\n\t\t// non-enumerable members vanish silently. Without this check, the\n\t\t// loss surfaces as a bare TypeError deep inside the first run().\n\t\tassertRepositoryDefinitionMembers(branded as Record<PropertyKey, unknown>);\n\t\tObject.defineProperty(branded, repositoryDefinitionBrand, {\n\t\t\tconfigurable: false,\n\t\t\tenumerable: false,\n\t\t\tvalue: true,\n\t\t\twritable: false,\n\t\t});\n\t\treturn Object.freeze(branded);\n\t};\n\treturn builder as unknown as Extract<\n\t\tTRepositoryPort,\n\t\tCallableValue\n\t> extends never\n\t\t? RepositoryDefinitionBuilder<TRepositoryPort>\n\t\t: never;\n}\n\n/** Application-facing repositories inferred from their adapter definitions. */\nexport type RepositoriesOf<TDefinitions> = {\n\t[K in keyof TDefinitions]: RepositoryFacadeOf<TDefinitions[K]>;\n};\n\n/**\n * Preserves each concrete repository definition while rejecting incomplete\n * entries, callable adapter results, and definitions whose transaction context\n * or aggregate event family does not belong to the Unit of Work that owns them.\n */\nexport type CompatibleRepositoryDefinitions<\n\tEvt extends AnyDomainEvent,\n\tTCtx,\n\tTDefinitions,\n> = {\n\t[K in keyof TDefinitions]: TDefinitions[K] extends RepositoryDefinition<\n\t\tinfer TDefinitionContext,\n\t\tinfer _TRepositoryPort,\n\t\tinfer TAggregate,\n\t\tinfer _TBaseline,\n\t\tinfer _TChangeSet,\n\t\tinfer _TRemoval\n\t>\n\t\t? TAggregate extends IAggregateRoot<Id<string>, infer TDefinitionEvent>\n\t\t\t? [TDefinitionEvent] extends [Evt]\n\t\t\t\t? TCtx extends TDefinitionContext\n\t\t\t\t\t? TDefinitions[K]\n\t\t\t\t\t: never\n\t\t\t\t: never\n\t\t\t: never\n\t\t: never;\n};\n\n/** @inline */\ntype RepositoryFacadeOf<TDefinition> = TDefinition extends RepositoryDefinition<\n\tinfer _TCtx,\n\tinfer TRepositoryPort,\n\tinfer _TAggregate,\n\tinfer _TBaseline,\n\tinfer _TChangeSet,\n\tinfer _TRemoval\n>\n\t? TRepositoryPort\n\t: never;\n\n/** Unit-of-Work-owned writes added to every application repository facade. */\nexport interface AggregateWriteRegistration<\n\tTAggregate extends IAggregateRoot<Id<string>, AnyDomainEvent>,\n> {\n\tadd(aggregate: TAggregate): void;\n\tupdate(aggregate: TAggregate): void;\n}\n\n/** Optional physical removal added only by an explicit repository definition. */\nexport interface PhysicalRemovalRegistration<\n\tTAggregate extends IAggregateRoot<Id<string>, AnyDomainEvent>,\n> {\n\tremove(aggregate: TAggregate): void;\n}\n\n/** Dependencies for {@link UnitOfWork}; the app-level singleton part. */\nexport interface UnitOfWorkDeps<\n\tEvt extends AnyDomainEvent,\n\tTCtx,\n\tTDefinitions extends Record<string, unknown>,\n> {\n\tscope: TransactionScope<TCtx>;\n\t/**\n\t * The write half of the outbox; see `WithCommitDeps.outbox` for the\n\t * required-vs-optional-bus asymmetry and the explicit opt-out\n\t * (`outboxWriterAcceptingEventLoss`).\n\t */\n\toutbox: OutboxWriter<Evt>;\n\tbus?: EventBus<Evt>;\n\t/** See `withCommit`: observer for post-commit `bus.publish` failures. */\n\tonPublishError?: (error: unknown, events: ReadonlyArray<Evt>) => void;\n\t/**\n\t * See `withCommit`: application-shell observer after acknowledgement.\n\t * The version argument is captured before any observer runs; the context\n\t * carries the bounded post-commit execution signal and deadline.\n\t */\n\tonPersisted?: (\n\t\taggregate: IAggregateRoot<Id<string>, Evt>,\n\t\tversion: Version,\n\t\tcontext: ExecutionContext,\n\t) => void | Promise<void>;\n\t/**\n\t * See `withCommit`: failure observer for internal post-commit\n\t * acknowledgement/disposal and the application-shell `onPersisted`\n\t * callback. Never rejects the committed write.\n\t */\n\tonPersistError?: (\n\t\terror: unknown,\n\t\taggregate: IAggregateRoot<Id<string>, Evt>,\n\t) => void;\n\t/**\n\t * See `withCommit`: one total budget shared by the complete post-commit\n\t * application phase. Default `30000`ms.\n\t */\n\tpostCommitTimeoutMs?: number;\n\trepositories: CompatibleRepositoryDefinitions<Evt, TCtx, TDefinitions>;\n}\n\n/**\n * Explicit-intent Unit of Work: one `run()` call is one application-level\n * write operation. All repository writes inside the callback share one\n * transaction and either persist completely or not at all.\n *\n * Built ON TOP of `withCommit` - the commit orchestration (event\n * harvest into the outbox inside the transaction, internal acknowledgement\n * after the commit, best-effort in-process publish last) is inherited,\n * not reimplemented. What this layer adds:\n *\n * - **Tx-bound repository adapters via a registry.** The callback receives\n * application-facing repository facades and never sees the raw transaction\n * or tracking capability.\n * - **Unit-of-Work-owned writes.** Standard `add`, `update`, and `remove`\n * methods register lifecycle intent. Adapter implementations with those\n * names are not invoked through the facade.\n * - **Lifecycle errors.** {@link NestedUnitOfWorkError},\n * {@link TransactionClosedError}, {@link CommitError},\n * {@link RollbackError}, {@link AggregateDeletedError}.\n *\n * - **A per-operation Identity Map and expected-version receipt.** Read paths\n * call `trackLoaded` before returning an aggregate. The Unit of Work then\n * owns the one-instance rule and the optimistic-concurrency expectation.\n * - **Persistence-last guard.** Once write intent is registered, a later\n * version or event-batch change rejects the operation before commit.\n *\n * Nested transactions, savepoints, and transaction joining remain outside\n * this boundary. One `run()` is one consistency transaction.\n *\n * **Instance discipline:** one instance owns one logical operation at\n * a time. `run()` while a run is active throws\n * {@link NestedUnitOfWorkError} - that covers genuine nesting AND two\n * concurrent requests sharing one instance, which is the same bug in\n * different clothes. Construct one `UnitOfWork` per operation\n * (construction stores one reference; the shareable singleton is the\n * deps object). Sequential reuse of an instance is fine.\n *\n * **Error pass-through:** an error thrown by the work callback (a\n * repository's `ConcurrencyConflictError`, a `DomainError`, anything)\n * is rethrown UNCHANGED - the unit of work never converts a concurrency\n * conflict into a generic error. Only the two failure modes the\n * callback cannot observe are wrapped: see {@link CommitError} and\n * {@link RollbackError}.\n *\n * @example\n * ```ts\n * const deps = {\n * scope: drizzleScope,\n * outbox: drizzleOutbox,\n * bus: eventBus,\n * repositories: {\n * restaurants: restaurantRepositoryDefinition,\n * },\n * };\n *\n * const uow = new UnitOfWork(deps);\n * const result = await uow.run(async ({ repositories }) => {\n * const restaurant = await repositories.restaurants.getById(id);\n * restaurant.changeOpeningHours(openingHours);\n * repositories.restaurants.update(restaurant);\n * return restaurant.id;\n * });\n * ```\n */\nexport class UnitOfWork<\n\tEvt extends AnyDomainEvent,\n\tTCtx,\n\tTDefinitions extends Record<string, unknown>,\n> {\n\tprivate _active = false;\n\n\tconstructor(private readonly deps: UnitOfWorkDeps<Evt, TCtx, TDefinitions>) {}\n\n\t/**\n\t * Execute one unit of work: open the transaction, hand the callback\n\t * tx-bound repositories, commit on resolve, roll back on throw,\n\t * run the post-commit lifecycle (acknowledge, observe, publish) for every\n\t * enrolled aggregate. Returns the callback's result.\n\t */\n\tpublic async run<R>(\n\t\twork: (\n\t\t\tcontext: UnitOfWorkContext<RepositoriesOf<TDefinitions>>,\n\t\t) => Promise<R>,\n\t\toptions?: RunOptions,\n\t): Promise<R> {\n\t\t// Pre-flight: an already-aborted caller rejects with the signal's\n\t\t// reason before opening a transaction (no callback runs). Placed\n\t\t// before the active-guard so a doubly-bad call (aborted signal on an\n\t\t// already-running instance) is reported as aborted rather than as a\n\t\t// nesting error. The `??` fallback mirrors event-bus.ts and guards a\n\t\t// non-spec polyfill whose `reason` is undefined.\n\t\tif (options?.signal?.aborted) {\n\t\t\tthrow abortReason(\n\t\t\t\toptions.signal,\n\t\t\t\t\"UnitOfWork.run aborted before opening a transaction\",\n\t\t\t);\n\t\t}\n\t\tif (this._active) {\n\t\t\tthrow new NestedUnitOfWorkError();\n\t\t}\n\t\tthis._active = true;\n\n\t\tlet session: Session<Evt> | undefined;\n\t\tlet workCompleted = false;\n\t\tlet workThrew = false;\n\t\tlet workError: unknown;\n\n\t\ttry {\n\t\t\treturn await withCommit<Evt, R, TCtx>(\n\t\t\t\t{\n\t\t\t\t\toutbox: this.deps.outbox,\n\t\t\t\t\tbus: this.deps.bus,\n\t\t\t\t\tscope: this.deps.scope,\n\t\t\t\t\tonPublishError: this.deps.onPublishError,\n\t\t\t\t\tonPersisted: this.deps.onPersisted,\n\t\t\t\t\tonPersistError: this.deps.onPersistError,\n\t\t\t\t\tpostCommitTimeoutMs: this.deps.postCommitTimeoutMs,\n\t\t\t\t\tsignal: options?.signal,\n\t\t\t\t},\n\t\t\t\tasync (tx, enrollment) => {\n\t\t\t\t\t// Fresh state per scope invocation: a TransactionScope that\n\t\t\t\t\t// retries its callback (serialization-failure retry wrappers)\n\t\t\t\t\t// re-runs this fn, and state from the rolled-back attempt\n\t\t\t\t\t// (enrollments, identity-map entries, error flags) must not\n\t\t\t\t\t// leak into the retry. The previous attempt's session is\n\t\t\t\t\t// closed so its leaked contexts turn loud.\n\t\t\t\t\tsession?.close();\n\t\t\t\t\tconst s = new Session<Evt>(enrollment);\n\t\t\t\t\tsession = s;\n\t\t\t\t\tworkCompleted = false;\n\t\t\t\t\tworkThrew = false;\n\t\t\t\t\tworkError = undefined;\n\n\t\t\t\t\tconst repositories = this.buildRepositories(tx, s);\n\t\t\t\t\tconst context = makeContext(repositories, s, options?.signal);\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst result = await work(context);\n\t\t\t\t\t\t// Validate tracking before sealing: a loaded aggregate that\n\t\t\t\t\t\t// changed without update intent would otherwise be lost.\n\t\t\t\t\t\t// Throws inside\n\t\t\t\t\t\t// the transaction, so the unit of work rolls back.\n\t\t\t\t\t\ts.assertReadyToCommit();\n\t\t\t\t\t\tawait s.flush(tx);\n\t\t\t\t\t\t// A flush may yield to the event loop. Re-check before the\n\t\t\t\t\t\t// transaction is allowed to commit so leaked concurrent work\n\t\t\t\t\t\t// cannot mutate an already registered aggregate mid-flush.\n\t\t\t\t\t\ts.assertReadyToCommit();\n\t\t\t\t\t\tworkCompleted = true;\n\t\t\t\t\t\t// Seal immediately: the aggregates snapshot below is what\n\t\t\t\t\t\t// gets harvested. A late registration from work still in\n\t\t\t\t\t\t// flight must throw\n\t\t\t\t\t\t// TransactionClosedError instead of being silently\n\t\t\t\t\t\t// accepted-but-never-harvested.\n\t\t\t\t\t\tconst commits = s.commitTokens;\n\t\t\t\t\t\ts.close();\n\t\t\t\t\t\treturn { result, commits };\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\tworkThrew = true;\n\t\t\t\t\t\tworkError = error;\n\t\t\t\t\t\tthrow error;\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tthrow classifyRunError(error, {\n\t\t\t\tworkThrew,\n\t\t\t\tworkCompleted,\n\t\t\t\tworkError,\n\t\t\t\tsignal: options?.signal,\n\t\t\t});\n\t\t} finally {\n\t\t\tsession?.close();\n\t\t\tthis._active = false;\n\t\t}\n\t}\n\n\tprivate buildRepositories(\n\t\ttx: TCtx,\n\t\tsession: Session<Evt>,\n\t): RepositoriesOf<TDefinitions> {\n\t\tconst repositories = {} as RepositoriesOf<TDefinitions>;\n\t\tfor (const key of Object.keys(this.deps.repositories) as Array<\n\t\t\tkeyof TDefinitions\n\t\t>) {\n\t\t\tconst candidate = this.deps.repositories[key] as unknown;\n\t\t\tif (!isRepositoryDefinition(candidate)) {\n\t\t\t\tthrow new InvalidRepositoryDefinitionError(String(key));\n\t\t\t}\n\t\t\tconst definition = candidate as RuntimeRepositoryDefinition<Evt, TCtx>;\n\t\t\tconst adapter = definition.create(tx, session.trackingFor(definition));\n\t\t\trepositories[key] = bindRepositoryWrites(\n\t\t\t\tadapter,\n\t\t\t\tsession,\n\t\t\t\tdefinition,\n\t\t\t\tString(key),\n\t\t\t) as RepositoriesOf<TDefinitions>[typeof key];\n\t\t}\n\t\treturn repositories;\n\t}\n}\n\nfunction isRepositoryDefinition(value: unknown): value is object {\n\tif (value === null || typeof value !== \"object\") return false;\n\ttry {\n\t\tconst marker = Reflect.getOwnPropertyDescriptor(\n\t\t\tvalue,\n\t\t\trepositoryDefinitionBrand,\n\t\t);\n\t\treturn (\n\t\t\tmarker?.value === true &&\n\t\t\tmarker.configurable === false &&\n\t\t\tmarker.enumerable === false &&\n\t\t\tmarker.writable === false &&\n\t\t\tObject.isFrozen(value)\n\t\t);\n\t} catch {\n\t\treturn false;\n\t}\n}\n\n/**\n * Builds the application-facing repository facade. Standard lifecycle writes\n * are always supplied by the Unit of Work; similarly named adapter methods are\n * never invoked. Other methods are bound to the adapter so classes with private\n * fields keep their normal receiver.\n */\nfunction bindRepositoryWrites<TRepository, Evt extends AnyDomainEvent>(\n\tadapter: TRepository,\n\tsession: Session<Evt>,\n\tdefinition: RuntimePersistenceDefinition<Evt>,\n\trepository: string,\n): TRepository {\n\tif (adapter === null || typeof adapter !== \"object\") {\n\t\tthrow new InvalidRepositoryAdapterError(\n\t\t\trepository,\n\t\t\tadapter === null ? \"null\" : typeof adapter,\n\t\t);\n\t}\n\n\tconst state = createRepositoryFacadeState(\n\t\tadapter as object,\n\t\tsession,\n\t\tdefinition,\n\t);\n\tinstallRepositoryLifecycleOperations(state);\n\tforwardAdapterOwnProperties(state);\n\treturn new Proxy(\n\t\tstate.target,\n\t\tcreateRepositoryFacadeHandler(state),\n\t) as TRepository;\n}\n\nconst REPOSITORY_LIFECYCLE_OPERATIONS = [\"add\", \"update\", \"remove\"] as const;\n\ninterface GuardedMethodCacheEntry {\n\t/** The source function the wrapper was built over; identity-checked on\n\t * every read so a self-mutated adapter method cannot serve stale. */\n\treadonly sourceMethod: (...args: unknown[]) => unknown;\n\treadonly guarded: (...args: unknown[]) => unknown;\n}\n\ninterface RepositoryFacadeState<Evt extends AnyDomainEvent> {\n\treadonly source: object;\n\treadonly target: object;\n\treadonly session: Session<Evt>;\n\treadonly definition: RuntimePersistenceDefinition<Evt>;\n\treadonly methodCache: Map<PropertyKey, GuardedMethodCacheEntry>;\n\treadonly forwardedOwnProperties: Set<PropertyKey>;\n\treadonly writes: Set<PropertyKey>;\n}\n\nfunction createRepositoryFacadeState<Evt extends AnyDomainEvent>(\n\tsource: object,\n\tsession: Session<Evt>,\n\tdefinition: RuntimePersistenceDefinition<Evt>,\n): RepositoryFacadeState<Evt> {\n\treturn {\n\t\tsource,\n\t\ttarget: Object.create(Reflect.getPrototypeOf(source)) as object,\n\t\tsession,\n\t\tdefinition,\n\t\tmethodCache: new Map(),\n\t\tforwardedOwnProperties: new Set(),\n\t\twrites: new Set(),\n\t};\n}\n\nfunction repositoryOperationName(property: PropertyKey): string {\n\tconst name =\n\t\ttypeof property === \"symbol\"\n\t\t\t? (property.description ?? property.toString())\n\t\t\t: property;\n\treturn `repository.${name}`;\n}\n\nfunction isRepositoryLifecycleOperation(property: PropertyKey): boolean {\n\treturn REPOSITORY_LIFECYCLE_OPERATIONS.includes(\n\t\tproperty as (typeof REPOSITORY_LIFECYCLE_OPERATIONS)[number],\n\t);\n}\n\n/**\n * Own-or-inherited presence that stops BEFORE `Object.prototype`: members\n * every object inherits (`toString`, `valueOf`, `constructor`) are language\n * plumbing, not repository surface, and must not trip the facade's\n * session-open assertion.\n */\nfunction hasMemberBelowObjectPrototype(\n\tobject: object,\n\tproperty: PropertyKey,\n): boolean {\n\tlet current: object | null = object;\n\twhile (current !== null && current !== Object.prototype) {\n\t\tif (Reflect.getOwnPropertyDescriptor(current, property)) return true;\n\t\tcurrent = Reflect.getPrototypeOf(current);\n\t}\n\treturn false;\n}\n\nfunction readRepositorySource<Evt extends AnyDomainEvent>(\n\tstate: RepositoryFacadeState<Evt>,\n\tproperty: PropertyKey,\n): unknown {\n\tstate.session.assertOpen(repositoryOperationName(property));\n\tconst value = Reflect.get(state.source, property, state.source);\n\tif (typeof value !== \"function\") return value;\n\t// Cache validity is keyed on the CURRENT source function, not the\n\t// property name alone: adapter methods run with `this` bound to the raw\n\t// source, so a lazy-init self-assignment replaces the method without any\n\t// proxy trap firing. A name-only cache would keep serving the wrapper\n\t// closed over the replaced function for the rest of the run.\n\tconst cached = state.methodCache.get(property);\n\tif (cached && cached.sourceMethod === value) return cached.guarded;\n\tconst sourceMethod = value as (...args: unknown[]) => unknown;\n\tconst guarded = (...args: unknown[]): unknown => {\n\t\tstate.session.assertOpen(repositoryOperationName(property));\n\t\treturn Reflect.apply(sourceMethod, state.source, args);\n\t};\n\tstate.methodCache.set(property, { sourceMethod, guarded });\n\treturn guarded;\n}\n\nfunction defineForwardedRepositoryProperty<Evt extends AnyDomainEvent>(\n\tstate: RepositoryFacadeState<Evt>,\n\tproperty: PropertyKey,\n\tdescriptor: PropertyDescriptor,\n): void {\n\tObject.defineProperty(state.target, property, {\n\t\tconfigurable: true,\n\t\tenumerable: descriptor.enumerable ?? false,\n\t\tget: () => readRepositorySource(state, property),\n\t\tset:\n\t\t\t(\"value\" in descriptor && descriptor.writable) || descriptor.set\n\t\t\t\t? (value: unknown) => {\n\t\t\t\t\t\tstate.session.assertOpen(repositoryOperationName(property));\n\t\t\t\t\t\tif (!Reflect.set(state.source, property, value, state.source)) {\n\t\t\t\t\t\t\tthrow new TypeError(\n\t\t\t\t\t\t\t\t`Cannot assign to repository property ${String(property)}`,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t: undefined,\n\t});\n\tstate.forwardedOwnProperties.add(property);\n}\n\nfunction installRepositoryLifecycleOperations<Evt extends AnyDomainEvent>(\n\tstate: RepositoryFacadeState<Evt>,\n): void {\n\tconst operations = state.definition.physicalRemoval\n\t\t? REPOSITORY_LIFECYCLE_OPERATIONS\n\t\t: REPOSITORY_LIFECYCLE_OPERATIONS.slice(0, 2);\n\tfor (const operation of operations) {\n\t\tstate.writes.add(operation);\n\t\tObject.defineProperty(state.target, operation, {\n\t\t\tconfigurable: false,\n\t\t\tenumerable: false,\n\t\t\twritable: false,\n\t\t\tvalue: (aggregate: unknown) => {\n\t\t\t\tstate.session.assertOpen(repositoryOperationName(operation));\n\t\t\t\tstate.session[operation](\n\t\t\t\t\taggregate as IAggregateRoot<Id<string>, Evt>,\n\t\t\t\t\tstate.definition,\n\t\t\t\t);\n\t\t\t},\n\t\t});\n\t}\n}\n\nfunction forwardAdapterOwnProperties<Evt extends AnyDomainEvent>(\n\tstate: RepositoryFacadeState<Evt>,\n): void {\n\tfor (const property of Reflect.ownKeys(state.source)) {\n\t\tif (isRepositoryLifecycleOperation(property)) continue;\n\t\tconst descriptor = Reflect.getOwnPropertyDescriptor(state.source, property);\n\t\tif (descriptor) {\n\t\t\tdefineForwardedRepositoryProperty(state, property, descriptor);\n\t\t}\n\t}\n}\n\nfunction createRepositoryFacadeHandler<Evt extends AnyDomainEvent>(\n\tstate: RepositoryFacadeState<Evt>,\n): ProxyHandler<object> {\n\treturn {\n\t\tget: (target, property, receiver) => {\n\t\t\t// Language-level probes are not repository operations: promise\n\t\t\t// resolution reads `then` on any value returned from run(),\n\t\t\t// JSON.stringify probes `toJSON`, string interpolation reads\n\t\t\t// `toString`, and inspection utilities read well-known symbols.\n\t\t\t// One principled rule instead of one exemption per discovered\n\t\t\t// probe: only a property present BELOW Object.prototype is\n\t\t\t// repository surface and gets the session-open assertion.\n\t\t\t// Everything else is language plumbing and answers normally, so\n\t\t\t// logging a leaked facade after close cannot mask the original\n\t\t\t// failure. Member reads keep the loud TransactionClosedError\n\t\t\t// (a probe cannot leak state; a member read can).\n\t\t\tif (\n\t\t\t\t!hasMemberBelowObjectPrototype(target, property) &&\n\t\t\t\t!hasMemberBelowObjectPrototype(state.source, property)\n\t\t\t) {\n\t\t\t\treturn Reflect.get(target, property, receiver);\n\t\t\t}\n\t\t\tstate.session.assertOpen(repositoryOperationName(property));\n\t\t\tconst own = Reflect.getOwnPropertyDescriptor(target, property);\n\t\t\tif (own) return Reflect.get(target, property, receiver);\n\t\t\tif (property === \"remove\") return undefined;\n\t\t\treturn readRepositorySource(state, property);\n\t\t},\n\t\tset: (target, property, value, receiver) =>\n\t\t\tsetRepositoryFacadeProperty(state, target, property, value, receiver),\n\t\thas: (target, property) => {\n\t\t\tstate.session.assertOpen(repositoryOperationName(property));\n\t\t\treturn (\n\t\t\t\tstate.writes.has(property) ||\n\t\t\t\t(property !== \"remove\" &&\n\t\t\t\t\t(Reflect.has(target, property) ||\n\t\t\t\t\t\tReflect.has(state.source, property)))\n\t\t\t);\n\t\t},\n\t\tdefineProperty: (target, property, descriptor) =>\n\t\t\tdefineRepositoryFacadeProperty(state, target, property, descriptor),\n\t\tdeleteProperty: (target, property) =>\n\t\t\tdeleteRepositoryFacadeProperty(state, target, property),\n\t};\n}\n\nfunction setRepositoryFacadeProperty<Evt extends AnyDomainEvent>(\n\tstate: RepositoryFacadeState<Evt>,\n\ttarget: object,\n\tproperty: PropertyKey,\n\tvalue: unknown,\n\treceiver: unknown,\n): boolean {\n\tstate.session.assertOpen(repositoryOperationName(property));\n\tif (isRepositoryLifecycleOperation(property)) return false;\n\tif (Reflect.getOwnPropertyDescriptor(target, property)) {\n\t\tconst set = Reflect.set(target, property, value, receiver);\n\t\tif (set) state.methodCache.delete(property);\n\t\treturn set;\n\t}\n\tif (!Reflect.isExtensible(target)) return false;\n\tconst set = Reflect.set(state.source, property, value, state.source);\n\tconst descriptor = Reflect.getOwnPropertyDescriptor(state.source, property);\n\tif (set && descriptor) {\n\t\tdefineForwardedRepositoryProperty(state, property, descriptor);\n\t}\n\t// Every successful set invalidates the guarded-method cache, matching the\n\t// own-descriptor and delete paths: a cached wrapper closed over the\n\t// replaced function must not outlive the override (test spies, strategy\n\t// swaps).\n\tif (set) state.methodCache.delete(property);\n\treturn set;\n}\n\nfunction defineRepositoryFacadeProperty<Evt extends AnyDomainEvent>(\n\tstate: RepositoryFacadeState<Evt>,\n\ttarget: object,\n\tproperty: PropertyKey,\n\tdescriptor: PropertyDescriptor,\n): boolean {\n\tstate.session.assertOpen(repositoryOperationName(property));\n\tif (\n\t\tisRepositoryLifecycleOperation(property) &&\n\t\t!Reflect.getOwnPropertyDescriptor(target, property)\n\t) {\n\t\treturn false;\n\t}\n\tconst current = Reflect.getOwnPropertyDescriptor(target, property);\n\tif (!Reflect.defineProperty(target, property, descriptor)) return false;\n\tconst next = Reflect.getOwnPropertyDescriptor(target, property);\n\tif (\n\t\tstate.forwardedOwnProperties.has(property) &&\n\t\t(current?.get !== next?.get || current?.set !== next?.set)\n\t) {\n\t\tstate.forwardedOwnProperties.delete(property);\n\t}\n\treturn true;\n}\n\nfunction deleteRepositoryFacadeProperty<Evt extends AnyDomainEvent>(\n\tstate: RepositoryFacadeState<Evt>,\n\ttarget: object,\n\tproperty: PropertyKey,\n): boolean {\n\tstate.session.assertOpen(repositoryOperationName(property));\n\tif (isRepositoryLifecycleOperation(property)) return false;\n\tconst targetDescriptor = Reflect.getOwnPropertyDescriptor(target, property);\n\tif (targetDescriptor && !state.forwardedOwnProperties.has(property)) {\n\t\treturn Reflect.deleteProperty(target, property);\n\t}\n\tconst sourceDescriptor = Reflect.getOwnPropertyDescriptor(\n\t\tstate.source,\n\t\tproperty,\n\t);\n\tif (\n\t\ttargetDescriptor?.configurable === false ||\n\t\tsourceDescriptor?.configurable === false\n\t) {\n\t\treturn false;\n\t}\n\tif (!Reflect.deleteProperty(state.source, property)) return false;\n\tif (targetDescriptor && !Reflect.deleteProperty(target, property))\n\t\treturn false;\n\tstate.forwardedOwnProperties.delete(property);\n\tstate.methodCache.delete(property);\n\treturn true;\n}\n\ntype AggregateLifecycle = \"new\" | \"loaded\";\n\n/**\n * The immutable receipt one add/update/remove registration freezes: intent,\n * exact version and event batch, the sealed persistence baseline, and the\n * derived change set. It exists as ONE optional unit so registration,\n * rollback, and flush cannot half-apply it; `registration === undefined`\n * means \"tracked but no write registered\".\n */\ninterface WriteRegistration<Evt extends AnyDomainEvent> {\n\treadonly intent: AggregateWriteIntent;\n\treadonly version: Version;\n\treadonly events: ReadonlyArray<PendingDomainEvent<Evt>>;\n\treadonly baseline: PersistenceBaseline<\n\t\tIAggregateRoot<Id<string>, Evt>,\n\t\tunknown\n\t>;\n\treadonly changes: PersistenceChanges<unknown>;\n}\n\ninterface TrackedAggregate<Evt extends AnyDomainEvent> {\n\treadonly aggregate: IAggregateRoot<Id<string>, Evt>;\n\treadonly lifecycle: AggregateLifecycle;\n\treadonly expectedVersion: Version | undefined;\n\treadonly definition: RuntimePersistenceDefinition<Evt>;\n\treadonly baseline: PersistenceBaseline<\n\t\tIAggregateRoot<Id<string>, Evt>,\n\t\tunknown\n\t>;\n\tregistration?: WriteRegistration<Evt>;\n}\n\n/** Internal session implementation; closed by `run()`'s finally. */\nclass Session<Evt extends AnyDomainEvent> {\n\t// Read tracking order is independent of write registration order. Flush\n\t// follows this list so adapters observe the same explicit order as the use\n\t// case's add/update/remove calls. Enrollment and removal state are NOT\n\t// separate collections: both derive from each entry's registration, so\n\t// the bookkeeping cannot drift apart.\n\tprivate readonly _registeredWrites: TrackedAggregate<Evt>[] = [];\n\tprivate readonly _commitTokens = new Set<AggregateCommitToken<Evt>>();\n\tprivate readonly _identityMap = new IdentityMap();\n\t// What adapters receive: the typed read-only view, enforced at runtime.\n\t// Handing out the map itself would expose set/delete/clear to JavaScript\n\t// callers, and a stray clear() erases deletion tombstones and the\n\t// pending-event baselines behind UnenrolledChangesError.\n\tprivate readonly _identityMapView = Object.freeze({\n\t\tget: this._identityMap.get.bind(this._identityMap),\n\t\thas: this._identityMap.has.bind(this._identityMap),\n\t\tisDeleted: this._identityMap.isDeleted.bind(this._identityMap),\n\t}) as UnitOfWorkIdentityMap;\n\tprivate readonly _trackingByAggregate = new WeakMap<\n\t\tIAggregateRoot<Id<string>, Evt>,\n\t\tTrackedAggregate<Evt>\n\t>();\n\tprivate readonly _trackedAggregates = new Set<TrackedAggregate<Evt>>();\n\tprivate _closed = false;\n\n\tconstructor(private readonly commitEnrollment: CommitEnrollment<Evt>) {}\n\n\tpublic get identityMap(): UnitOfWorkIdentityMap {\n\t\tthis.assertOpen(\"tracking.identityMap\");\n\t\treturn this._identityMapView;\n\t}\n\n\tpublic trackingFor(\n\t\tdefinition: RuntimePersistenceDefinition<Evt>,\n\t): RepositoryTracking<IAggregateRoot<Id<string>, Evt>> {\n\t\tconst session = this;\n\t\treturn Object.freeze({\n\t\t\tget identityMap() {\n\t\t\t\treturn session.identityMap;\n\t\t\t},\n\t\t\ttrackLoaded: (aggregate: IAggregateRoot<Id<string>, Evt>) =>\n\t\t\t\tsession.trackLoaded(aggregate, definition),\n\t\t});\n\t}\n\n\t/** The registration of an instance, or undefined when none is tracked. */\n\tprivate registrationOf(\n\t\taggregate: object,\n\t): WriteRegistration<Evt> | undefined {\n\t\treturn this._trackingByAggregate.get(\n\t\t\taggregate as IAggregateRoot<Id<string>, Evt>,\n\t\t)?.registration;\n\t}\n\n\t/** Whether THIS instance registered a remove in this session. */\n\tprivate isRemovedInstance(aggregate: object): boolean {\n\t\treturn this.registrationOf(aggregate)?.intent === \"remove\";\n\t}\n\n\tprivate trackLoaded<TAggregate extends IAggregateRoot<Id<string>, Evt>>(\n\t\taggregate: TAggregate,\n\t\tdefinition: RuntimePersistenceDefinition<Evt>,\n\t): TAggregate {\n\t\tthis.assertOpen(\"tracking.trackLoaded\");\n\t\t// Ownership is checked BEFORE identity-map registration: a rejected\n\t\t// instance must not stay registered under the second definition's\n\t\t// class key with no tracking entry behind it.\n\t\tconst existing = this._trackingByAggregate.get(aggregate);\n\t\tif (existing && existing.definition !== definition) {\n\t\t\tthrow new AggregateTrackingError(\n\t\t\t\tString(aggregate.id),\n\t\t\t\t\"load\",\n\t\t\t\t\"different_repository\",\n\t\t\t\texisting.registration?.intent,\n\t\t\t);\n\t\t}\n\t\tthis._identityMap.set(definition.aggregate, aggregate.id, aggregate);\n\t\tif (existing) return aggregate;\n\n\t\tconst entry: TrackedAggregate<Evt> = {\n\t\t\taggregate,\n\t\t\tlifecycle: \"loaded\",\n\t\t\texpectedVersion: aggregate.version,\n\t\t\tdefinition,\n\t\t\tbaseline: capturePersistenceBaseline(definition.persistence, aggregate),\n\t\t};\n\t\tthis._trackingByAggregate.set(aggregate, entry);\n\t\tthis._trackedAggregates.add(entry);\n\t\treturn aggregate;\n\t}\n\n\tpublic add(\n\t\taggregate: IAggregateRoot<Id<string>, Evt>,\n\t\tdefinition: RuntimePersistenceDefinition<Evt>,\n\t): void {\n\t\tthis.assertOpen(\"repository.add\");\n\t\tthis.assertNotRemoved(aggregate, definition);\n\t\tconst existing = this._trackingByAggregate.get(aggregate);\n\t\tif (existing && existing.definition !== definition) {\n\t\t\tthrow new AggregateTrackingError(\n\t\t\t\tString(aggregate.id),\n\t\t\t\t\"add\",\n\t\t\t\t\"different_repository\",\n\t\t\t\texisting.registration?.intent,\n\t\t\t);\n\t\t}\n\t\tif (existing?.lifecycle === \"loaded\") {\n\t\t\tthrow new AggregateTrackingError(\n\t\t\t\tString(aggregate.id),\n\t\t\t\t\"add\",\n\t\t\t\t\"loaded_as_new\",\n\t\t\t\texisting.registration?.intent,\n\t\t\t);\n\t\t}\n\n\t\tlet entry = existing;\n\t\tconst newlyTracked = !entry;\n\t\tif (!entry) {\n\t\t\tthis._identityMap.set(definition.aggregate, aggregate.id, aggregate);\n\t\t\tentry = {\n\t\t\t\taggregate,\n\t\t\t\tlifecycle: \"new\",\n\t\t\t\texpectedVersion: undefined,\n\t\t\t\tdefinition,\n\t\t\t\tbaseline: insertPersistenceBaseline(definition.persistence),\n\t\t\t};\n\t\t\tthis._trackingByAggregate.set(aggregate, entry);\n\t\t\tthis._trackedAggregates.add(entry);\n\t\t}\n\n\t\ttry {\n\t\t\tthis.registerWrite(entry, \"add\", definition);\n\t\t} catch (error) {\n\t\t\t// A failed add must not leave a phantom: without this rollback,\n\t\t\t// findById would serve the never-persisted instance from the\n\t\t\t// identity map while the commit-readiness guard ignores \"new\"\n\t\t\t// lifecycle entries, so the transaction would commit without a\n\t\t\t// write for it.\n\t\t\tif (newlyTracked) {\n\t\t\t\tthis._trackingByAggregate.delete(aggregate);\n\t\t\t\tthis._trackedAggregates.delete(entry);\n\t\t\t\tthis._identityMap.discard(definition.aggregate, aggregate.id, aggregate);\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tpublic update(\n\t\taggregate: IAggregateRoot<Id<string>, Evt>,\n\t\tdefinition: RuntimePersistenceDefinition<Evt>,\n\t): void {\n\t\tthis.assertOpen(\"repository.update\");\n\t\tconst entry = this.loadedEntryFor(aggregate, \"update\", definition);\n\t\tthis.registerWrite(entry, \"update\", definition);\n\t}\n\n\tpublic remove(\n\t\taggregate: IAggregateRoot<Id<string>, Evt>,\n\t\tdefinition: RuntimePersistenceDefinition<Evt>,\n\t): void {\n\t\tthis.assertOpen(\"repository.remove\");\n\t\t// Idempotent by reference, like add and update: a repeated remove of\n\t\t// the SAME instance re-declares the same final lifecycle outcome\n\t\t// (collection semantics; the enrollment layer already returns the\n\t\t// same token for a repeat enrollDeleted). The deletion-finality gate\n\t\t// stays sharp for everything else: add, update, and trackLoaded\n\t\t// after remove, and any OTHER instance with the same id, still\n\t\t// reject.\n\t\tconst entry = this._trackingByAggregate.get(aggregate);\n\t\tif (this.isRemovedInstance(aggregate) && entry?.definition === definition) {\n\t\t\treturn;\n\t\t}\n\t\tconst loaded = this.loadedEntryFor(aggregate, \"remove\", definition);\n\t\tthis.registerWrite(loaded, \"remove\", definition);\n\t}\n\n\t/** Registers persistence intent and commit enrollment as one operation. */\n\tprivate registerWrite(\n\t\tentry: TrackedAggregate<Evt>,\n\t\tintent: AggregateWriteIntent,\n\t\tdefinition: RuntimePersistenceDefinition<Evt>,\n\t): void {\n\t\tconst newlyRegistered = this.registerIntent(entry, intent);\n\t\ttry {\n\t\t\tif (intent === \"remove\") {\n\t\t\t\tthis.registerRemovedCommit(\n\t\t\t\t\tentry.aggregate,\n\t\t\t\t\tdefinition,\n\t\t\t\t\tentry.expectedVersion,\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tthis.registerSavedCommit(\n\t\t\t\t\tentry.aggregate,\n\t\t\t\t\tdefinition,\n\t\t\t\t\tentry.expectedVersion,\n\t\t\t\t);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tif (newlyRegistered) this.rollbackIntentRegistration(entry);\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tprivate loadedEntryFor(\n\t\taggregate: IAggregateRoot<Id<string>, Evt>,\n\t\toperation: \"update\" | \"remove\",\n\t\tdefinition: RuntimePersistenceDefinition<Evt>,\n\t): TrackedAggregate<Evt> {\n\t\tthis.assertNotRemoved(aggregate, definition);\n\t\tconst entry = this._trackingByAggregate.get(aggregate);\n\t\t// Repository-ownership violations report as such on every operation:\n\t\t// add and trackLoaded already use different_repository, and code\n\t\t// branching on the machine-readable reason must not get not_loaded\n\t\t// for the identical violation on the update/remove path.\n\t\tif (entry && entry.definition !== definition) {\n\t\t\tthrow new AggregateTrackingError(\n\t\t\t\tString(aggregate.id),\n\t\t\t\toperation,\n\t\t\t\t\"different_repository\",\n\t\t\t\tentry.registration?.intent,\n\t\t\t);\n\t\t}\n\t\t// An add()-registered aggregate IS tracked, just not \"loaded\": report\n\t\t// the real conflict with the registered intent. The not_loaded advice\n\t\t// (\"load it through the repository\") is impossible for an aggregate\n\t\t// that has no row yet and would actively mislead.\n\t\tif (\n\t\t\tentry &&\n\t\t\tentry.lifecycle === \"new\" &&\n\t\t\tentry.definition === definition\n\t\t) {\n\t\t\tthrow new AggregateTrackingError(\n\t\t\t\tString(aggregate.id),\n\t\t\t\toperation,\n\t\t\t\t\"conflicting_intent\",\n\t\t\t\tentry.registration?.intent,\n\t\t\t);\n\t\t}\n\t\tif (\n\t\t\t!entry ||\n\t\t\tentry.lifecycle !== \"loaded\" ||\n\t\t\tentry.definition !== definition\n\t\t) {\n\t\t\tthrow new AggregateTrackingError(\n\t\t\t\tString(aggregate.id),\n\t\t\t\toperation,\n\t\t\t\t\"not_loaded\",\n\t\t\t\tentry?.registration?.intent,\n\t\t\t);\n\t\t}\n\t\treturn entry;\n\t}\n\n\tprivate assertNotRemoved(\n\t\taggregate: IAggregateRoot<Id<string>, Evt>,\n\t\tdefinition: RuntimePersistenceDefinition<Evt>,\n\t): void {\n\t\tif (this._identityMap.isDeleted(definition.aggregate, aggregate.id)) {\n\t\t\tthrow new AggregateDeletedError(String(aggregate.id));\n\t\t}\n\t}\n\n\tprivate registerIntent(\n\t\tentry: TrackedAggregate<Evt>,\n\t\tintent: AggregateWriteIntent,\n\t): boolean {\n\t\tif (entry.registration !== undefined) {\n\t\t\tif (entry.registration.intent !== intent) {\n\t\t\t\tthrow new AggregateTrackingError(\n\t\t\t\t\tString(entry.aggregate.id),\n\t\t\t\t\tintent,\n\t\t\t\t\t\"conflicting_intent\",\n\t\t\t\t\tentry.registration.intent,\n\t\t\t\t);\n\t\t\t}\n\t\t\tthis.assertUnchangedAfterRegistration(entry);\n\t\t\treturn false;\n\t\t}\n\n\t\tentry.registration = Object.freeze({\n\t\t\tintent,\n\t\t\tversion: entry.aggregate.version,\n\t\t\t// Already a frozen detached copy from the pendingEvents getter.\n\t\t\tevents: entry.aggregate.pendingEvents,\n\t\t\tbaseline: recapturePersistenceBaseline(entry.baseline, entry.aggregate),\n\t\t\tchanges: derivePersistenceChanges(entry.baseline, entry.aggregate),\n\t\t});\n\t\tthis._registeredWrites.push(entry);\n\t\treturn true;\n\t}\n\n\t/** Restores the pre-registration state when commit enrollment rejects. */\n\tprivate rollbackIntentRegistration(entry: TrackedAggregate<Evt>): void {\n\t\tconst index = this._registeredWrites.lastIndexOf(entry);\n\t\tif (index >= 0) this._registeredWrites.splice(index, 1);\n\t\tdelete entry.registration;\n\t}\n\n\tprivate assertUnchangedAfterRegistration(entry: TrackedAggregate<Evt>): void {\n\t\tconst registration = entry.registration;\n\t\tif (registration === undefined) return;\n\t\tconst currentEvents = entry.aggregate.pendingEvents;\n\t\t// Capture-to-capture drift, NOT changes().isEmpty(): the\n\t\t// PersistenceModel contract permits full-replacement change sets that\n\t\t// are never empty, so a non-empty change set proves nothing about\n\t\t// mutation after registration.\n\t\tconst persistenceChanged = persistenceProjectionDrifted(\n\t\t\tregistration.baseline,\n\t\t\tentry.aggregate,\n\t\t);\n\t\tconst sameEvents =\n\t\t\tcurrentEvents.length === registration.events.length &&\n\t\t\tcurrentEvents.every(\n\t\t\t\t(event, index) => event === registration.events[index],\n\t\t\t);\n\t\tif (\n\t\t\tregistration.version !== entry.aggregate.version ||\n\t\t\t!sameEvents ||\n\t\t\tpersistenceChanged\n\t\t) {\n\t\t\tthrow new AggregateTrackingError(\n\t\t\t\tString(entry.aggregate.id),\n\t\t\t\t\"commit\",\n\t\t\t\t\"mutated_after_registration\",\n\t\t\t\tregistration.intent,\n\t\t\t);\n\t\t}\n\t}\n\n\tprivate registerSavedCommit(\n\t\taggregate: IAggregateRoot<Id<string>, Evt>,\n\t\tdefinition: RuntimePersistenceDefinition<Evt>,\n\t\texpectedVersion: Version | undefined,\n\t): AggregateCommitToken<Evt> {\n\t\tthis.assertOpen(\"repository.add/update\");\n\t\t// Two gates, one invariant: the registration check catches the same\n\t\t// reference; the identity-map tombstone (keyed on the instance's\n\t\t// concrete class) catches a DIFFERENT instance with the same\n\t\t// type+id: e.g. one re-created via the static factory after the\n\t\t// delete. Both mean \"deleted is final within this operation\".\n\t\tif (\n\t\t\tthis.isRemovedInstance(aggregate) ||\n\t\t\tthis._identityMap.isDeleted(definition.aggregate, aggregate.id)\n\t\t) {\n\t\t\tthrow new AggregateDeletedError(String(aggregate.id));\n\t\t}\n\t\tconst token = this.commitEnrollment.enrollSaved(aggregate, {\n\t\t\texpectedVersion,\n\t\t});\n\t\tthis._commitTokens.add(token);\n\t\treturn token;\n\t}\n\n\tprivate registerRemovedCommit(\n\t\taggregate: IAggregateRoot<Id<string>, Evt>,\n\t\tdefinition: RuntimePersistenceDefinition<Evt>,\n\t\texpectedVersion: Version | undefined,\n\t): AggregateCommitToken<Evt> {\n\t\tthis.assertOpen(\"repository.remove\");\n\t\tconst token = this.commitEnrollment.enrollDeleted(aggregate, {\n\t\t\texpectedVersion,\n\t\t});\n\t\t// One call does ALL the deletion bookkeeping: the identity-map\n\t\t// entry is removed and tombstoned automatically (keyed on the\n\t\t// instance's concrete class), so repositories do not need a\n\t\t// second manual identityMap.delete() call; a forgotten leg of a\n\t\t// two-call protocol would silently weaken the deletion gate. The\n\t\t// removed state itself derives from the entry's registration.\n\t\t// Assumption (documented on IdentityMap): repositories key the\n\t\t// map with the same concrete class their factories produce.\n\t\t// Deleted aggregates stay in the harvest set: their recorded\n\t\t// deletion events must reach the outbox (repository.md, hard-\n\t\t// delete with event harvest). withCommit receives them in the\n\t\t// deleted token disposition, so the saved-only application observer\n\t\t// never fires for a deletion.\n\t\tthis._identityMap.delete(definition.aggregate, aggregate.id);\n\t\tthis._commitTokens.add(token);\n\t\treturn token;\n\t}\n\n\t/**\n\t * End-of-run safety net. A loaded aggregate whose version or pending event\n\t * batch changed without `update` intent would otherwise be silently lost.\n\t * An aggregate that changed after registration could persist state and\n\t * events from different moments. Both violations reject inside the\n\t * transaction.\n\t */\n\tpublic assertReadyToCommit(): void {\n\t\tfor (const entry of this._trackedAggregates) {\n\t\t\tif (entry.registration !== undefined) {\n\t\t\t\tthis.assertUnchangedAfterRegistration(entry);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t// Capture-to-capture drift against the load-time baseline: a\n\t\t\t// full-replacement model's changes() is never empty, which would\n\t\t\t// misreport every merely-loaded aggregate as unenrolled changes.\n\t\t\tif (\n\t\t\t\tentry.lifecycle === \"loaded\" &&\n\t\t\t\t(entry.aggregate.version !== entry.expectedVersion ||\n\t\t\t\t\tpersistenceProjectionDrifted(entry.baseline, entry.aggregate))\n\t\t\t) {\n\t\t\t\tthrow new UnenrolledChangesError(String(entry.aggregate.id));\n\t\t\t}\n\t\t}\n\n\t\tfor (const instance of this._identityMap.instancesWithNewPendingEvents()) {\n\t\t\t// Any registration (add, update, or remove) means the instance is\n\t\t\t// enrolled and its batch will be harvested.\n\t\t\tif (\n\t\t\t\tinstance !== null &&\n\t\t\t\ttypeof instance === \"object\" &&\n\t\t\t\tthis.registrationOf(instance) !== undefined\n\t\t\t) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t// Events were recorded on a loaded aggregate after it was\n\t\t\t// registered, yet it has no write intent: a forgotten update whose\n\t\t\t// events would be silently dropped.\n\t\t\tconst id = (instance as { id?: unknown }).id;\n\t\t\tthrow new UnenrolledChangesError(String(id));\n\t\t}\n\t}\n\n\t/** Flushes every registered receipt in deterministic registration order. */\n\tpublic async flush(transaction: unknown): Promise<void> {\n\t\tthis.assertOpen(\"unitOfWork.flush\");\n\t\tfor (const entry of this._registeredWrites) {\n\t\t\tconst registration = entry.registration;\n\t\t\tif (registration === undefined) {\n\t\t\t\tthrow new AggregateTrackingError(\n\t\t\t\t\tString(entry.aggregate.id),\n\t\t\t\t\t\"commit\",\n\t\t\t\t\t\"mutated_after_registration\",\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst write = Object.freeze({\n\t\t\t\tintent: registration.intent,\n\t\t\t\taggregateId: entry.aggregate.id,\n\t\t\t\texpectedVersion: entry.expectedVersion,\n\t\t\t\tversion: registration.version,\n\t\t\t\tchanges: registration.changes,\n\t\t\t\tevents: registration.events,\n\t\t\t}) as AggregatePersistenceWrite<IAggregateRoot<Id<string>, Evt>, unknown>;\n\t\t\ttry {\n\t\t\t\tawait entry.definition.flush(transaction, write);\n\t\t\t} catch (error) {\n\t\t\t\tthrow mapRepositoryPersistenceError(entry.definition, error, write);\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic get commitTokens(): ReadonlyArray<AggregateCommitToken<Evt>> {\n\t\treturn [...this._commitTokens];\n\t}\n\n\tpublic close(): void {\n\t\tthis._closed = true;\n\t\t// Defensive: a leaked direct IdentityMap reference must not serve\n\t\t// stale instances into a later operation (that would silently\n\t\t// bypass OCC). The session getter already throws after close;\n\t\t// clearing covers refs captured before.\n\t\tthis._identityMap.clear();\n\t\tthis._trackedAggregates.clear();\n\t\tthis._registeredWrites.length = 0;\n\t\tthis._commitTokens.clear();\n\t}\n\n\tpublic assertOpen(operation: string): void {\n\t\tif (this._closed) {\n\t\t\tthrow new TransactionClosedError(operation);\n\t\t}\n\t}\n}\n\nfunction mapRepositoryPersistenceError<Evt extends AnyDomainEvent>(\n\tdefinition: RuntimePersistenceDefinition<Evt>,\n\terror: unknown,\n\twrite: AggregatePersistenceWrite<IAggregateRoot<Id<string>, Evt>, unknown>,\n): InfrastructureError {\n\tlet mapped: unknown;\n\ttry {\n\t\tmapped = definition.mapError(error, write);\n\t} catch (mapperError) {\n\t\tthrow new RepositoryErrorMappingFailedError({\n\t\t\taggregateId: String(write.aggregateId),\n\t\t\tintent: write.intent,\n\t\t\tpersistenceError: error,\n\t\t\tmapperError,\n\t\t});\n\t}\n\t// Copy-safe: an adapter package can carry its own copy of the kit, whose\n\t// InfrastructureError fails a plain instanceof here; rejecting it would\n\t// turn every retryable conflict into a non-retryable wiring crash that\n\t// blames a correct mapper.\n\tif (isInfrastructureErrorLike(mapped)) return mapped;\n\tthrow new RepositoryErrorMappingFailedError({\n\t\taggregateId: String(write.aggregateId),\n\t\tintent: write.intent,\n\t\tpersistenceError: error,\n\t\tmapperError: new TypeError(\n\t\t\t\"Repository mapError must return an InfrastructureError instance\",\n\t\t),\n\t});\n}\n\nfunction makeContext<TRepos, Evt extends AnyDomainEvent>(\n\trepositories: TRepos,\n\tsession: Session<Evt>,\n\tsignal: AbortSignal | undefined,\n): UnitOfWorkContext<TRepos> {\n\treturn {\n\t\tget repositories(): TRepos {\n\t\t\tsession.assertOpen(\"context.repositories\");\n\t\t\treturn repositories;\n\t\t},\n\t\t// The caller's own signal: exposed directly, not gated by\n\t\t// assertOpen, so polling `aborted` after close stays harmless.\n\t\tsignal,\n\t};\n}\n\n/**\n * Classifies a `withCommit` rejection into the error `run()` should throw,\n * using the flags captured inside the work wrapper. Pure and total: it\n * returns the error to throw rather than throwing itself, so `run()` reads\n * as orchestration and this decision is unit-testable in isolation.\n *\n * - `workThrew`: the work callback (or `assertAllChangesEnrolled`) threw.\n * The scope normally rethrows that error unchanged (rolled back, pass\n * through so a `ConcurrencyConflictError` & co. stay catchable as-is); a\n * scope that WRAPS the original is detected via the cause chain and also\n * passed through. Only a rejection that neither IS nor wraps the\n * callback's error indicates the rollback itself failed, which becomes a\n * {@link RollbackError}.\n * - `workCompleted`: the callback finished; the failure is post-completion.\n * A harvest-guard violation (an event missing aggregateId / aggregateType,\n * or an eventful persisted aggregate that did not advance its version) is a deterministic\n * programming bug, surfaced as its {@link EventHarvestError} (which does\n * NOT extend `InfrastructureError`, so a retry-on-Infrastructure handler\n * skips it). It is thrown inside `scope.transactional()`, so a wrapping\n * scope can nest it: walk the chain rather than a bare `instanceof`. Only\n * genuinely unforeseeable post-completion failures (outbox write, the\n * commit itself) become {@link CommitError}.\n * - Neither flag set: `withCommit` rejected before the callback ran (the\n * scope failed to even open a transaction); pass the error through.\n */\nfunction classifyRunError(\n\terror: unknown,\n\tstate: {\n\t\treadonly workThrew: boolean;\n\t\treadonly workCompleted: boolean;\n\t\treadonly workError: unknown;\n\t\treadonly signal: AbortSignal | undefined;\n\t},\n): unknown {\n\t// Cancellation wins over the attempt flags: a scope that rejects with\n\t// the caller's abort reason between retry attempts never re-enters the\n\t// work callback, so workThrew/workError still describe the PREVIOUS\n\t// attempt. Classifying by those stale flags would mislabel the abort as\n\t// a RollbackError carrying a retryable cause, inviting a retry of an\n\t// explicitly cancelled operation.\n\tif (\n\t\tstate.signal?.aborted &&\n\t\tstate.signal.reason !== undefined &&\n\t\t(error === state.signal.reason ||\n\t\t\tcauseChainContains(error, state.signal.reason))\n\t) {\n\t\treturn error;\n\t}\n\tif (state.workThrew) {\n\t\tif (\n\t\t\terror === state.workError ||\n\t\t\tcauseChainContains(error, state.workError)\n\t\t) {\n\t\t\treturn error;\n\t\t}\n\t\treturn new RollbackError(state.workError, error);\n\t}\n\tif (state.workCompleted) {\n\t\tconst harvestError = findHarvestErrorInChain(error);\n\t\tif (harvestError) {\n\t\t\treturn harvestError;\n\t\t}\n\t\treturn new CommitError(error);\n\t}\n\treturn error;\n}\n\n/**\n * Cycle-safe, getter-throw-safe walk over `error`'s standard `cause`\n * chain. `visit` runs for every object link (the top error included) and\n * receives the link plus its lazily read `cause`; a non-undefined return\n * stops the walk. A throwing `cause` getter (lazy deserialization, revoked\n * Proxy) ends the walk as no-match instead of replacing the real failure\n * with the getter's exception.\n */\nfunction findInCauseChain<T>(\n\terror: unknown,\n\tvisit: (link: object, cause: unknown) => T | undefined,\n): T | undefined {\n\tconst seen = new Set<unknown>();\n\tlet current: unknown = error;\n\twhile (\n\t\tcurrent !== null &&\n\t\ttypeof current === \"object\" &&\n\t\t!seen.has(current)\n\t) {\n\t\tseen.add(current);\n\t\tlet cause: unknown;\n\t\ttry {\n\t\t\tcause = (current as { cause?: unknown }).cause;\n\t\t} catch {\n\t\t\treturn undefined;\n\t\t}\n\t\tconst found = visit(current, cause);\n\t\tif (found !== undefined) return found;\n\t\tcurrent = cause;\n\t}\n\treturn undefined;\n}\n\n/**\n * Walks `error`'s `cause` chain and returns the first `EventHarvestError`,\n * or `undefined`. `withCommit` throws the harvest-guard error INSIDE\n * `scope.transactional`, so a wrapping scope can nest it; matching\n * only the top-level error would let the wrapper mask the non-retryable\n * type. `withCommit` and `run()` share this module, so the local\n * `instanceof` is reliable for the un-wrapped link.\n */\nfunction findHarvestErrorInChain(\n\terror: unknown,\n): EventHarvestError | undefined {\n\treturn findInCauseChain(error, (link) =>\n\t\tlink instanceof EventHarvestError ? link : undefined,\n\t);\n}\n\n/**\n * Whether `error`'s `cause` chain contains `target` by reference. A\n * `target` of `undefined`/`null` never matches: every error without a\n * `cause` property would otherwise \"contain\" a thrown `undefined`.\n */\nfunction causeChainContains(error: unknown, target: unknown): boolean {\n\tif (target === undefined || target === null) {\n\t\treturn false;\n\t}\n\treturn (\n\t\tfindInCauseChain(error, (_link, cause) =>\n\t\t\tcause === target ? true : undefined,\n\t\t) ?? false\n\t);\n}\n","/** Operational classification applied to one failed background delivery. */\nexport type DeliveryFailureKind = \"transient\" | \"permanent\" | \"unknown\";\n\n/** Consumer-owned translation from an adapter error to delivery semantics. */\nexport type DeliveryFailureClassifier = (error: unknown) => DeliveryFailureKind;\n\n/** Result of applying a delivery-failure classifier safely. */\nexport interface DeliveryFailureAssessment {\n\t/** How the shell will account for and recover from the failure. */\n\treadonly kind: DeliveryFailureKind;\n\t/** Classifier bug or invalid return value, when classification itself failed. */\n\treadonly classifierError?: unknown;\n}\n\nconst KINDS = new Set<DeliveryFailureKind>([\n\t\"transient\",\n\t\"permanent\",\n\t\"unknown\",\n]);\n\n/**\n * Default delivery classification. A retryable marker anywhere in the cause\n * chain, or a native `TimeoutError`, is transient. An explicit\n * `retryable: false` marker is permanent. Unmapped errors stay unknown and use\n * the shell's safe accounting default.\n */\nexport function classifyDeliveryFailure(error: unknown): DeliveryFailureKind {\n\tlet current = error;\n\tlet sawNonRetryable = false;\n\tconst seen = new Set<object>();\n\n\twhile (\n\t\tcurrent !== null &&\n\t\t(typeof current === \"object\" || typeof current === \"function\")\n\t) {\n\t\tconst node = current as object;\n\t\tif (seen.has(node)) break;\n\t\tseen.add(node);\n\n\t\ttry {\n\t\t\tconst candidate = current as {\n\t\t\t\treadonly name?: unknown;\n\t\t\t\treadonly retryable?: unknown;\n\t\t\t\treadonly cause?: unknown;\n\t\t\t};\n\t\t\tif (candidate.name === \"TimeoutError\") return \"transient\";\n\t\t\tif (candidate.retryable === true) return \"transient\";\n\t\t\tif (candidate.retryable === false) sawNonRetryable = true;\n\t\t\tcurrent = candidate.cause;\n\t\t} catch {\n\t\t\treturn \"unknown\";\n\t\t}\n\t}\n\n\treturn sawNonRetryable ? \"permanent\" : \"unknown\";\n}\n\n/** Applies a custom/default classifier without letting it break the worker. */\nexport function assessDeliveryFailure(\n\terror: unknown,\n\tclassifier: DeliveryFailureClassifier = classifyDeliveryFailure,\n): DeliveryFailureAssessment {\n\ttry {\n\t\tconst kind = classifier(error);\n\t\tif (KINDS.has(kind)) return Object.freeze({ kind });\n\t\treturn Object.freeze({\n\t\t\tkind: \"unknown\",\n\t\t\tclassifierError: new TypeError(\n\t\t\t\t`Delivery failure classifier returned invalid kind: ${String(kind)}`,\n\t\t\t),\n\t\t});\n\t} catch (classifierError) {\n\t\treturn Object.freeze({ kind: \"unknown\", classifierError });\n\t}\n}\n","/**\n * Exponential backoff with jitter, shared by every retry loop in the\n * kit (`RetryingTransactionScope` attempt delays, `OutboxDispatcher`\n * failure backoff).\n *\n * `attempt` is 1-based. The exponential value\n * (`baseDelayMs * 2^(attempt-1)`) is capped at `maxDelayMs`, then a\n * jitter band (`* random(0.8, 1.2)`) is applied and re-clamped to the\n * cap. Pure and deterministic given `random`. Result is never\n * negative.\n *\n * Deliberately not exported from the package entries: it is shared\n * kit plumbing, not public API.\n */\nexport function computeBackoffDelay(\n\tattempt: number,\n\topts: { baseDelayMs: number; maxDelayMs: number; random: () => number },\n): number {\n\tconst exponential = opts.baseDelayMs * 2 ** (attempt - 1);\n\tconst capped = Math.min(opts.maxDelayMs, exponential);\n\tconst jitter = 0.8 + opts.random() * 0.4; // [0.8, 1.2)\n\treturn Math.max(0, Math.min(opts.maxDelayMs, Math.round(capped * jitter)));\n}\n\n/**\n * Wraps an injected jitter source with observer-grade robustness: a\n * throwing or non-finite source degrades to the midpoint multiplier\n * (no jitter) instead of rejecting the poller that uses it, which\n * documents itself as never rejecting and is typically `void`ed.\n */\nexport function neutralJitterSource(source: () => number): () => number {\n\treturn () => {\n\t\ttry {\n\t\t\tconst value = source();\n\t\t\treturn Number.isFinite(value) ? value : 0.5;\n\t\t} catch {\n\t\t\treturn 0.5;\n\t\t}\n\t};\n}\n","/**\n * Awaits an in-flight pass on behalf of a joining caller without\n * letting a signal-less pass hold the joiner hostage: on the joiner's\n * abort this resolves `\"stopped\"` and leaves the pass running for its\n * owner. The pass promise must never reject (the pollers' documented\n * contract), so a plain `then` suffices; the abort listener is removed\n * once the pass settles.\n */\nexport function joinWithoutBlockingOnAbort(\n\tpass: Promise<\"drained\" | \"stopped\">,\n\tsignal: AbortSignal | undefined,\n): Promise<\"drained\" | \"stopped\"> {\n\tif (signal === undefined) return pass;\n\tif (signal.aborted) return Promise.resolve(\"stopped\");\n\treturn new Promise((resolve) => {\n\t\tconst onAbort = (): void => resolve(\"stopped\");\n\t\tsignal.addEventListener(\"abort\", onAbort, { once: true });\n\t\tvoid pass.then((outcome) => {\n\t\t\tsignal.removeEventListener(\"abort\", onAbort);\n\t\t\tresolve(outcome);\n\t\t});\n\t});\n}\n","import { abortReason } from \"./abort\";\n\n/**\n * Abortable `setTimeout` that RESOLVES early when the signal fires.\n * The graceful-stop variant: callers that treat an abort as \"stop\n * sleeping and wind down\" (a worker loop's idle or backoff sleep) use\n * this so the loop can observe `signal.aborted` and return cleanly.\n */\nexport function sleepResolvingOnAbort(\n\tms: number,\n\tsignal: AbortSignal,\n): Promise<void> {\n\tif (ms <= 0 || signal.aborted) return Promise.resolve();\n\treturn new Promise((resolve) => {\n\t\tconst done = (): void => {\n\t\t\tclearTimeout(timer);\n\t\t\tsignal.removeEventListener(\"abort\", done);\n\t\t\tresolve();\n\t\t};\n\t\tconst timer = setTimeout(done, ms);\n\t\tsignal.addEventListener(\"abort\", done, { once: true });\n\t});\n}\n\n/**\n * Abortable `setTimeout` that REJECTS with the signal's reason when it\n * fires. The cancellation variant: callers that treat an abort as \"this\n * operation failed, propagate it\" (a retry loop whose caller awaits the\n * result) use this so the rejection carries through.\n */\nexport function sleepRejectingOnAbort(\n\tms: number,\n\tsignal: AbortSignal | undefined,\n\tabortMessage: string,\n): Promise<void> {\n\treturn new Promise<void>((resolve, reject) => {\n\t\tif (signal?.aborted) {\n\t\t\treject(abortReason(signal, abortMessage));\n\t\t\treturn;\n\t\t}\n\t\tlet onAbort: (() => void) | undefined;\n\t\tconst timer = setTimeout(() => {\n\t\t\tif (onAbort && signal) signal.removeEventListener(\"abort\", onAbort);\n\t\t\tresolve();\n\t\t}, ms);\n\t\tif (signal) {\n\t\t\tonAbort = () => {\n\t\t\t\tclearTimeout(timer);\n\t\t\t\treject(abortReason(signal, abortMessage));\n\t\t\t};\n\t\t\tsignal.addEventListener(\"abort\", onAbort, { once: true });\n\t\t}\n\t});\n}\n","import { computeBackoffDelay, neutralJitterSource } from \"./backoff\";\nimport { joinWithoutBlockingOnAbort } from \"./in-flight\";\nimport { sleepResolvingOnAbort } from \"./sleep\";\nimport { assertNonNegativeFinite, assertPositiveInteger } from \"./validate\";\n\n/** Numeric options every kit poll loop shares; see the concrete classes. */\nexport interface PollLoopOptions {\n\tbatchSize?: number;\n\tpollIntervalMs?: number;\n\tbaseDelayMs?: number;\n\tmaxDelayMs?: number;\n\trandom?: () => number;\n}\n\n/**\n * The hardened poll-loop shell shared by `OutboxDispatcher` and\n * `DeadlineProcessor`, so the operationally tricky parts exist exactly\n * once: the never-rejecting `run(signal)` cadence (idle sleep when\n * drained, jittered streak backoff when stopped), the reentrancy-safe\n * `drainOnce` that joins an in-flight pass instead of starting a\n * competing one, option validation, and the per-instance neutralized\n * jitter source. Subclasses implement one thing: {@link pass}, the\n * delivery semantics of their port. Internal plumbing, not exported\n * from the package entries.\n */\nexport abstract class PollLoop {\n\tprotected readonly batchSize: number;\n\tprivate readonly pollIntervalMs: number;\n\tprivate readonly baseDelayMs: number;\n\tprivate readonly maxDelayMs: number;\n\tprivate readonly jitter: () => number;\n\n\t/**\n\t * Failed cycles since the last clean one; drives the backoff.\n\t * Subclasses bump it once per failed cycle and reset it on clean or\n\t * empty cycles (a subclass may bump by more, e.g. to a record's\n\t * attempt count, via direct assignment).\n\t */\n\tprotected consecutiveFailures = 0;\n\n\t/** In-flight pass; overlapping drainOnce calls join it. */\n\tprivate inFlightPass?: Promise<\"drained\" | \"stopped\">;\n\n\tprotected constructor(context: string, options: PollLoopOptions) {\n\t\tconst batchSize = options.batchSize ?? 32;\n\t\tassertPositiveInteger(context, \"batchSize\", batchSize);\n\t\tthis.batchSize = batchSize;\n\t\tthis.pollIntervalMs = options.pollIntervalMs ?? 250;\n\t\tthis.baseDelayMs = options.baseDelayMs ?? 50;\n\t\tthis.maxDelayMs = options.maxDelayMs ?? 5000;\n\t\tassertNonNegativeFinite(context, \"pollIntervalMs\", this.pollIntervalMs);\n\t\tassertNonNegativeFinite(context, \"baseDelayMs\", this.baseDelayMs);\n\t\tassertNonNegativeFinite(context, \"maxDelayMs\", this.maxDelayMs);\n\t\tthis.jitter = neutralJitterSource(options.random ?? Math.random);\n\t}\n\n\t/**\n\t * One full pass over the backlog: loop batches until nothing is\n\t * pending (`\"drained\"`) or a failure ends the cycle (`\"stopped\"`).\n\t * Must never reject; only ever one pass is in flight.\n\t */\n\tprotected abstract pass(signal?: AbortSignal): Promise<\"drained\" | \"stopped\">;\n\n\t/**\n\t * Runs the poll loop until `signal` aborts, then resolves. Never\n\t * rejects: a `\"drained\"` pass sleeps `pollIntervalMs`, a `\"stopped\"`\n\t * one sleeps the current streak backoff.\n\t */\n\tasync run(signal: AbortSignal): Promise<void> {\n\t\twhile (!signal.aborted) {\n\t\t\tconst outcome = await this.drainOnce(signal);\n\t\t\tif (signal.aborted) return;\n\t\t\tif (outcome === \"drained\") {\n\t\t\t\tawait sleepResolvingOnAbort(this.pollIntervalMs, signal);\n\t\t\t} else {\n\t\t\t\tawait sleepResolvingOnAbort(this.currentBackoff(), signal);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Single pass for cron triggers and serverless runtimes; returns\n\t * without sleeping (the tick cadence is the retry pacing; only\n\t * `run` sleeps the backoff). Reentrancy-safe: a call during an\n\t * in-flight pass joins it, and the joining call's own `signal`\n\t * still ends its wait while the pass runs on for its owner.\n\t *\n\t * With producers that keep the backlog non-empty, \"until drained\"\n\t * can outlast a bounded invocation: pass a `signal` wired to your\n\t * runtime's deadline (`AbortSignal.timeout(...)`) so the pass ends\n\t * cleanly; completed work stays acknowledged, the rest waits for\n\t * the next tick.\n\t */\n\tasync drainOnce(signal?: AbortSignal): Promise<\"drained\" | \"stopped\"> {\n\t\tif (this.inFlightPass !== undefined) {\n\t\t\treturn joinWithoutBlockingOnAbort(this.inFlightPass, signal);\n\t\t}\n\t\tconst pass = this.pass(signal);\n\t\tthis.inFlightPass = pass;\n\t\ttry {\n\t\t\treturn await pass;\n\t\t} finally {\n\t\t\tthis.inFlightPass = undefined;\n\t\t}\n\t}\n\n\t/** Backoff for the current consecutive-failure streak. */\n\tprivate currentBackoff(): number {\n\t\treturn computeBackoffDelay(Math.max(1, this.consecutiveFailures), {\n\t\t\tbaseDelayMs: this.baseDelayMs,\n\t\t\tmaxDelayMs: this.maxDelayMs,\n\t\t\trandom: this.jitter,\n\t\t});\n\t}\n}\n","import {\n\tassessDeliveryFailure,\n\ttype DeliveryFailureAssessment,\n\ttype DeliveryFailureClassifier,\n} from \"../utils/delivery-failure\";\nimport {\n\tDEFAULT_EXECUTION_TIMEOUT_MS,\n\ttype ExecutionContext,\n\trunBoundedExecution,\n} from \"../utils/execution\";\nimport { captureObserverFunctions, reportToObserver } from \"../utils/observer\";\nimport { PollLoop } from \"../utils/poll-loop\";\nimport { assertNonNegativeFinite } from \"../utils/validate\";\nimport type {\n\tDeadLetterDeadline,\n\tDeadlineStore,\n\tDueDeadline,\n} from \"./deadline-store\";\n\n/**\n * Required operational observers for {@link DeadlineProcessor}. All hooks are\n * best-effort notifications: synchronous throws and rejected promises are\n * neutralized so observability cannot change delivery state. The processor\n * captures and freezes these function references at construction, so later\n * mutation of the supplied object cannot disable an operational channel.\n *\n * `onDeadLetter` fires immediately after `markFailed` reports the exact\n * transition. It is not a durable notification boundary: a process can stop\n * after the store commits the transition and before the callback runs. Keep\n * polling {@link DeadlineStore.deadLetters} for durable alerting and\n * reconciliation; the hook provides low-latency diagnostics.\n */\nexport interface DeadlineProcessorObservers<TPayload> {\n\t/**\n\t * A handler, acknowledgement, or failure-tracking operation failed.\n\t * Handler failures include their accounting assessment; store failures do\n\t * not consume poison-message attempts and have no assessment.\n\t */\n\treadonly onDeliveryError: (\n\t\terror: unknown,\n\t\tdeadline: DueDeadline<TPayload>,\n\t\tassessment?: DeliveryFailureAssessment,\n\t) => void;\n\t/** Reading the poll clock or due page failed. */\n\treadonly onPollError: (error: unknown) => void;\n\t/** A deadline crossed the store's dead-letter threshold. */\n\treadonly onDeadLetter: (deadline: DeadLetterDeadline<TPayload>) => void;\n}\n\n/** Construction options for {@link DeadlineProcessor}. */\nexport interface DeadlineProcessorOptions<TPayload> {\n\t/** The poll surface; see {@link DeadlineStore}. */\n\tstore: DeadlineStore<TPayload>;\n\n\t/** Complete, required operational observer bundle. */\n\tobservers: DeadlineProcessorObservers<TPayload>;\n\n\t/**\n\t * Receives each due deadline as an input. A throw signals delivery\n\t * failure: the processor reports it via `markFailed` (the store\n\t * dead-letters past its ceiling) and moves on to the next deadline;\n\t * neighbors are independent. Remember the guide's discipline: a\n\t * delivered deadline is a proposal, so check it against current\n\t * state before acting. Pass `context.signal` to I/O adapters or enforce a\n\t * native timeout no later than `context.deadlineAt`. The shell bounds its\n\t * wait but cannot terminate an ignored foreign promise; production handlers\n\t * must prevent zombie work from overlapping a retry.\n\t */\n\thandler: (\n\t\tdeadline: DueDeadline<TPayload>,\n\t\tcontext: ExecutionContext,\n\t) => Promise<void> | void;\n\n\t/** Deadlines fetched per poll. Default `32`. */\n\tbatchSize?: number;\n\n\t/** Idle sleep between polls when nothing is due. Default `250`ms. */\n\tpollIntervalMs?: number;\n\n\t/**\n\t * First backoff delay after a failed cycle; grows exponentially with\n\t * the processor's consecutive-failure streak and is jittered.\n\t * Default `50`ms.\n\t */\n\tbaseDelayMs?: number;\n\n\t/** Ceiling for the failure backoff. Default `5000`ms. */\n\tmaxDelayMs?: number;\n\n\t/**\n\t * Maximum time to await one deadline handler. The handler receives the same\n\t * deadline as an AbortSignal and an absolute `deadlineAt`. Default `30000`ms.\n\t */\n\tdeliveryTimeoutMs?: number;\n\n\t/**\n\t * Maximum time to await one poll-store read, acknowledgement, or failure\n\t * update. The store receives the same cooperative context. This bounds the\n\t * worker's wait; production adapters must also cancel or natively bound the\n\t * underlying I/O. Default `30000`ms.\n\t */\n\tstorageTimeoutMs?: number;\n\n\t/**\n\t * Classifies handler failures as transient, permanent, or unknown. Transient\n\t * failures back off without consuming the poison ceiling; permanent and\n\t * unknown failures count. The default walks the cause chain: native\n\t * `TimeoutError` and `retryable: true` are transient, `retryable: false` is\n\t * permanent, and unmapped errors are unknown. A throwing or invalid custom\n\t * classifier becomes unknown and is exposed through the observer assessment\n\t * without replacing the original handler error.\n\t */\n\tclassifyFailure?: DeliveryFailureClassifier;\n\n\t/**\n\t * Jitter source for the failure backoff, injectable for\n\t * deterministic tests. Default `Math.random`. Neutralized like every\n\t * user callback: a throwing or non-finite source degrades to the\n\t * midpoint multiplier.\n\t */\n\trandom?: () => number;\n\n\t/**\n\t * The clock the poll passes to {@link DeadlineStore.due}. Omit it to use\n\t * `() => new Date()`. An injected clock that throws or returns an invalid\n\t * `Date` fails the cycle before the store is read, reports through\n\t * `onPollError`, and participates in the normal failure backoff.\n\t */\n\tclock?: () => Date;\n}\n\n/**\n * The hardened delivery loop for {@link DeadlineStore}: poll due\n * deadlines, hand each one to the handler, acknowledge or report the\n * failure. The delivery semantics are deliberately simpler than the\n * outbox dispatcher's, because deadlines carry no ordering: a HANDLER\n * failure never stops the batch; the failing deadline is reported via\n * `markFailed` and its neighbors keep flowing in the same cycle.\n *\n * What it shares with the dispatcher is the loop hardening, which is\n * exactly the part hand-rolled loops get wrong:\n *\n * - **Never rejects.** Clock and poll errors, handler throws, ack failures,\n * and observer bugs are absorbed and reported; `run(signal)` resolves on\n * abort and never becomes an unhandled rejection.\n * - **Backs off under failure.** A cycle containing any failure grows\n * the jittered exponential backoff toward `maxDelayMs` (one step per\n * cycle); an empty backlog or a clean cycle resets the streak.\n * - **Reentrancy-safe.** A `drainOnce` call while a pass is in flight\n * joins that pass instead of starting a competing poll (overlapping\n * cron ticks would double-deliver); a joining call still honors its\n * own signal.\n * - **At-least-once.** A crash or ack failure after handling\n * redelivers; handlers stay idempotent (the guide shows the\n * idempotency-store wiring). Delivered deadlines are acknowledged in\n * ONE `markDelivered` call per cycle, and an ack failure ends the\n * cycle: it signals the store's write path, not a poison record, so\n * it is reported per affected deadline, never to `markFailed`\n * (counting it toward the poison ceiling would dead-letter healthy\n * work), and the backoff paces the redelivery instead of the pass\n * re-running every handler against a dead write path.\n * - **Bounded waiting requires bounded adapters.** Delivery and store operations\n * receive cooperative cancellation and an absolute deadline. The processor\n * returns after its configured bound even when a promise ignores the signal,\n * but only the adapter can terminate native I/O and prevent late work from\n * overlapping a retry. A late idempotent acknowledgement remains valid.\n *\n * Run one logical processor per store unless the adapter's `due`\n * claims records; the same rule as the dispatcher.\n */\nexport class DeadlineProcessor<TPayload = unknown> extends PollLoop {\n\tprivate readonly store: DeadlineStore<TPayload>;\n\tprivate readonly handler: (\n\t\tdeadline: DueDeadline<TPayload>,\n\t\tcontext: ExecutionContext,\n\t) => Promise<void> | void;\n\tprivate readonly clock: () => Date;\n\tprivate readonly observers: DeadlineProcessorObservers<TPayload>;\n\tprivate readonly deliveryTimeoutMs: number;\n\tprivate readonly storageTimeoutMs: number;\n\tprivate readonly classifyFailure?: DeliveryFailureClassifier;\n\n\tconstructor(options: DeadlineProcessorOptions<TPayload>) {\n\t\tsuper(\"DeadlineProcessor\", options);\n\t\tthis.observers = captureObserverFunctions(\n\t\t\t\"DeadlineProcessor\",\n\t\t\toptions.observers,\n\t\t\t[\"onDeliveryError\", \"onPollError\", \"onDeadLetter\"],\n\t\t);\n\t\tthis.store = options.store;\n\t\tthis.handler = options.handler;\n\t\tthis.classifyFailure = options.classifyFailure;\n\t\tthis.clock = options.clock ?? (() => new Date());\n\t\tthis.deliveryTimeoutMs =\n\t\t\toptions.deliveryTimeoutMs ?? DEFAULT_EXECUTION_TIMEOUT_MS;\n\t\tthis.storageTimeoutMs =\n\t\t\toptions.storageTimeoutMs ?? DEFAULT_EXECUTION_TIMEOUT_MS;\n\t\tassertNonNegativeFinite(\n\t\t\t\"DeadlineProcessor\",\n\t\t\t\"deliveryTimeoutMs\",\n\t\t\tthis.deliveryTimeoutMs,\n\t\t);\n\t\tassertNonNegativeFinite(\n\t\t\t\"DeadlineProcessor\",\n\t\t\t\"storageTimeoutMs\",\n\t\t\tthis.storageTimeoutMs,\n\t\t);\n\t}\n\n\t/**\n\t * One full delivery pass (the `run`/`drainOnce` shell lives on\n\t * {@link PollLoop}): delivers due deadlines batch by batch until\n\t * nothing is due or a cycle contained a failure.\n\t */\n\tprotected async pass(signal?: AbortSignal): Promise<\"drained\" | \"stopped\"> {\n\t\twhile (!signal?.aborted) {\n\t\t\tlet batch: ReadonlyArray<DueDeadline<TPayload>>;\n\t\t\ttry {\n\t\t\t\tbatch = await runBoundedExecution(\n\t\t\t\t\t\"DeadlineProcessor.due\",\n\t\t\t\t\t{ signal, timeoutMs: this.storageTimeoutMs },\n\t\t\t\t\t(context) => this.store.due(this.now(), this.batchSize, context),\n\t\t\t\t);\n\t\t\t} catch (error) {\n\t\t\t\tif (signal?.aborted) return \"stopped\";\n\t\t\t\tthis.consecutiveFailures += 1;\n\t\t\t\treportToObserver(() => this.observers.onPollError(error));\n\t\t\t\treturn \"stopped\";\n\t\t\t}\n\t\t\tif (batch.length === 0) {\n\t\t\t\tthis.consecutiveFailures = 0;\n\t\t\t\treturn \"drained\";\n\t\t\t}\n\n\t\t\t// Handler failures do NOT stop the batch: deadlines carry no\n\t\t\t// cross-address ordering, so a poison deadline blocks only\n\t\t\t// itself and is reported to the store's bounded retries.\n\t\t\tlet handlerFailed = false;\n\t\t\tconst delivered: DueDeadline<TPayload>[] = [];\n\t\t\tfor (const deadline of batch) {\n\t\t\t\tif (signal?.aborted) break;\n\t\t\t\tlet boundedContext: ExecutionContext | undefined;\n\t\t\t\ttry {\n\t\t\t\t\tawait runBoundedExecution(\n\t\t\t\t\t\t\"DeadlineProcessor.handler\",\n\t\t\t\t\t\t{ signal, timeoutMs: this.deliveryTimeoutMs },\n\t\t\t\t\t\t(context) => {\n\t\t\t\t\t\t\tboundedContext = context;\n\t\t\t\t\t\t\treturn this.handler(deadline, context);\n\t\t\t\t\t\t},\n\t\t\t\t\t);\n\t\t\t\t\tdelivered.push(deadline);\n\t\t\t\t} catch (error) {\n\t\t\t\t\tif (signal?.aborted) break;\n\t\t\t\t\thandlerFailed = true;\n\t\t\t\t\tconst assessment = assessDeliveryFailure(error, this.classifyFailure);\n\t\t\t\t\treportToObserver(() =>\n\t\t\t\t\t\tthis.observers.onDeliveryError(error, deadline, assessment),\n\t\t\t\t\t);\n\t\t\t\t\t// The processor's own delivery budget expiring is\n\t\t\t\t\t// deterministic evidence against THIS deliveryId, not a\n\t\t\t\t\t// transient infrastructure hiccup: without consuming an\n\t\t\t\t\t// attempt, a handler that permanently ignores\n\t\t\t\t\t// context.signal never reaches the dead letter and every\n\t\t\t\t\t// poll re-serves it and spawns another zombie execution.\n\t\t\t\t\tconst ownBudgetExpired =\n\t\t\t\t\t\t!signal?.aborted && boundedContext?.signal.aborted === true;\n\t\t\t\t\tif (assessment.kind !== \"transient\" || ownBudgetExpired) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst deadLetter = await runBoundedExecution(\n\t\t\t\t\t\t\t\t\"DeadlineProcessor.markFailed\",\n\t\t\t\t\t\t\t\t{ signal, timeoutMs: this.storageTimeoutMs },\n\t\t\t\t\t\t\t\t(context) =>\n\t\t\t\t\t\t\t\t\tthis.store.markFailed(deadline.deliveryId, error, context),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\tif (deadLetter !== undefined) {\n\t\t\t\t\t\t\t\treportToObserver(() => this.observers.onDeadLetter(deadLetter));\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} catch (markError) {\n\t\t\t\t\t\t\tif (!signal?.aborted) {\n\t\t\t\t\t\t\t\treportToObserver(() =>\n\t\t\t\t\t\t\t\t\tthis.observers.onDeliveryError(markError, deadline),\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// One ack round-trip per cycle. An ack failure DOES stop the\n\t\t\t// cycle: it signals the store's write path, not a poison\n\t\t\t// record; continuing would re-run every handler against a dead\n\t\t\t// write path on each backoff step. Every handled deadline will\n\t\t\t// redeliver (the documented duplicates), so each is reported.\n\t\t\tlet acked = true;\n\t\t\tif (delivered.length > 0) {\n\t\t\t\ttry {\n\t\t\t\t\t// A completed handler keeps one bounded acknowledgement attempt\n\t\t\t\t\t// when shutdown won immediately after completion. An acknowledgement\n\t\t\t\t\t// that was already running remains owner-cancellable.\n\t\t\t\t\tconst acknowledgementSignal = signal?.aborted ? undefined : signal;\n\t\t\t\t\tawait runBoundedExecution(\n\t\t\t\t\t\t\"DeadlineProcessor.markDelivered\",\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tsignal: acknowledgementSignal,\n\t\t\t\t\t\t\ttimeoutMs: this.storageTimeoutMs,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t(context) =>\n\t\t\t\t\t\t\tthis.store.markDelivered(\n\t\t\t\t\t\t\t\tdelivered.map((deadline) => deadline.deliveryId),\n\t\t\t\t\t\t\t\tcontext,\n\t\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\t} catch (error) {\n\t\t\t\t\tacked = false;\n\t\t\t\t\tif (!signal?.aborted) {\n\t\t\t\t\t\tfor (const deadline of delivered) {\n\t\t\t\t\t\t\treportToObserver(() =>\n\t\t\t\t\t\t\t\tthis.observers.onDeliveryError(error, deadline),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (handlerFailed || !acked) {\n\t\t\t\t// One streak bump per failed cycle; run()'s backoff sleep\n\t\t\t\t// paces the retry (a bare drainOnce loop gets its pacing\n\t\t\t\t// from the tick cadence instead).\n\t\t\t\tthis.consecutiveFailures += 1;\n\t\t\t\treturn \"stopped\";\n\t\t\t}\n\t\t\tthis.consecutiveFailures = 0;\n\t\t\t// An abort mid-batch left deadlines unhandled; not a failure,\n\t\t\t// but not a drained backlog either.\n\t\t\tif (signal?.aborted) return \"stopped\";\n\t\t}\n\t\treturn \"stopped\";\n\t}\n\n\t/**\n\t * Reads and validates the poll clock before the store is consulted.\n\t * The caller's poll-error path reports any throw and applies backoff.\n\t */\n\tprivate now(): Date {\n\t\tconst value = this.clock();\n\t\tif (!(value instanceof Date) || Number.isNaN(value.getTime())) {\n\t\t\tthrow new TypeError(\"DeadlineProcessor: clock must return a valid Date\");\n\t\t}\n\t\treturn value;\n\t}\n}\n","import { InMemoryCapacityExceededError } from \"../core/errors\";\nimport {\n\tassertPositiveInteger,\n\tassertPositiveSafeInteger,\n} from \"../utils/validate\";\nimport type {\n\tDeadLetterDeadline,\n\tDeadlineStore,\n\tDueDeadline,\n} from \"./deadline-store\";\n\n/** Construction options for {@link InMemoryDeadlineStore}. */\nexport interface InMemoryDeadlineStoreOptions {\n\t/** Maximum records retained across pending and dead-letter states. */\n\treadonly maxRecords?: number;\n\n\t/**\n\t * How many failed delivery attempts move a deadline to the\n\t * dead-letter set. Default `5`.\n\t */\n\tmaxDeliveryAttempts?: number;\n}\n\ninterface StoredDeadline<TPayload> {\n\tdeliveryId: string;\n\tscope: string;\n\tkey: string;\n\tdueAt: Date;\n\tpayload: TPayload;\n\tattempts: number;\n\t/** Monotonic tie-breaker: scheduling order for equal due times. */\n\tsequence: number;\n\tlastError?: string;\n}\n\n/**\n * In-memory reference implementation of {@link DeadlineStore}: defines\n * the port's semantics and serves finite-lifetime tests and demos. Without\n * `maxRecords`, pending and dead-letter records are unbounded. A configured\n * limit rejects a new address before mutation; delivery state is never\n * silently evicted.\n *\n * **Not transaction-aware**, the same documented limitation as the\n * other in-memory references: a rolled-back `schedule` or `cancel`\n * stays applied here. The transactional half of the contract is the\n * SQL adapter's job; prove it with `createDeadlineStoreContractTests`\n * and its rollback capability.\n *\n * Payloads are deep-copied on schedule and on delivery\n * (`structuredClone`), so neither side can mutate the other's copy.\n */\nexport class InMemoryDeadlineStore<TPayload = unknown>\n\timplements DeadlineStore<TPayload>\n{\n\tprivate readonly pending = new Map<string, StoredDeadline<TPayload>>();\n\t/** Keyed by deliveryId: several incarnations of one address can be dead. */\n\tprivate readonly dead = new Map<string, StoredDeadline<TPayload>>();\n\tprivate readonly maxDeliveryAttempts: number;\n\tprivate readonly maxRecords: number | undefined;\n\tprivate nextSequence = 0;\n\n\tconstructor(options: InMemoryDeadlineStoreOptions = {}) {\n\t\tconst max = options.maxDeliveryAttempts ?? 5;\n\t\tassertPositiveInteger(\"InMemoryDeadlineStore\", \"maxDeliveryAttempts\", max);\n\t\tthis.maxDeliveryAttempts = max;\n\t\tif (options.maxRecords !== undefined) {\n\t\t\tassertPositiveSafeInteger(\n\t\t\t\t\"InMemoryDeadlineStore\",\n\t\t\t\t\"maxRecords\",\n\t\t\t\toptions.maxRecords,\n\t\t\t);\n\t\t}\n\t\tthis.maxRecords = options.maxRecords;\n\t}\n\n\tasync schedule(deadline: {\n\t\tscope: string;\n\t\tkey: string;\n\t\tdueAt: Date;\n\t\tpayload: TPayload;\n\t}): Promise<void> {\n\t\tconst deadlineAddress = address(deadline.scope, deadline.key);\n\t\tif (\n\t\t\t!this.pending.has(deadlineAddress) &&\n\t\t\tthis.maxRecords !== undefined &&\n\t\t\tthis.pending.size + this.dead.size >= this.maxRecords\n\t\t) {\n\t\t\tthrow new InMemoryCapacityExceededError({\n\t\t\t\tstore: \"InMemoryDeadlineStore\",\n\t\t\t\tresource: \"records\",\n\t\t\t\tlimit: this.maxRecords,\n\t\t\t\tcurrent: this.pending.size + this.dead.size,\n\t\t\t\tattempted: 1,\n\t\t\t});\n\t\t}\n\t\tconst sequence = this.nextSequence++;\n\t\t// Replacing an occupied address gets a FRESH incarnation: a late\n\t\t// ack or failure report against the old deliveryId must not touch\n\t\t// the successor.\n\t\tthis.pending.set(deadlineAddress, {\n\t\t\tdeliveryId: `deadline-${sequence}`,\n\t\t\tscope: deadline.scope,\n\t\t\tkey: deadline.key,\n\t\t\tdueAt: new Date(deadline.dueAt),\n\t\t\tpayload: structuredClone(deadline.payload),\n\t\t\tattempts: 0,\n\t\t\tsequence,\n\t\t});\n\t}\n\n\tasync cancel(scope: string, key: string): Promise<void> {\n\t\tthis.pending.delete(address(scope, key));\n\t}\n\n\tasync due(\n\t\tnow: Date,\n\t\tlimit: number,\n\t): Promise<ReadonlyArray<DueDeadline<TPayload>>> {\n\t\tif (!Number.isInteger(limit) || limit < 0) {\n\t\t\tthrow new Error(\n\t\t\t\t`InMemoryDeadlineStore: limit must be an integer >= 0, got ${limit}`,\n\t\t\t);\n\t\t}\n\t\t// \"Up to limit\": zero is a legal page size and yields an empty page\n\t\t// (a loop computing capacity - inFlight may legitimately pass it).\n\t\tif (limit === 0) return [];\n\t\treturn [...this.pending.values()]\n\t\t\t.filter((deadline) => deadline.dueAt.getTime() <= now.getTime())\n\t\t\t.sort(\n\t\t\t\t(a, b) =>\n\t\t\t\t\ta.dueAt.getTime() - b.dueAt.getTime() || a.sequence - b.sequence,\n\t\t\t)\n\t\t\t.slice(0, limit)\n\t\t\t.map((deadline) => toRecord(deadline));\n\t}\n\n\tasync markDelivered(deliveryIds: ReadonlyArray<string>): Promise<void> {\n\t\tfor (const deliveryId of deliveryIds) {\n\t\t\tthis.dead.delete(deliveryId);\n\t\t\tfor (const [key, deadline] of this.pending) {\n\t\t\t\tif (deadline.deliveryId === deliveryId) {\n\t\t\t\t\tthis.pending.delete(key);\n\t\t\t\t\tbreak; // deliveryIds are unique; nothing more to find\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tasync markFailed(\n\t\tdeliveryId: string,\n\t\terror?: unknown,\n\t): Promise<DeadLetterDeadline<TPayload> | undefined> {\n\t\tfor (const [key, deadline] of this.pending) {\n\t\t\tif (deadline.deliveryId !== deliveryId) continue;\n\t\t\tdeadline.attempts += 1;\n\t\t\t// An errorless report must not erase an earlier recorded reason.\n\t\t\tif (error !== undefined) deadline.lastError = String(error);\n\t\t\tif (deadline.attempts >= this.maxDeliveryAttempts) {\n\t\t\t\tthis.pending.delete(key);\n\t\t\t\tthis.dead.set(deadline.deliveryId, deadline);\n\t\t\t\treturn toDeadLetter(deadline);\n\t\t\t}\n\t\t\treturn undefined;\n\t\t}\n\t\t// Unknown, delivered, replaced, or already dead-lettered: a late\n\t\t// report must not resurrect or advance anything.\n\t\treturn undefined;\n\t}\n\n\tasync deadLetters(): Promise<ReadonlyArray<DeadLetterDeadline<TPayload>>> {\n\t\treturn [...this.dead.values()]\n\t\t\t.sort((a, b) => a.sequence - b.sequence)\n\t\t\t.map(toDeadLetter);\n\t}\n}\n\nfunction toDeadLetter<TPayload>(\n\tdeadline: StoredDeadline<TPayload>,\n): DeadLetterDeadline<TPayload> {\n\treturn {\n\t\t...toRecord(deadline),\n\t\t...(deadline.lastError === undefined\n\t\t\t? {}\n\t\t\t: { lastError: deadline.lastError }),\n\t};\n}\n\nfunction toRecord<TPayload>(\n\tdeadline: StoredDeadline<TPayload>,\n): DueDeadline<TPayload> {\n\treturn {\n\t\tdeliveryId: deadline.deliveryId,\n\t\tscope: deadline.scope,\n\t\tkey: deadline.key,\n\t\tdueAt: new Date(deadline.dueAt),\n\t\tpayload: structuredClone(deadline.payload),\n\t\tattempts: deadline.attempts,\n\t};\n}\n\n/** NUL-separated so no scope/key concatenation can collide. */\nfunction address(scope: string, key: string): string {\n\treturn `${scope}\\u0000${key}`;\n}\n","import { DomainError, KitWiringError } from \"../core/errors\";\n\n/** No transition is defined for the input in the current state. */\nexport class InvalidDomainTransitionError extends DomainError<\"INVALID_DOMAIN_TRANSITION\"> {\n\tconstructor(\n\t\tpublic readonly state: string,\n\t\tpublic readonly inputType: string,\n\t) {\n\t\tsuper({\n\t\t\tcode: \"INVALID_DOMAIN_TRANSITION\",\n\t\t\tmessage: `No domain transition from \"${state}\" on \"${inputType}\".`,\n\t\t});\n\t}\n}\n\n/** A defined transition was rejected by its domain guard. */\nexport class DomainTransitionGuardRejectedError extends DomainError<\"DOMAIN_TRANSITION_GUARD_REJECTED\"> {\n\tconstructor(\n\t\tpublic readonly state: string,\n\t\tpublic readonly inputType: string,\n\t) {\n\t\tsuper({\n\t\t\tcode: \"DOMAIN_TRANSITION_GUARD_REJECTED\",\n\t\t\tmessage: `Domain transition guard rejected \"${inputType}\" from \"${state}\".`,\n\t\t});\n\t}\n}\n\n/** The machine definition violates its runtime contract. */\nexport class InvalidDomainMachineDefinitionError extends KitWiringError<\"INVALID_DOMAIN_MACHINE_DEFINITION\"> {\n\tconstructor(message: string, cause?: unknown) {\n\t\tsuper(\"INVALID_DOMAIN_MACHINE_DEFINITION\", message, cause);\n\t}\n}\n\n/** Context contains unsupported or unsafe runtime data. */\nexport class InvalidDomainMachineContextError extends KitWiringError<\"INVALID_DOMAIN_MACHINE_CONTEXT\"> {\n\tconstructor(message: string, cause?: unknown) {\n\t\tsuper(\"INVALID_DOMAIN_MACHINE_CONTEXT\", message, cause);\n\t}\n}\n\n/** A supplied or produced snapshot is malformed or violates invariants. */\nexport class InvalidDomainMachineSnapshotError extends KitWiringError<\"INVALID_DOMAIN_MACHINE_SNAPSHOT\"> {\n\tconstructor(message: string, cause?: unknown) {\n\t\tsuper(\"INVALID_DOMAIN_MACHINE_SNAPSHOT\", message, cause);\n\t}\n}\n\n/** An input is malformed or contains unsupported runtime data. */\nexport class InvalidDomainMachineInputError extends KitWiringError<\"INVALID_DOMAIN_MACHINE_INPUT\"> {\n\tconstructor(message: string, cause?: unknown) {\n\t\tsuper(\"INVALID_DOMAIN_MACHINE_INPUT\", message, cause);\n\t}\n}\n\n/** A guard returned a value other than `boolean` or `DomainError`. */\nexport class InvalidDomainTransitionGuardResultError extends KitWiringError<\"INVALID_DOMAIN_TRANSITION_GUARD_RESULT\"> {\n\tconstructor(message: string, cause?: unknown) {\n\t\tsuper(\"INVALID_DOMAIN_TRANSITION_GUARD_RESULT\", message, cause);\n\t}\n}\n\n/** A reducer returned a malformed result or unsupported output data. */\nexport class InvalidDomainTransitionResultError extends KitWiringError<\"INVALID_DOMAIN_TRANSITION_RESULT\"> {\n\tconstructor(message: string, cause?: unknown) {\n\t\tsuper(\"INVALID_DOMAIN_TRANSITION_RESULT\", message, cause);\n\t}\n}\n\n/** A callback attempted to evaluate the same stateful machine recursively. */\nexport class ReentrantDomainStateMachineEvaluationError extends KitWiringError<\"REENTRANT_DOMAIN_STATE_MACHINE_EVALUATION\"> {\n\tconstructor() {\n\t\tsuper(\n\t\t\t\"REENTRANT_DOMAIN_STATE_MACHINE_EVALUATION\",\n\t\t\t\"Domain state machine callbacks cannot evaluate the same machine.\",\n\t\t);\n\t}\n}\n","import {\n\tfindPropertyDescriptor,\n\tisBuiltInObject,\n\tisIntrinsicConstructorPrototype,\n} from \"../utils/array/is-built-in\";\nimport { deepFreeze } from \"../value-object/value-object\";\nimport type { DomainMachineInput, DomainMachineReadonly } from \"./contracts\";\nimport {\n\tInvalidDomainMachineContextError,\n\tInvalidDomainMachineInputError,\n\tInvalidDomainTransitionResultError,\n} from \"./errors\";\n\ntype DomainMachineDataErrorFactory = (\n\tmessage: string,\n\tcause?: unknown,\n) =>\n\t| InvalidDomainMachineContextError\n\t| InvalidDomainMachineInputError\n\t| InvalidDomainTransitionResultError;\n\nconst DOMAIN_MACHINE_DATA_MAX_DEPTH = 256;\nconst DOMAIN_MACHINE_DATA_MAX_NODES = 10_000;\nconst DOMAIN_MACHINE_DATA_MAX_PROPERTIES = 100_000;\n\ntype DomainMachineDataTraversal = {\n\tnodes: number;\n\tproperties: number;\n};\n\nexport function copyDomainMachineOutputs<TOutput>(\n\toutputs: readonly (TOutput | DomainMachineReadonly<TOutput>)[] | undefined,\n): readonly DomainMachineReadonly<TOutput>[] {\n\ttry {\n\t\tconst copiedOutputs = cloneDomainMachineDataValue(\n\t\t\toutputs ?? [],\n\t\t\tcreateDomainTransitionOutputError,\n\t\t);\n\t\treturn deepFreeze(\n\t\t\tcopiedOutputs,\n\t\t) as readonly DomainMachineReadonly<TOutput>[];\n\t} catch (cause) {\n\t\tif (cause instanceof InvalidDomainTransitionResultError) {\n\t\t\tthrow cause;\n\t\t}\n\t\tthrow new InvalidDomainTransitionResultError(\n\t\t\t\"Domain transition result outputs must contain cloneable, deeply immutable data.\",\n\t\t\tcause,\n\t\t);\n\t}\n}\n\nexport function copyDomainMachineInput<TInput extends DomainMachineInput>(\n\tinput: TInput,\n): DomainMachineReadonly<TInput> {\n\ttry {\n\t\treturn deepFreeze(\n\t\t\tcloneDomainMachineDataValue(input, createDomainMachineInputError),\n\t\t) as DomainMachineReadonly<TInput>;\n\t} catch (cause) {\n\t\tif (cause instanceof InvalidDomainMachineInputError) {\n\t\t\tthrow cause;\n\t\t}\n\t\tthrow new InvalidDomainMachineInputError(\n\t\t\t\"Domain machine input must contain cloneable, deeply immutable data.\",\n\t\t\tcause,\n\t\t);\n\t}\n}\n\nexport function copyDomainMachineContext<TContext>(\n\tcontext: TContext | DomainMachineReadonly<TContext>,\n): DomainMachineReadonly<TContext> {\n\ttry {\n\t\treturn deepFreeze(\n\t\t\tcloneDomainMachineDataValue(context, createDomainMachineContextError),\n\t\t) as DomainMachineReadonly<TContext>;\n\t} catch (cause) {\n\t\tif (cause instanceof InvalidDomainMachineContextError) {\n\t\t\tthrow cause;\n\t\t}\n\t\tthrow new InvalidDomainMachineContextError(\n\t\t\t\"Domain machine context must contain cloneable, deeply immutable data.\",\n\t\t\tcause,\n\t\t);\n\t}\n}\n\nfunction createDomainMachineContextError(\n\tmessage: string,\n\tcause?: unknown,\n): InvalidDomainMachineContextError {\n\treturn new InvalidDomainMachineContextError(message, cause);\n}\n\nfunction createDomainMachineInputError(\n\tmessage: string,\n\tcause?: unknown,\n): InvalidDomainMachineInputError {\n\treturn new InvalidDomainMachineInputError(message, cause);\n}\n\nfunction createDomainTransitionOutputError(\n\tmessage: string,\n\tcause?: unknown,\n): InvalidDomainTransitionResultError {\n\treturn new InvalidDomainTransitionResultError(message, cause);\n}\n\nfunction cloneDomainMachineDataValue<TValue>(\n\tvalue: TValue,\n\terrorFactory: DomainMachineDataErrorFactory,\n\tseen = new WeakMap<object, unknown>(),\n\ttraversal: DomainMachineDataTraversal = { nodes: 0, properties: 0 },\n\tdepth = 0,\n): TValue {\n\tif (typeof value === \"function\") {\n\t\tthrow errorFactory(\"Domain machine data cannot contain function values.\");\n\t}\n\tif (value === null || typeof value !== \"object\") return value;\n\n\tconst source = value as object;\n\tif (depth > DOMAIN_MACHINE_DATA_MAX_DEPTH) {\n\t\tthrow errorFactory(\n\t\t\t`Domain machine data exceeds the maximum depth of ${DOMAIN_MACHINE_DATA_MAX_DEPTH}.`,\n\t\t);\n\t}\n\tconst existing = seen.get(source);\n\tif (existing !== undefined) return existing as TValue;\n\ttraversal.nodes += 1;\n\tif (traversal.nodes > DOMAIN_MACHINE_DATA_MAX_NODES) {\n\t\tthrow errorFactory(\n\t\t\t`Domain machine data contains more than ${DOMAIN_MACHINE_DATA_MAX_NODES.toLocaleString(\"en-US\")} object nodes.`,\n\t\t);\n\t}\n\tconst toStringTagDescriptor = findPropertyDescriptor(\n\t\tsource,\n\t\tSymbol.toStringTag,\n\t);\n\tif (\n\t\ttoStringTagDescriptor !== undefined &&\n\t\t!(\"value\" in toStringTagDescriptor)\n\t) {\n\t\tthrow errorFactory(\n\t\t\t\"Domain machine data cannot contain accessor properties.\",\n\t\t);\n\t}\n\n\tif (Array.isArray(value)) {\n\t\tif (!isIntrinsicArrayPrototype(Object.getPrototypeOf(value))) {\n\t\t\tthrow errorFactory(\n\t\t\t\t\"Domain machine data cannot contain custom Array instances.\",\n\t\t\t);\n\t\t}\n\t\tconst cloned: unknown[] = new Array(value.length);\n\t\tseen.set(source, cloned);\n\n\t\tfor (const key of readDomainMachineDataKeys(\n\t\t\tsource,\n\t\t\terrorFactory,\n\t\t\ttraversal,\n\t\t)) {\n\t\t\tconst descriptor = Object.getOwnPropertyDescriptor(source, key);\n\t\t\tif (!descriptor) continue;\n\n\t\t\tif (!(\"value\" in descriptor)) {\n\t\t\t\tthrow errorFactory(\n\t\t\t\t\t\"Domain machine data cannot contain accessor properties.\",\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif (key === \"length\") continue;\n\n\t\t\tdescriptor.value = cloneDomainMachineDataValue(\n\t\t\t\tdescriptor.value,\n\t\t\t\terrorFactory,\n\t\t\t\tseen,\n\t\t\t\ttraversal,\n\t\t\t\tdepth + 1,\n\t\t\t);\n\t\t\tObject.defineProperty(cloned, key, descriptor);\n\t\t}\n\t\treturn cloned as TValue;\n\t}\n\n\tconst prototype = Object.getPrototypeOf(source);\n\tif (prototype !== null && !isIntrinsicObjectPrototype(prototype)) {\n\t\tthrow errorFactory(\n\t\t\t\"Domain machine data cannot contain custom class instances.\",\n\t\t);\n\t}\n\n\tconst tag = Object.prototype.toString.call(source);\n\tif (isBuiltInObject(source, tag) || ArrayBuffer.isView(source)) {\n\t\tthrow errorFactory(\n\t\t\t`Domain machine data cannot contain ${tag.slice(8, -1)} object values.`,\n\t\t);\n\t}\n\n\tconst cloned = Object.create(prototype === null ? null : Object.prototype);\n\tseen.set(source, cloned);\n\n\tfor (const key of readDomainMachineDataKeys(\n\t\tsource,\n\t\terrorFactory,\n\t\ttraversal,\n\t)) {\n\t\tconst descriptor = Object.getOwnPropertyDescriptor(source, key);\n\t\tif (!descriptor) continue;\n\n\t\tif (!(\"value\" in descriptor)) {\n\t\t\tthrow errorFactory(\n\t\t\t\t\"Domain machine data cannot contain accessor properties.\",\n\t\t\t);\n\t\t}\n\n\t\tdescriptor.value = cloneDomainMachineDataValue(\n\t\t\tdescriptor.value,\n\t\t\terrorFactory,\n\t\t\tseen,\n\t\t\ttraversal,\n\t\t\tdepth + 1,\n\t\t);\n\t\tObject.defineProperty(cloned, key, descriptor);\n\t}\n\n\treturn cloned as TValue;\n}\n\nfunction readDomainMachineDataKeys(\n\tvalue: object,\n\terrorFactory: DomainMachineDataErrorFactory,\n\ttraversal: DomainMachineDataTraversal,\n): readonly PropertyKey[] {\n\tconst keys = Reflect.ownKeys(value);\n\ttraversal.properties += keys.length;\n\tif (traversal.properties > DOMAIN_MACHINE_DATA_MAX_PROPERTIES) {\n\t\tthrow errorFactory(\n\t\t\t`Domain machine data contains more than ${DOMAIN_MACHINE_DATA_MAX_PROPERTIES.toLocaleString(\"en-US\")} own properties.`,\n\t\t);\n\t}\n\treturn keys;\n}\n\nexport function isRecord(\n\tvalue: unknown,\n): value is Record<PropertyKey, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nexport function isPlainRecord(\n\tvalue: unknown,\n): value is Record<PropertyKey, unknown> {\n\tif (!isRecord(value)) return false;\n\n\tconst prototype = Object.getPrototypeOf(value);\n\treturn prototype === null || isIntrinsicObjectPrototype(prototype);\n}\n\nfunction isIntrinsicArrayPrototype(prototype: object | null): boolean {\n\tif (prototype === null || !Array.isArray(prototype)) return false;\n\tif (!isIntrinsicConstructorPrototype(prototype, \"Array\")) return false;\n\n\tconst parentPrototype = Object.getPrototypeOf(prototype);\n\treturn (\n\t\tparentPrototype !== null && isIntrinsicObjectPrototype(parentPrototype)\n\t);\n}\n\nfunction isIntrinsicObjectPrototype(prototype: object): boolean {\n\treturn (\n\t\tObject.getPrototypeOf(prototype) === null &&\n\t\tisIntrinsicConstructorPrototype(prototype, \"Object\")\n\t);\n}\n\nexport function hasOwn<T extends object>(\n\tvalue: T,\n\tkey: PropertyKey,\n): key is keyof T {\n\treturn Object.hasOwn(value, key);\n}\n","import type {\n\tDomainMachineDefinition,\n\tDomainMachineInput,\n\tDomainMachineSnapshot,\n\tDomainStateNode,\n\tDomainTransition,\n} from \"./contracts\";\nimport { InvalidDomainMachineDefinitionError } from \"./errors\";\nimport { hasOwn, isPlainRecord } from \"./machine-data\";\n\nconst DOMAIN_MACHINE_DEFINITION_KEYS: ReadonlySet<PropertyKey> = new Set([\n\t\"initial\",\n\t\"initialContext\",\n\t\"validateSnapshot\",\n\t\"states\",\n]);\nconst DOMAIN_MACHINE_STATE_NODE_KEYS: ReadonlySet<PropertyKey> = new Set([\n\t\"terminal\",\n\t\"validateContext\",\n\t\"on\",\n]);\nconst DOMAIN_MACHINE_TRANSITION_KEYS: ReadonlySet<PropertyKey> = new Set([\n\t\"target\",\n\t\"guard\",\n\t\"reduce\",\n]);\n\nexport function copyDomainMachineDefinition<\n\tTState extends string,\n\tTContext,\n\tTInput extends DomainMachineInput,\n\tTOutput,\n>(\n\tdefinition: DomainMachineDefinition<TState, TContext, TInput, TOutput>,\n): DomainMachineDefinition<TState, TContext, TInput, TOutput> {\n\tconst states = readDomainMachineDefinitionProperty(\n\t\tdefinition,\n\t\t\"states\",\n\t) as DomainMachineDefinition<TState, TContext, TInput, TOutput>[\"states\"];\n\tconst copiedStates = Object.create(null) as {\n\t\t[TName in TState]: DomainStateNode<TState, TContext, TInput, TOutput>;\n\t};\n\n\tfor (const state of Object.keys(states) as TState[]) {\n\t\tconst node = readDomainMachineDefinitionProperty(\n\t\t\tstates,\n\t\t\tstate,\n\t\t) as DomainStateNode<TState, TContext, TInput, TOutput>;\n\t\tconst transitions = readOptionalDomainMachineDefinitionProperty(\n\t\t\tnode,\n\t\t\t\"on\",\n\t\t) as DomainStateNode<TState, TContext, TInput, TOutput>[\"on\"] | undefined;\n\t\tconst copiedTransitions = Object.create(null) as {\n\t\t\t[TType in TInput[\"type\"]]?: DomainTransition<\n\t\t\t\tTState,\n\t\t\t\tTContext,\n\t\t\t\tExtract<TInput, { readonly type: TType }>,\n\t\t\t\tTOutput\n\t\t\t>;\n\t\t};\n\n\t\tfor (const inputType of Object.keys(\n\t\t\ttransitions ?? {},\n\t\t) as TInput[\"type\"][]) {\n\t\t\tconst transition = readDomainMachineDefinitionProperty(\n\t\t\t\ttransitions as object,\n\t\t\t\tinputType,\n\t\t\t) as\n\t\t\t\t| DomainTransition<\n\t\t\t\t\t\tTState,\n\t\t\t\t\t\tTContext,\n\t\t\t\t\t\tExtract<TInput, { readonly type: typeof inputType }>,\n\t\t\t\t\t\tTOutput\n\t\t\t\t >\n\t\t\t\t| undefined;\n\t\t\tif (transition) {\n\t\t\t\tconst copiedTransition = Object.freeze({\n\t\t\t\t\ttarget: readDomainMachineDefinitionProperty(transition, \"target\"),\n\t\t\t\t\tguard: readOptionalDomainMachineDefinitionProperty(\n\t\t\t\t\t\ttransition,\n\t\t\t\t\t\t\"guard\",\n\t\t\t\t\t),\n\t\t\t\t\treduce: readOptionalDomainMachineDefinitionProperty(\n\t\t\t\t\t\ttransition,\n\t\t\t\t\t\t\"reduce\",\n\t\t\t\t\t),\n\t\t\t\t}) as DomainTransition<\n\t\t\t\t\tTState,\n\t\t\t\t\tTContext,\n\t\t\t\t\tExtract<TInput, { readonly type: typeof inputType }>,\n\t\t\t\t\tTOutput\n\t\t\t\t>;\n\t\t\t\tObject.defineProperty(copiedTransitions, inputType, {\n\t\t\t\t\tvalue: copiedTransition,\n\t\t\t\t\tenumerable: true,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tObject.defineProperty(copiedStates, state, {\n\t\t\tvalue: Object.freeze({\n\t\t\t\tterminal: readOptionalDomainMachineDefinitionProperty(node, \"terminal\"),\n\t\t\t\tvalidateContext: readOptionalDomainMachineDefinitionProperty(\n\t\t\t\t\tnode,\n\t\t\t\t\t\"validateContext\",\n\t\t\t\t),\n\t\t\t\ton: Object.freeze(copiedTransitions),\n\t\t\t}),\n\t\t\tenumerable: true,\n\t\t});\n\t}\n\n\treturn Object.freeze({\n\t\tinitial: readDomainMachineDefinitionProperty(\n\t\t\tdefinition,\n\t\t\t\"initial\",\n\t\t) as TState,\n\t\tinitialContext: readDomainMachineDefinitionProperty(\n\t\t\tdefinition,\n\t\t\t\"initialContext\",\n\t\t) as () => TContext,\n\t\tvalidateSnapshot: readOptionalDomainMachineDefinitionProperty(\n\t\t\tdefinition,\n\t\t\t\"validateSnapshot\",\n\t\t) as\n\t\t\t| ((snapshot: DomainMachineSnapshot<TState, TContext>) => boolean)\n\t\t\t| undefined,\n\t\tstates: Object.freeze(copiedStates),\n\t});\n}\n\n/**\n * Registry of definitions produced by `prepareDomainMachineDefinition`:\n * validated, defensively copied, deeply frozen. The runtime membership\n * proof lives in this module-private WeakSet (the stable copies are\n * frozen and must stay pure data, so no runtime brand property); the\n * compile-time proof is the required type brand on\n * {@link PreparedDomainMachineDefinition}. Only\n * `prepareDomainMachineDefinition` below adds to the set, so membership\n * always implies validated + copied + frozen.\n */\nconst preparedDefinitions = new WeakSet<object>();\n\ndeclare const preparedDefinitionBrand: unique symbol;\n\n/**\n * A machine definition that `prepareDomainMachineDefinition` has\n * validated, defensively copied, and deeply frozen. Assignable wherever\n * a plain `DomainMachineDefinition` is accepted; the reverse does NOT\n * hold (the brand is required), so an API that demands a prepared\n * definition rejects raw ones at compile time. The pure functions and\n * the `DomainStateMachine` constructor recognize prepared definitions\n * at runtime and skip their per-call validate-and-copy.\n */\nexport type PreparedDomainMachineDefinition<\n\tTState extends string,\n\tTContext,\n\tTInput extends DomainMachineInput,\n\tTOutput = never,\n> = DomainMachineDefinition<TState, TContext, TInput, TOutput> & {\n\treadonly [preparedDefinitionBrand]: true;\n};\n\n/**\n * The entry-point normalization every pure function and the\n * `DomainStateMachine` constructor share: a prepared definition passes\n * through untouched (already validated, copied, frozen); anything else\n * pays the documented per-call validate-and-copy.\n */\nexport function ensureStableDomainMachineDefinition<\n\tTState extends string,\n\tTContext,\n\tTInput extends DomainMachineInput,\n\tTOutput,\n>(\n\tdefinition: DomainMachineDefinition<TState, TContext, TInput, TOutput>,\n): DomainMachineDefinition<TState, TContext, TInput, TOutput> {\n\tif (preparedDefinitions.has(definition)) return definition;\n\tvalidateDomainMachineDefinition(definition);\n\tconst stable = copyDomainMachineDefinition(definition);\n\t// Re-validate the COPY: a Proxy can legally answer the copy's reads\n\t// differently from validation's (TOCTOU), so the object that will\n\t// actually be dispatched against must itself pass validation. Costs a\n\t// second pass on the raw path only; prepared definitions skip all of\n\t// this.\n\tvalidateDomainMachineDefinition(stable);\n\treturn stable;\n}\n\n/**\n * Validates and stabilizes a machine definition ONCE, for repeated use\n * with the pure functions. Without it, `transitionDomainState` and\n * `canTransitionDomainState` re-validate and defensively re-copy the\n * WHOLE definition on every call (the documented safety of the raw\n * path); on a hot dispatch path that is avoidable O(definition) work.\n * The `DomainStateMachine` class does the equivalent once in its\n * constructor; this export brings the same amortization to pure-API\n * users:\n *\n * ```ts\n * const prepared = prepareDomainMachineDefinition(orderLifecycle);\n * // per dispatch: no re-validation, no definition copy\n * const outcome = transitionDomainState(prepared, snapshot, input);\n * ```\n *\n * The returned definition is a deeply frozen copy, isolated from later\n * mutation of the input object. Preparing an already-prepared\n * definition returns it unchanged.\n */\nexport function prepareDomainMachineDefinition<\n\tTState extends string,\n\tTContext,\n\tTInput extends DomainMachineInput,\n\tTOutput,\n>(\n\tdefinition: DomainMachineDefinition<TState, TContext, TInput, TOutput>,\n): PreparedDomainMachineDefinition<TState, TContext, TInput, TOutput> {\n\tconst stable = ensureStableDomainMachineDefinition(definition);\n\tpreparedDefinitions.add(stable);\n\treturn stable as PreparedDomainMachineDefinition<\n\t\tTState,\n\t\tTContext,\n\t\tTInput,\n\t\tTOutput\n\t>;\n}\n\nexport function getTransition<\n\tTState extends string,\n\tTContext,\n\tTInput extends DomainMachineInput,\n\tTOutput,\n>(\n\tdefinition: DomainMachineDefinition<TState, TContext, TInput, TOutput>,\n\tstate: TState,\n\tinput: TInput,\n): DomainTransition<TState, TContext, TInput, TOutput> | undefined {\n\tconst transitions = definition.states[state].on;\n\tif (!transitions || !hasOwn(transitions, input.type)) return undefined;\n\n\treturn transitions[input.type as TInput[\"type\"]] as\n\t\t| DomainTransition<TState, TContext, TInput, TOutput>\n\t\t| undefined;\n}\n\nexport function validateDomainMachineDefinition<\n\tTState extends string,\n\tTContext,\n\tTInput extends DomainMachineInput,\n\tTOutput,\n>(\n\tdefinition: DomainMachineDefinition<TState, TContext, TInput, TOutput>,\n): void {\n\tconst candidate = definition as unknown;\n\tif (!isPlainRecord(candidate)) {\n\t\tthrow new InvalidDomainMachineDefinitionError(\n\t\t\t\"Domain machine definition must be a plain object.\",\n\t\t);\n\t}\n\tassertDomainMachineDefinitionDataProperties(\n\t\tcandidate,\n\t\tDOMAIN_MACHINE_DEFINITION_KEYS,\n\t);\n\n\tconst initial = readDomainMachineDefinitionProperty(candidate, \"initial\");\n\tif (typeof initial !== \"string\") {\n\t\tthrow new InvalidDomainMachineDefinitionError(\n\t\t\t\"Domain machine initial state must be a string data property.\",\n\t\t);\n\t}\n\n\tif (\n\t\ttypeof readDomainMachineDefinitionProperty(candidate, \"initialContext\") !==\n\t\t\"function\"\n\t) {\n\t\tthrow new InvalidDomainMachineDefinitionError(\n\t\t\t\"Domain machine initialContext must be a function data property.\",\n\t\t);\n\t}\n\n\tconst validateSnapshot = readOptionalDomainMachineDefinitionProperty(\n\t\tcandidate,\n\t\t\"validateSnapshot\",\n\t);\n\tif (\n\t\tvalidateSnapshot !== undefined &&\n\t\ttypeof validateSnapshot !== \"function\"\n\t) {\n\t\tthrow new InvalidDomainMachineDefinitionError(\n\t\t\t\"Domain machine validateSnapshot must be a function data property.\",\n\t\t);\n\t}\n\n\tconst statesCandidate = readDomainMachineDefinitionProperty(\n\t\tcandidate,\n\t\t\"states\",\n\t);\n\tif (!isPlainRecord(statesCandidate)) {\n\t\tthrow new InvalidDomainMachineDefinitionError(\n\t\t\t\"Domain machine states must be a plain object data property.\",\n\t\t);\n\t}\n\tconst states: Record<PropertyKey, unknown> = statesCandidate;\n\tassertDomainMachineDefinitionEntryMap(states, \"state\");\n\n\tif (!hasOwn(states, initial)) {\n\t\tthrow new InvalidDomainMachineDefinitionError(\n\t\t\t`Initial domain machine state \"${initial}\" is not defined.`,\n\t\t);\n\t}\n\n\tfor (const state of Object.keys(states)) {\n\t\tconst node: unknown = readDomainMachineDefinitionProperty(states, state);\n\t\tif (!isPlainRecord(node)) {\n\t\t\tthrow new InvalidDomainMachineDefinitionError(\n\t\t\t\t`Domain machine state \"${state}\" must be a plain object data property.`,\n\t\t\t);\n\t\t}\n\t\tassertDomainMachineDefinitionDataProperties(\n\t\t\tnode,\n\t\t\tDOMAIN_MACHINE_STATE_NODE_KEYS,\n\t\t);\n\n\t\tconst terminal: unknown = readOptionalDomainMachineDefinitionProperty(\n\t\t\tnode,\n\t\t\t\"terminal\",\n\t\t);\n\t\tif (terminal !== undefined && typeof terminal !== \"boolean\") {\n\t\t\tthrow new InvalidDomainMachineDefinitionError(\n\t\t\t\t`Domain machine state \"${state}\" terminal flag must be a boolean.`,\n\t\t\t);\n\t\t}\n\n\t\tconst validateContext: unknown =\n\t\t\treadOptionalDomainMachineDefinitionProperty(node, \"validateContext\");\n\t\tif (\n\t\t\tvalidateContext !== undefined &&\n\t\t\ttypeof validateContext !== \"function\"\n\t\t) {\n\t\t\tthrow new InvalidDomainMachineDefinitionError(\n\t\t\t\t`Domain machine state \"${state}\" validateContext must be a function.`,\n\t\t\t);\n\t\t}\n\n\t\tconst transitions: unknown = readOptionalDomainMachineDefinitionProperty(\n\t\t\tnode,\n\t\t\t\"on\",\n\t\t);\n\t\tif (transitions !== undefined && !isPlainRecord(transitions)) {\n\t\t\tthrow new InvalidDomainMachineDefinitionError(\n\t\t\t\t`Domain machine state \"${state}\" transitions must be a plain object.`,\n\t\t\t);\n\t\t}\n\t\tif (isPlainRecord(transitions)) {\n\t\t\tassertDomainMachineDefinitionEntryMap(transitions, \"input\");\n\t\t}\n\n\t\tconst inputTypes = Object.keys(transitions ?? {});\n\t\tif (terminal === true && inputTypes.length > 0) {\n\t\t\tthrow new InvalidDomainMachineDefinitionError(\n\t\t\t\t`Terminal domain machine state \"${state}\" cannot declare transitions.`,\n\t\t\t);\n\t\t}\n\n\t\tfor (const inputType of inputTypes) {\n\t\t\tconst transition: unknown = readDomainMachineDefinitionProperty(\n\t\t\t\ttransitions as object,\n\t\t\t\tinputType,\n\t\t\t);\n\t\t\tif (!isPlainRecord(transition)) {\n\t\t\t\tthrow new InvalidDomainMachineDefinitionError(\n\t\t\t\t\t`Domain transition from \"${state}\" on \"${inputType}\" must be a plain object.`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tassertDomainMachineDefinitionDataProperties(\n\t\t\t\ttransition,\n\t\t\t\tDOMAIN_MACHINE_TRANSITION_KEYS,\n\t\t\t);\n\n\t\t\tconst target: unknown = readDomainMachineDefinitionProperty(\n\t\t\t\ttransition,\n\t\t\t\t\"target\",\n\t\t\t);\n\t\t\tif (typeof target !== \"string\") {\n\t\t\t\tthrow new InvalidDomainMachineDefinitionError(\n\t\t\t\t\t`Domain transition from \"${state}\" on \"${inputType}\" must target a string state.`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif (!hasOwn(states, target)) {\n\t\t\t\tthrow new InvalidDomainMachineDefinitionError(\n\t\t\t\t\t`Domain transition from \"${state}\" on \"${inputType}\" targets unknown state \"${target}\".`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst guard: unknown = readOptionalDomainMachineDefinitionProperty(\n\t\t\t\ttransition,\n\t\t\t\t\"guard\",\n\t\t\t);\n\t\t\tif (guard !== undefined && typeof guard !== \"function\") {\n\t\t\t\tthrow new InvalidDomainMachineDefinitionError(\n\t\t\t\t\t`Domain transition from \"${state}\" on \"${inputType}\" guard must be a function.`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst reduce: unknown = readOptionalDomainMachineDefinitionProperty(\n\t\t\t\ttransition,\n\t\t\t\t\"reduce\",\n\t\t\t);\n\t\t\tif (reduce !== undefined && typeof reduce !== \"function\") {\n\t\t\t\tthrow new InvalidDomainMachineDefinitionError(\n\t\t\t\t\t`Domain transition from \"${state}\" on \"${inputType}\" reduce must be a function.`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunction assertDomainMachineDefinitionDataProperties(\n\tvalue: object,\n\tallowedKeys?: ReadonlySet<PropertyKey>,\n): void {\n\tfor (const key of Reflect.ownKeys(value)) {\n\t\tconst descriptor = Object.getOwnPropertyDescriptor(value, key);\n\t\tif (descriptor !== undefined && !(\"value\" in descriptor)) {\n\t\t\tthrow new InvalidDomainMachineDefinitionError(\n\t\t\t\t\"Domain machine definition must contain data properties only.\",\n\t\t\t);\n\t\t}\n\t\tif (allowedKeys !== undefined && !allowedKeys.has(key)) {\n\t\t\tthrow new InvalidDomainMachineDefinitionError(\n\t\t\t\t`Domain machine definition contains unknown property \"${String(key)}\".`,\n\t\t\t);\n\t\t}\n\t}\n}\n\nfunction assertDomainMachineDefinitionEntryMap(\n\tvalue: object,\n\tentryName: \"state\" | \"input\",\n): void {\n\tassertDomainMachineDefinitionDataProperties(value);\n\n\tfor (const key of Reflect.ownKeys(value)) {\n\t\tconst descriptor = Object.getOwnPropertyDescriptor(value, key);\n\t\tif (typeof key !== \"string\" || descriptor?.enumerable !== true) {\n\t\t\tthrow new InvalidDomainMachineDefinitionError(\n\t\t\t\t`Domain machine ${entryName} names must be enumerable string properties.`,\n\t\t\t);\n\t\t}\n\t}\n}\n\nfunction readDomainMachineDefinitionProperty(\n\tvalue: object,\n\tkey: PropertyKey,\n): unknown {\n\tconst descriptor = Object.getOwnPropertyDescriptor(value, key);\n\tif (descriptor === undefined || !(\"value\" in descriptor)) {\n\t\tthrow new InvalidDomainMachineDefinitionError(\n\t\t\t\"Domain machine definition must contain data properties only.\",\n\t\t);\n\t}\n\n\treturn descriptor.value;\n}\n\nfunction readOptionalDomainMachineDefinitionProperty(\n\tvalue: object,\n\tkey: PropertyKey,\n): unknown {\n\tconst descriptor = Object.getOwnPropertyDescriptor(value, key);\n\tif (descriptor === undefined) return undefined;\n\tif (!(\"value\" in descriptor)) {\n\t\tthrow new InvalidDomainMachineDefinitionError(\n\t\t\t\"Domain machine definition must contain data properties only.\",\n\t\t);\n\t}\n\n\treturn descriptor.value;\n}\n","import { DomainError } from \"../core/errors\";\nimport type {\n\tDomainMachineDefinition,\n\tDomainMachineInput,\n\tDomainMachineReadonly,\n\tDomainMachineSnapshot,\n\tDomainTransitionResult,\n} from \"./contracts\";\nimport {\n\tInvalidDomainMachineDefinitionError,\n\tInvalidDomainMachineInputError,\n\tInvalidDomainMachineSnapshotError,\n\tInvalidDomainTransitionGuardResultError,\n\tInvalidDomainTransitionResultError,\n} from \"./errors\";\nimport {\n\tcopyDomainMachineContext,\n\thasOwn,\n\tisPlainRecord,\n\tisRecord,\n} from \"./machine-data\";\n\nconst DOMAIN_TRANSITION_RESULT_KEYS: ReadonlySet<PropertyKey> = new Set([\n\t\"context\",\n\t\"outputs\",\n]);\n\nexport function prepareDomainMachineSnapshot<\n\tTState extends string,\n\tTContext,\n\tTInput extends DomainMachineInput,\n\tTOutput,\n>(\n\tdefinition: DomainMachineDefinition<TState, TContext, TInput, TOutput>,\n\tsnapshot: DomainMachineSnapshot<TState, TContext>,\n): DomainMachineSnapshot<TState, TContext> {\n\tvalidateDomainMachineSnapshot(definition, snapshot);\n\tconst preparedSnapshot = createDomainMachineSnapshot<TState, TContext>(\n\t\tsnapshot,\n\t);\n\t// Re-validate the COPY: a Proxy can answer the copy's reads differently\n\t// from validation's (TOCTOU), and the copy is what the machine runs on.\n\tvalidateDomainMachineSnapshot(definition, preparedSnapshot);\n\tvalidateDomainMachineSnapshotInvariant(definition, preparedSnapshot);\n\treturn preparedSnapshot;\n}\n\nexport function createDomainMachineSnapshotFromPreparedContext<\n\tTState extends string,\n\tTContext,\n>(\n\tstate: TState,\n\tcontext: DomainMachineReadonly<TContext>,\n): DomainMachineSnapshot<TState, TContext> {\n\treturn Object.freeze({ state, context });\n}\n\nexport function createDomainMachineSnapshot<\n\tTState extends string,\n\tTContext,\n>(snapshot: {\n\treadonly state: TState;\n\treadonly context: TContext | DomainMachineReadonly<TContext>;\n}): DomainMachineSnapshot<TState, TContext> {\n\treturn Object.freeze({\n\t\tstate: readDomainMachineSnapshotState(snapshot),\n\t\tcontext: copyDomainMachineContext<TContext>(\n\t\t\treadDomainMachineSnapshotContext(snapshot),\n\t\t),\n\t}) as DomainMachineSnapshot<TState, TContext>;\n}\n\nexport function validateDomainMachineSnapshot<\n\tTState extends string,\n\tTContext,\n\tTInput extends DomainMachineInput,\n\tTOutput,\n>(\n\tdefinition: DomainMachineDefinition<TState, TContext, TInput, TOutput>,\n\tsnapshot: DomainMachineSnapshot<TState, TContext>,\n): void {\n\tif (!isRecord(snapshot)) {\n\t\tthrow new InvalidDomainMachineSnapshotError(\n\t\t\t\"Domain machine snapshot must be an object.\",\n\t\t);\n\t}\n\n\tconst state = readDomainMachineSnapshotState(snapshot);\n\treadDomainMachineSnapshotContext(snapshot);\n\n\tif (!hasOwn(definition.states, state)) {\n\t\tthrow new InvalidDomainMachineSnapshotError(\n\t\t\t`Domain machine snapshot state \"${state}\" is not defined.`,\n\t\t);\n\t}\n}\n\nexport function validateDomainMachineSnapshotInvariant<\n\tTState extends string,\n\tTContext,\n\tTInput extends DomainMachineInput,\n\tTOutput,\n>(\n\tdefinition: DomainMachineDefinition<TState, TContext, TInput, TOutput>,\n\tsnapshot: DomainMachineSnapshot<TState, TContext>,\n): void {\n\tconst stateNode = definition.states[snapshot.state];\n\tif (stateNode.validateContext !== undefined) {\n\t\tconst validContext = stateNode.validateContext({\n\t\t\tstate: snapshot.state,\n\t\t\tcontext: snapshot.context,\n\t\t});\n\t\tif (typeof validContext !== \"boolean\") {\n\t\t\tthrow new InvalidDomainMachineDefinitionError(\n\t\t\t\t`Domain machine state \"${snapshot.state}\" validateContext must return a boolean.`,\n\t\t\t);\n\t\t}\n\t\tif (!validContext) {\n\t\t\tthrow new InvalidDomainMachineSnapshotError(\n\t\t\t\t`Domain machine snapshot violates the context invariant for state \"${snapshot.state}\".`,\n\t\t\t);\n\t\t}\n\t}\n\n\tif (definition.validateSnapshot === undefined) return;\n\n\tconst valid = definition.validateSnapshot(snapshot);\n\tif (typeof valid !== \"boolean\") {\n\t\tthrow new InvalidDomainMachineDefinitionError(\n\t\t\t\"Domain machine validateSnapshot must return a boolean.\",\n\t\t);\n\t}\n\n\tif (!valid) {\n\t\tthrow new InvalidDomainMachineSnapshotError(\n\t\t\t`Domain machine snapshot violates invariants for state \"${snapshot.state}\".`,\n\t\t);\n\t}\n}\n\nfunction readDomainMachineSnapshotState<TState extends string>(snapshot: {\n\treadonly state: TState;\n}): TState {\n\tconst stateDescriptor = Object.getOwnPropertyDescriptor(snapshot, \"state\");\n\tif (\n\t\tstateDescriptor === undefined ||\n\t\t!(\"value\" in stateDescriptor) ||\n\t\ttypeof stateDescriptor.value !== \"string\"\n\t) {\n\t\tthrow new InvalidDomainMachineSnapshotError(\n\t\t\t\"Domain machine snapshot state must be a string data property.\",\n\t\t);\n\t}\n\n\treturn stateDescriptor.value as TState;\n}\n\nfunction readDomainMachineSnapshotContext<TContext>(snapshot: {\n\treadonly context: TContext;\n}): TContext {\n\tconst contextDescriptor = Object.getOwnPropertyDescriptor(\n\t\tsnapshot,\n\t\t\"context\",\n\t);\n\tif (contextDescriptor === undefined || !(\"value\" in contextDescriptor)) {\n\t\tthrow new InvalidDomainMachineSnapshotError(\n\t\t\t\"Domain machine snapshot context must be present as a data property.\",\n\t\t);\n\t}\n\n\treturn contextDescriptor.value as TContext;\n}\n\nexport function validateDomainMachineInput(\n\tinput: unknown,\n): asserts input is DomainMachineInput {\n\tif (!isDomainMachineInput(input)) {\n\t\tthrow new InvalidDomainMachineInputError(\n\t\t\t\"Domain machine input must be an object with a string type.\",\n\t\t);\n\t}\n}\n\nexport function isDomainMachineInput(\n\tinput: unknown,\n): input is DomainMachineInput {\n\tif (!isRecord(input)) return false;\n\n\tconst typeDescriptor = Object.getOwnPropertyDescriptor(input, \"type\");\n\treturn (\n\t\ttypeDescriptor !== undefined &&\n\t\t\"value\" in typeDescriptor &&\n\t\ttypeof typeDescriptor.value === \"string\"\n\t);\n}\n\nexport function resolveDomainTransitionGuardResult(\n\tresult: unknown,\n):\n\t| { readonly allowed: true }\n\t| { readonly allowed: false; readonly rejection?: DomainError } {\n\tif (typeof result === \"boolean\") return { allowed: result };\n\tif (result instanceof DomainError) {\n\t\treturn { allowed: false, rejection: result };\n\t}\n\n\tthrow new InvalidDomainTransitionGuardResultError(\n\t\t\"Domain transition guard must return a boolean or DomainError.\",\n\t);\n}\n\nexport function validateDomainTransitionResult<TContext, TOutput>(\n\tresult: DomainTransitionResult<TContext, TOutput> | undefined,\n): void {\n\tif (result === undefined) return;\n\n\tif (!isPlainRecord(result)) {\n\t\tthrow new InvalidDomainTransitionResultError(\n\t\t\t\"Domain transition result must be a plain object when returned.\",\n\t\t);\n\t}\n\n\tfor (const key of Reflect.ownKeys(result)) {\n\t\tif (!DOMAIN_TRANSITION_RESULT_KEYS.has(key)) {\n\t\t\tthrow new InvalidDomainTransitionResultError(\n\t\t\t\t`Domain transition result contains unknown property \"${String(key)}\".`,\n\t\t\t);\n\t\t}\n\t\tconst descriptor = Object.getOwnPropertyDescriptor(result, key);\n\t\tif (descriptor !== undefined && !(\"value\" in descriptor)) {\n\t\t\tthrow new InvalidDomainTransitionResultError(\n\t\t\t\t\"Domain transition result must contain data properties only.\",\n\t\t\t);\n\t\t}\n\t}\n\n\tconst outputs = readDomainTransitionResultOutputs(result);\n\tif (outputs !== undefined && !Array.isArray(outputs)) {\n\t\tthrow new InvalidDomainTransitionResultError(\n\t\t\t\"Domain transition result outputs must be an array when provided.\",\n\t\t);\n\t}\n}\n\nexport function readDomainTransitionResultContext<TContext, TOutput>(\n\tresult: DomainTransitionResult<TContext, TOutput> | undefined,\n):\n\t| { readonly hasContext: false }\n\t| { readonly hasContext: true; readonly context: TContext } {\n\tif (result === undefined) return { hasContext: false };\n\n\tconst contextDescriptor = Object.getOwnPropertyDescriptor(result, \"context\");\n\tif (contextDescriptor === undefined) return { hasContext: false };\n\tif (!(\"value\" in contextDescriptor)) {\n\t\tthrow new InvalidDomainTransitionResultError(\n\t\t\t\"Domain transition result context must be a data property when provided.\",\n\t\t);\n\t}\n\n\treturn { hasContext: true, context: contextDescriptor.value as TContext };\n}\n\nexport function readDomainTransitionResultOutputs<TContext, TOutput>(\n\tresult: DomainTransitionResult<TContext, TOutput> | undefined,\n): readonly TOutput[] | undefined {\n\tif (result === undefined) return undefined;\n\n\tconst outputsDescriptor = Object.getOwnPropertyDescriptor(result, \"outputs\");\n\tif (outputsDescriptor === undefined) return undefined;\n\tif (!(\"value\" in outputsDescriptor)) {\n\t\tthrow new InvalidDomainTransitionResultError(\n\t\t\t\"Domain transition result outputs must be a data property when provided.\",\n\t\t);\n\t}\n\n\treturn outputsDescriptor.value as readonly TOutput[] | undefined;\n}\n","import type {\n\tDomainMachineDefinition,\n\tDomainMachineInput,\n\tDomainMachineSnapshot,\n\tDomainTransitionOutcome,\n} from \"./contracts\";\nimport {\n\tensureStableDomainMachineDefinition,\n\tgetTransition,\n} from \"./definition\";\nimport {\n\tDomainTransitionGuardRejectedError,\n\tInvalidDomainTransitionError,\n} from \"./errors\";\nimport {\n\tcopyDomainMachineInput,\n\tcopyDomainMachineOutputs,\n} from \"./machine-data\";\nimport {\n\tcreateDomainMachineSnapshot,\n\tcreateDomainMachineSnapshotFromPreparedContext,\n\tisDomainMachineInput,\n\tprepareDomainMachineSnapshot,\n\treadDomainTransitionResultContext,\n\treadDomainTransitionResultOutputs,\n\tresolveDomainTransitionGuardResult,\n\tvalidateDomainMachineInput,\n\tvalidateDomainMachineSnapshotInvariant,\n\tvalidateDomainTransitionResult,\n} from \"./snapshot\";\n\n/** Creates and validates a fresh initial snapshot from a machine definition. */\nexport function createInitialDomainMachineSnapshot<\n\tTState extends string,\n\tTContext,\n\tTInput extends DomainMachineInput,\n\tTOutput,\n>(\n\tdefinition: DomainMachineDefinition<TState, TContext, TInput, TOutput>,\n): DomainMachineSnapshot<TState, TContext> {\n\tconst stableDefinition = ensureStableDomainMachineDefinition(definition);\n\treturn createInitialDomainMachineSnapshotFromPrepared(stableDefinition);\n}\n\nexport function createInitialDomainMachineSnapshotFromPrepared<\n\tTState extends string,\n\tTContext,\n\tTInput extends DomainMachineInput,\n\tTOutput,\n>(\n\tdefinition: DomainMachineDefinition<TState, TContext, TInput, TOutput>,\n): DomainMachineSnapshot<TState, TContext> {\n\tconst snapshot = createDomainMachineSnapshot<TState, TContext>({\n\t\tstate: definition.initial,\n\t\tcontext: definition.initialContext(),\n\t});\n\tvalidateDomainMachineSnapshotInvariant(definition, snapshot);\n\treturn snapshot;\n}\n\n/**\n * Checks whether an input currently has an allowed transition.\n *\n * Returns `false` for missing transitions, terminal states, rejected guards,\n * and inputs without an own string `type` property. Invalid payload data for a\n * matching transition and broken guard code still throw structured errors.\n */\nexport function canTransitionDomainState<\n\tTState extends string,\n\tTContext,\n\tTInput extends DomainMachineInput,\n\tTOutput,\n>(\n\tdefinition: DomainMachineDefinition<TState, TContext, TInput, TOutput>,\n\tsnapshot: DomainMachineSnapshot<TState, TContext>,\n\tinput: TInput,\n): boolean {\n\tconst stableDefinition = ensureStableDomainMachineDefinition(definition);\n\tconst currentSnapshot = prepareDomainMachineSnapshot(\n\t\tstableDefinition,\n\t\tsnapshot,\n\t);\n\treturn canTransitionPreparedDomainState(\n\t\tstableDefinition,\n\t\tcurrentSnapshot,\n\t\tinput,\n\t);\n}\n\nexport function canTransitionPreparedDomainState<\n\tTState extends string,\n\tTContext,\n\tTInput extends DomainMachineInput,\n\tTOutput,\n>(\n\tdefinition: DomainMachineDefinition<TState, TContext, TInput, TOutput>,\n\tsnapshot: DomainMachineSnapshot<TState, TContext>,\n\tinput: TInput,\n): boolean {\n\tif (!isDomainMachineInput(input)) return false;\n\n\tconst stateNode = definition.states[snapshot.state];\n\tif (stateNode.terminal === true) return false;\n\n\tconst transition = getTransition(definition, snapshot.state, input);\n\tif (!transition) return false;\n\n\tconst currentInput = copyDomainMachineInput(input);\n\tif (!transition.guard) return true;\n\n\tconst guardResult = transition.guard({\n\t\tstate: snapshot.state,\n\t\tcontext: snapshot.context,\n\t\tinput: currentInput,\n\t});\n\n\treturn resolveDomainTransitionGuardResult(guardResult).allowed;\n}\n\n/**\n * Applies one input without mutating the input definition or snapshot.\n *\n * @throws {@link InvalidDomainTransitionError} when no transition is defined.\n * @throws {@link DomainTransitionGuardRejectedError} when its guard rejects.\n * @throws A concrete `DomainError` returned by a rejecting guard.\n */\nexport function transitionDomainState<\n\tTState extends string,\n\tTContext,\n\tTInput extends DomainMachineInput,\n\tTOutput,\n>(\n\tdefinition: DomainMachineDefinition<TState, TContext, TInput, TOutput>,\n\tsnapshot: DomainMachineSnapshot<TState, TContext>,\n\tinput: TInput,\n): DomainTransitionOutcome<TState, TContext, TOutput> {\n\tconst stableDefinition = ensureStableDomainMachineDefinition(definition);\n\tconst currentSnapshot = prepareDomainMachineSnapshot(\n\t\tstableDefinition,\n\t\tsnapshot,\n\t);\n\treturn transitionPreparedDomainState(\n\t\tstableDefinition,\n\t\tcurrentSnapshot,\n\t\tinput,\n\t);\n}\n\nexport function transitionPreparedDomainState<\n\tTState extends string,\n\tTContext,\n\tTInput extends DomainMachineInput,\n\tTOutput,\n>(\n\tdefinition: DomainMachineDefinition<TState, TContext, TInput, TOutput>,\n\tsnapshot: DomainMachineSnapshot<TState, TContext>,\n\tinput: TInput,\n): DomainTransitionOutcome<TState, TContext, TOutput> {\n\tvalidateDomainMachineInput(input);\n\n\tconst from = snapshot.state;\n\tconst stateNode = definition.states[from];\n\tconst transition =\n\t\tstateNode.terminal === true\n\t\t\t? undefined\n\t\t\t: getTransition(definition, from, input);\n\n\tif (!transition) {\n\t\tthrow new InvalidDomainTransitionError(from, input.type);\n\t}\n\n\tconst currentInput = copyDomainMachineInput(input);\n\tconst guardResult =\n\t\ttransition.guard === undefined\n\t\t\t? true\n\t\t\t: transition.guard({\n\t\t\t\t\tstate: from,\n\t\t\t\t\tcontext: snapshot.context,\n\t\t\t\t\tinput: currentInput,\n\t\t\t\t});\n\tconst guardDecision = resolveDomainTransitionGuardResult(guardResult);\n\n\tif (!guardDecision.allowed) {\n\t\tif (guardDecision.rejection !== undefined) {\n\t\t\tthrow guardDecision.rejection;\n\t\t}\n\t\tthrow new DomainTransitionGuardRejectedError(from, currentInput.type);\n\t}\n\n\tconst result = transition.reduce?.({\n\t\tstate: from,\n\t\tcontext: snapshot.context,\n\t\tinput: currentInput,\n\t});\n\tvalidateDomainTransitionResult(result);\n\tconst contextResult = readDomainTransitionResultContext(result);\n\tconst nextContext = contextResult.hasContext\n\t\t? contextResult.context\n\t\t: snapshot.context;\n\tconst nextSnapshot =\n\t\tnextContext === snapshot.context\n\t\t\t? createDomainMachineSnapshotFromPreparedContext<TState, TContext>(\n\t\t\t\t\ttransition.target,\n\t\t\t\t\tsnapshot.context,\n\t\t\t\t)\n\t\t\t: createDomainMachineSnapshot<TState, TContext>({\n\t\t\t\t\tstate: transition.target,\n\t\t\t\t\tcontext: nextContext,\n\t\t\t\t});\n\tvalidateDomainMachineSnapshotInvariant(definition, nextSnapshot);\n\n\t// Frozen like every sibling return value (snapshots, outputs, the\n\t// analyzer result): the contract types the fields readonly, and the\n\t// runtime must not allow a cast to rewrite from/to.\n\treturn Object.freeze({\n\t\tfrom,\n\t\tto: transition.target,\n\t\tsnapshot: nextSnapshot,\n\t\toutputs: copyDomainMachineOutputs(\n\t\t\treadDomainTransitionResultOutputs(result),\n\t\t),\n\t});\n}\n","import type { DomainMachineDefinition, DomainMachineInput } from \"./contracts\";\nimport { ensureStableDomainMachineDefinition } from \"./definition\";\n\nexport type DomainMachineDefinitionDiagnostic<TState extends string> =\n\t| {\n\t\t\treadonly code: \"unreachable-state\";\n\t\t\treadonly state: TState;\n\t }\n\t| {\n\t\t\treadonly code: \"structural-dead-end\";\n\t\t\treadonly state: TState;\n\t }\n\t| {\n\t\t\treadonly code: \"no-terminal-path\";\n\t\t\treadonly state: TState;\n\t };\n\nexport type DomainMachineTransitionDescription<\n\tTState extends string,\n\tTInputType extends string,\n> = {\n\treadonly state: TState;\n\treadonly inputType: TInputType;\n\treadonly target: TState;\n\treadonly guarded: boolean;\n};\n\nexport type DomainMachineDefinitionAnalysis<\n\tTState extends string,\n\tTInputType extends string,\n> = {\n\treadonly diagnostics: readonly DomainMachineDefinitionDiagnostic<TState>[];\n\treadonly transitions: readonly DomainMachineTransitionDescription<\n\t\tTState,\n\t\tTInputType\n\t>[];\n\t/** States reachable when every guard is assumed to allow its transition. */\n\treadonly structurallyReachableStates: readonly TState[];\n\t/** States with a graph path to a terminal state when every guard is assumed to allow it. */\n\treadonly statesWithTerminalPath: readonly TState[];\n};\n\n/**\n * Inspects the declarative transition graph without executing definition callbacks.\n * Guarded edges are treated as possible edges, so diagnostics never claim more\n * runtime reachability than the static graph can prove.\n */\nexport function analyzeDomainMachineDefinition<\n\tTState extends string,\n\tTContext,\n\tTInput extends DomainMachineInput,\n\tTOutput,\n>(\n\tdefinition: DomainMachineDefinition<TState, TContext, TInput, TOutput>,\n): DomainMachineDefinitionAnalysis<TState, TInput[\"type\"]> {\n\t// The shared entry-point normalization: a prepared definition passes\n\t// through untouched (already validated, copied, frozen), a raw one\n\t// pays the documented per-call validate-and-copy.\n\tconst stableDefinition = ensureStableDomainMachineDefinition(definition);\n\tconst states = (Object.keys(stableDefinition.states) as TState[]).sort(\n\t\tcompareStrings,\n\t);\n\tconst outgoing = new Map<TState, TState[]>();\n\tconst incoming = new Map<TState, TState[]>();\n\tconst transitions: DomainMachineTransitionDescription<\n\t\tTState,\n\t\tTInput[\"type\"]\n\t>[] = [];\n\n\tfor (const state of states) {\n\t\toutgoing.set(state, []);\n\t\tincoming.set(state, []);\n\t}\n\n\tfor (const state of states) {\n\t\tconst stateTransitions = stableDefinition.states[state].on;\n\t\tconst inputTypes = (\n\t\t\tObject.keys(stateTransitions ?? {}) as TInput[\"type\"][]\n\t\t).sort(compareStrings);\n\n\t\tfor (const inputType of inputTypes) {\n\t\t\tconst transition = stateTransitions?.[inputType];\n\t\t\tif (transition === undefined) continue;\n\n\t\t\toutgoing.get(state)?.push(transition.target);\n\t\t\tincoming.get(transition.target)?.push(state);\n\t\t\ttransitions.push(\n\t\t\t\tObject.freeze({\n\t\t\t\t\tstate,\n\t\t\t\t\tinputType,\n\t\t\t\t\ttarget: transition.target,\n\t\t\t\t\tguarded: transition.guard !== undefined,\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\t}\n\n\tconst structurallyReachable = visitGraph(\n\t\t[stableDefinition.initial],\n\t\toutgoing,\n\t);\n\tconst terminalStates = states.filter(\n\t\t(state) => stableDefinition.states[state].terminal === true,\n\t);\n\tconst statesWithTerminalPath = visitGraph(terminalStates, incoming);\n\tconst diagnostics: DomainMachineDefinitionDiagnostic<TState>[] = [];\n\n\tfor (const state of states) {\n\t\tif (!structurallyReachable.has(state)) {\n\t\t\tdiagnostics.push(Object.freeze({ code: \"unreachable-state\", state }));\n\t\t}\n\t}\n\tfor (const state of states) {\n\t\tif (\n\t\t\tstableDefinition.states[state].terminal !== true &&\n\t\t\toutgoing.get(state)?.length === 0\n\t\t) {\n\t\t\tdiagnostics.push(Object.freeze({ code: \"structural-dead-end\", state }));\n\t\t}\n\t}\n\tfor (const state of states) {\n\t\tif (!statesWithTerminalPath.has(state)) {\n\t\t\tdiagnostics.push(Object.freeze({ code: \"no-terminal-path\", state }));\n\t\t}\n\t}\n\n\treturn Object.freeze({\n\t\tdiagnostics: Object.freeze(diagnostics),\n\t\ttransitions: Object.freeze(transitions),\n\t\tstructurallyReachableStates: Object.freeze(\n\t\t\tstates.filter((state) => structurallyReachable.has(state)),\n\t\t),\n\t\tstatesWithTerminalPath: Object.freeze(\n\t\t\tstates.filter((state) => statesWithTerminalPath.has(state)),\n\t\t),\n\t});\n}\n\nfunction visitGraph<TState extends string>(\n\tstartStates: readonly TState[],\n\tedges: ReadonlyMap<TState, readonly TState[]>,\n): ReadonlySet<TState> {\n\tconst visited = new Set<TState>();\n\tconst pending = [...startStates];\n\n\twhile (pending.length > 0) {\n\t\tconst state = pending.pop();\n\t\tif (state === undefined || visited.has(state)) continue;\n\n\t\tvisited.add(state);\n\t\tfor (const next of edges.get(state) ?? []) {\n\t\t\tif (!visited.has(next)) pending.push(next);\n\t\t}\n\t}\n\n\treturn visited;\n}\n\nfunction compareStrings(left: string, right: string): number {\n\treturn left < right ? -1 : left > right ? 1 : 0;\n}\n","import type {\n\tDomainMachineDefinition,\n\tDomainMachineInput,\n\tDomainMachineReadonly,\n\tDomainMachineSnapshot,\n\tDomainTransitionOutcome,\n} from \"./contracts\";\nimport { ensureStableDomainMachineDefinition } from \"./definition\";\nimport { ReentrantDomainStateMachineEvaluationError } from \"./errors\";\nimport {\n\tcreateDomainMachineSnapshot,\n\tprepareDomainMachineSnapshot,\n} from \"./snapshot\";\nimport {\n\tcanTransitionPreparedDomainState,\n\tcreateInitialDomainMachineSnapshotFromPrepared,\n\ttransitionPreparedDomainState,\n} from \"./transition\";\n\nexport type {\n\tDomainMachineDefinitionAnalysis,\n\tDomainMachineDefinitionDiagnostic,\n\tDomainMachineTransitionDescription,\n} from \"./analyzer\";\nexport { analyzeDomainMachineDefinition } from \"./analyzer\";\nexport type {\n\tDomainMachineDefinition,\n\tDomainMachineInput,\n\tDomainMachineReadonly,\n\tDomainMachineSnapshot,\n\tDomainStateNode,\n\tDomainTransition,\n\tDomainTransitionGuardResult,\n\tDomainTransitionOutcome,\n\tDomainTransitionResult,\n} from \"./contracts\";\nexport {\n\ttype PreparedDomainMachineDefinition,\n\tprepareDomainMachineDefinition,\n} from \"./definition\";\nexport {\n\tDomainTransitionGuardRejectedError,\n\tInvalidDomainMachineContextError,\n\tInvalidDomainMachineDefinitionError,\n\tInvalidDomainMachineInputError,\n\tInvalidDomainMachineSnapshotError,\n\tInvalidDomainTransitionError,\n\tInvalidDomainTransitionGuardResultError,\n\tInvalidDomainTransitionResultError,\n\tReentrantDomainStateMachineEvaluationError,\n} from \"./errors\";\nexport {\n\tcanTransitionDomainState,\n\tcreateInitialDomainMachineSnapshot,\n\ttransitionDomainState,\n} from \"./transition\";\n\n/**\n * Stateful convenience wrapper around the pure domain transition functions.\n *\n * Persist {@link snapshot}, not the machine instance. Pass a restored snapshot\n * to the second constructor overload to validate and reconstitute a machine.\n */\nexport class DomainStateMachine<\n\tTState extends string,\n\tTContext,\n\tTInput extends DomainMachineInput,\n\tTOutput = never,\n> {\n\tprivate readonly definition: DomainMachineDefinition<\n\t\tTState,\n\t\tTContext,\n\t\tTInput,\n\t\tTOutput\n\t>;\n\n\t#snapshot: DomainMachineSnapshot<TState, TContext>;\n\t#evaluating = false;\n\n\tconstructor(\n\t\tdefinition: DomainMachineDefinition<TState, TContext, TInput, TOutput>,\n\t);\n\tconstructor(\n\t\tdefinition: DomainMachineDefinition<TState, TContext, TInput, TOutput>,\n\t\tsnapshot: DomainMachineSnapshot<TState, TContext> | undefined,\n\t);\n\tconstructor(\n\t\tdefinition: DomainMachineDefinition<TState, TContext, TInput, TOutput>,\n\t\t...snapshotInput: [] | [DomainMachineSnapshot<TState, TContext> | undefined]\n\t) {\n\t\t// A prepared definition (prepareDomainMachineDefinition) passes\n\t\t// through; a raw one pays the one-time validate-and-copy here.\n\t\tthis.definition = ensureStableDomainMachineDefinition(definition);\n\t\t// Resolve the overload by the argument value, not the rest-parameter\n\t\t// arity: an explicit `undefined` snapshot (a natural result of a\n\t\t// nullable `repo.loadSnapshot(id)` or `map.get(id)` passed straight\n\t\t// through) means \"no snapshot\", so it must fall back to the initial\n\t\t// snapshot instead of failing validation.\n\t\tconst [suppliedSnapshot] = snapshotInput;\n\t\tif (suppliedSnapshot !== undefined) {\n\t\t\t// One shared implementation with the pure path (transition.ts);\n\t\t\t// hand-rolling the validate-copy-validate trio here would let\n\t\t\t// the class and pure snapshot preparation drift.\n\t\t\tthis.#snapshot = prepareDomainMachineSnapshot(\n\t\t\t\tthis.definition,\n\t\t\t\tsuppliedSnapshot,\n\t\t\t);\n\t\t} else {\n\t\t\tthis.#snapshot = createInitialDomainMachineSnapshotFromPrepared(\n\t\t\t\tthis.definition,\n\t\t\t);\n\t\t}\n\t}\n\n\t/** Returns a defensive, deeply frozen copy of the current snapshot. */\n\tget snapshot(): DomainMachineSnapshot<TState, TContext> {\n\t\treturn createDomainMachineSnapshot<TState, TContext>(this.#snapshot);\n\t}\n\n\t/** Current named control state. */\n\tget state(): TState {\n\t\treturn this.#snapshot.state;\n\t}\n\n\t/** Current deeply readonly context. */\n\tget context(): DomainMachineReadonly<TContext> {\n\t\treturn this.#snapshot.context;\n\t}\n\n\t/** Whether the current state permanently forbids outgoing transitions. */\n\tisTerminal(): boolean {\n\t\treturn this.definition.states[this.state].terminal === true;\n\t}\n\n\t/** Checks a transition without changing the current snapshot. */\n\tcan(input: TInput): boolean {\n\t\treturn this.evaluate(() =>\n\t\t\tcanTransitionPreparedDomainState(this.definition, this.#snapshot, input),\n\t\t);\n\t}\n\n\t/** Applies an input and advances the current snapshot on success. */\n\tdispatch(input: TInput): DomainTransitionOutcome<TState, TContext, TOutput> {\n\t\treturn this.evaluate(() => {\n\t\t\tconst result = transitionPreparedDomainState(\n\t\t\t\tthis.definition,\n\t\t\t\tthis.#snapshot,\n\t\t\t\tinput,\n\t\t\t);\n\t\t\tthis.#snapshot = result.snapshot;\n\t\t\treturn result;\n\t\t});\n\t}\n\n\tprivate evaluate<TResult>(operation: () => TResult): TResult {\n\t\tif (this.#evaluating) {\n\t\t\tthrow new ReentrantDomainStateMachineEvaluationError();\n\t\t}\n\n\t\tthis.#evaluating = true;\n\t\ttry {\n\t\t\treturn operation();\n\t\t} finally {\n\t\t\tthis.#evaluating = false;\n\t\t}\n\t}\n}\n","import type { AnyDomainEvent } from \"../aggregate/domain-event\";\nimport { abortReason } from \"../utils/abort\";\nimport {\n\tDEFAULT_EXECUTION_TIMEOUT_MS,\n\ttype ExecutionContext,\n\trunBoundedExecution,\n} from \"../utils/execution\";\nimport type {\n\tEventBus,\n\tEventHandler,\n\tOnceOptions,\n\tPublishOptions,\n} from \"./ports\";\n\n/**\n * Simple in-memory event bus implementation.\n * Supports multiple subscribers per event type (pub/sub pattern).\n *\n * @template Evt - The type of domain events (must extend DomainEvent)\n *\n * @example\n * ```typescript\n * const bus = new EventBusImpl<OrderEvent>();\n *\n * bus.subscribe(\"OrderCreated\", async (event) => {\n * await sendEmail(event.payload.customerId);\n * });\n *\n * bus.subscribe(\"OrderCreated\", async (event) => {\n * await logEvent(event);\n * });\n *\n * await bus.publish([orderCreatedEvent]);\n * // Both handlers will be called\n * ```\n */\nexport class EventBusImpl<Evt extends AnyDomainEvent> implements EventBus<Evt> {\n\tprivate readonly handlers = new Map<string, EventHandler<Evt>[]>();\n\tprivate readonly catchAllHandlers: EventHandler<Evt>[] = [];\n\n\tsubscribe<K extends Evt[\"type\"]>(\n\t\teventType: K,\n\t\thandler: EventHandler<Extract<Evt, { type: K }>>,\n\t): () => void {\n\t\tconst type = eventType;\n\t\tif (!this.handlers.has(type)) {\n\t\t\tthis.handlers.set(type, []);\n\t\t}\n\t\tconst handlersForType = this.handlers.get(type)!;\n\t\tconst casted = handler as EventHandler<Evt>;\n\t\thandlersForType.push(casted);\n\n\t\t// Return unsubscribe: removes exactly this subscription, even if the\n\t\t// same handler reference was subscribed multiple times (each call to\n\t\t// subscribe gets its own unsubscribe).\n\t\tlet removed = false;\n\t\treturn () => {\n\t\t\tif (removed) return;\n\t\t\tconst idx = handlersForType.indexOf(casted);\n\t\t\tif (idx !== -1) {\n\t\t\t\thandlersForType.splice(idx, 1);\n\t\t\t\tremoved = true;\n\t\t\t}\n\t\t\tif (handlersForType.length === 0) {\n\t\t\t\tthis.handlers.delete(type);\n\t\t\t}\n\t\t};\n\t}\n\n\t/**\n\t * See {@link EventBus.subscribeAll}: every published event, in the\n\t * same dispatch batch as its typed handlers.\n\t */\n\tsubscribeAll(handler: EventHandler<Evt>): () => void {\n\t\tthis.catchAllHandlers.push(handler);\n\n\t\t// Unsubscribe semantics as in subscribe(): removes exactly this\n\t\t// subscription, even when the same handler reference was\n\t\t// subscribed multiple times.\n\t\tlet removed = false;\n\t\treturn () => {\n\t\t\tif (removed) return;\n\t\t\tconst idx = this.catchAllHandlers.indexOf(handler);\n\t\t\tif (idx !== -1) {\n\t\t\t\tthis.catchAllHandlers.splice(idx, 1);\n\t\t\t\tremoved = true;\n\t\t\t}\n\t\t};\n\t}\n\n\tonce<K extends Evt[\"type\"]>(\n\t\teventType: K,\n\t\toptions?: OnceOptions,\n\t): Promise<Extract<Evt, { type: K }>> {\n\t\treturn new Promise<Extract<Evt, { type: K }>>((resolve, reject) => {\n\t\t\t// Reject synchronously if the signal is already aborted; don't\n\t\t\t// even subscribe.\n\t\t\tif (options?.signal?.aborted) {\n\t\t\t\treject(abortReason(options.signal, \"EventBus.once aborted\"));\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tlet timer: ReturnType<typeof setTimeout> | undefined;\n\t\t\tlet settled = false;\n\t\t\tlet abortListener: (() => void) | undefined;\n\n\t\t\tconst cleanup = () => {\n\t\t\t\tif (settled) return;\n\t\t\t\tsettled = true;\n\t\t\t\tunsubscribe();\n\t\t\t\tif (timer !== undefined) clearTimeout(timer);\n\t\t\t\tif (abortListener && options?.signal) {\n\t\t\t\t\toptions.signal.removeEventListener(\"abort\", abortListener);\n\t\t\t\t}\n\t\t\t};\n\n\t\t\tconst unsubscribe = this.subscribe(eventType, (event) => {\n\t\t\t\tcleanup();\n\t\t\t\tresolve(event);\n\t\t\t});\n\n\t\t\tif (options?.signal) {\n\t\t\t\tabortListener = () => {\n\t\t\t\t\tcleanup();\n\t\t\t\t\treject(abortReason(options.signal!, \"EventBus.once aborted\"));\n\t\t\t\t};\n\t\t\t\toptions.signal.addEventListener(\"abort\", abortListener);\n\t\t\t}\n\n\t\t\tif (typeof options?.timeoutMs === \"number\") {\n\t\t\t\ttimer = setTimeout(() => {\n\t\t\t\t\tcleanup();\n\t\t\t\t\treject(\n\t\t\t\t\t\tnew Error(\n\t\t\t\t\t\t\t`EventBus.once timed out after ${options.timeoutMs}ms waiting for \"${eventType}\"`,\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\t}, options.timeoutMs);\n\t\t\t}\n\t\t});\n\t}\n\n\t/**\n\t * See {@link EventBus.publish} for the full ordering / parallelism /\n\t * error-aggregation contract this implementation realises:\n\t * - events in input order, sequentially;\n\t * - handlers within one event in parallel via `Promise.allSettled`;\n\t * - errors collected and thrown after the batch (single Error, or\n\t * `AggregateError` for multiple failures).\n\t */\n\tasync publish(\n\t\tevents: ReadonlyArray<Evt>,\n\t\toptions: PublishOptions = {},\n\t): Promise<void> {\n\t\t// The errors array lives HERE, outside the bounded execution: the\n\t\t// abort/timeout race can reject while handlers already failed, and\n\t\t// the port contract promises that collected handler errors are\n\t\t// thrown after dispatch. An abort ends the batch but must not\n\t\t// swallow the failures that already happened.\n\t\tconst errors: Error[] = [];\n\t\ttry {\n\t\t\tawait runBoundedExecution(\n\t\t\t\t\"EventBus.publish\",\n\t\t\t\t{\n\t\t\t\t\tsignal: options.signal,\n\t\t\t\t\ttimeoutMs: options.timeoutMs ?? DEFAULT_EXECUTION_TIMEOUT_MS,\n\t\t\t\t},\n\t\t\t\t(context) => this.publishWithinContext(events, context, errors),\n\t\t\t);\n\t\t} catch (boundedError) {\n\t\t\tif (errors.length === 0) throw boundedError;\n\t\t\tthrow new AggregateError(\n\t\t\t\t[\n\t\t\t\t\tboundedError instanceof Error\n\t\t\t\t\t\t? boundedError\n\t\t\t\t\t\t: new Error(String(boundedError), { cause: boundedError }),\n\t\t\t\t\t...errors,\n\t\t\t\t],\n\t\t\t\t\"EventBus.publish aborted after handler failures\",\n\t\t\t);\n\t\t}\n\t\tif (errors.length === 1) {\n\t\t\tthrow errors[0];\n\t\t}\n\t\tif (errors.length > 1) {\n\t\t\tthrow new AggregateError(errors, \"Multiple event handlers failed\");\n\t\t}\n\t}\n\n\tprivate async publishWithinContext(\n\t\tevents: ReadonlyArray<Evt>,\n\t\tcontext: ExecutionContext,\n\t\terrors: Error[],\n\t): Promise<void> {\n\t\tfor (const event of events) {\n\t\t\tif (context.signal.aborted) {\n\t\t\t\tthrow abortReason(context.signal, \"EventBus.publish aborted\");\n\t\t\t}\n\t\t\t// Typed and catch-all handlers share ONE allSettled batch, so the\n\t\t\t// contract holds across both kinds: none sees the others' errors,\n\t\t\t// none is skipped when a peer fails. Snapshot so a handler\n\t\t\t// unsubscribing during dispatch doesn't shift indices while we\n\t\t\t// iterate. The async wrapper converts a synchronous throw\n\t\t\t// (EventHandler may return void) into a rejection; otherwise it\n\t\t\t// would escape before allSettled sees the array, skipping peers\n\t\t\t// and orphaning their promises.\n\t\t\tconst batch = [\n\t\t\t\t...(this.handlers.get(event.type) ?? []),\n\t\t\t\t...this.catchAllHandlers,\n\t\t\t];\n\t\t\tif (batch.length > 0) {\n\t\t\t\t// Each failure is recorded the moment it happens, not after the\n\t\t\t\t// whole batch settles: a hung peer would otherwise trap a\n\t\t\t\t// settled rejection inside allSettled, invisible to the\n\t\t\t\t// abort/timeout path that ends the publish.\n\t\t\t\tconst batchStart = errors.length;\n\t\t\t\tconst failedIndices: number[] = [];\n\t\t\t\tawait Promise.allSettled(\n\t\t\t\t\tbatch.map(async (handler, index) => {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tawait handler(event, context);\n\t\t\t\t\t\t} catch (reason) {\n\t\t\t\t\t\t\tfailedIndices.push(index);\n\t\t\t\t\t\t\terrors.push(\n\t\t\t\t\t\t\t\treason instanceof Error\n\t\t\t\t\t\t\t\t\t? reason\n\t\t\t\t\t\t\t\t\t: // Attach the raw reason as cause: a handler\n\t\t\t\t\t\t\t\t\t\t// rejecting with a structured payload must stay\n\t\t\t\t\t\t\t\t\t\t// diagnosable, not collapse to '[object Object]'.\n\t\t\t\t\t\t\t\t\t\tnew Error(String(reason), { cause: reason }),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t\t// A settled batch reports its failures in subscription order\n\t\t\t\t// (the aggregation contract); recording order above is\n\t\t\t\t// settlement order so an abort mid-batch already sees them.\n\t\t\t\tconst settled = errors.splice(batchStart);\n\t\t\t\terrors.push(\n\t\t\t\t\t...failedIndices\n\t\t\t\t\t\t.map((index, i) => ({ index, error: settled[i] as Error }))\n\t\t\t\t\t\t.sort((a, b) => a.index - b.index)\n\t\t\t\t\t\t.map((entry) => entry.error),\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (context.signal.aborted) {\n\t\t\t\tthrow abortReason(context.signal, \"EventBus.publish aborted\");\n\t\t\t}\n\t\t}\n\t}\n}\n","import type { AggregateAddress } from \"../aggregate/aggregate-address\";\nimport {\n\ttype AnyDomainEvent,\n\tcreateDomainEvent,\n\ttype DomainEvent,\n\ttype EventMetadata,\n} from \"../aggregate/domain-event\";\nimport { InvalidIntegrationMessageError } from \"../core/errors\";\nimport { deepFreeze } from \"../value-object/value-object\";\nimport {\n\tassertJsonValue,\n\tisJsonObject,\n\ttype JsonObject,\n\ttype JsonValue,\n} from \"./json-value\";\nimport type { CommitPosition, CommittedDomainEvent } from \"./ports\";\n\nexport type { JsonObject, JsonPrimitive, JsonValue } from \"./json-value\";\n\n/** Standard relationship headers carried by the public message envelope. */\nexport interface IntegrationMessageRelationships {\n\t/** Groups messages that belong to one operation or trace. */\n\treadonly correlationId?: string;\n\t/** Groups a long-running business interaction across several correlations. */\n\treadonly conversationId?: string;\n\t/** Identifies the message, event, or command that immediately caused this one. */\n\treadonly causationId?: string;\n}\n\n/** Application-owned public content produced from one internal domain event. */\nexport interface IntegrationMessageContent<\n\tTType extends string,\n\tTPayload extends JsonValue,\n\tTMetadata extends JsonObject = JsonObject,\n> extends IntegrationMessageRelationships {\n\treadonly type: TType;\n\treadonly version: number;\n\treadonly payload: TPayload;\n\t/** Custom JSON metadata; relationship header names are reserved. */\n\treadonly metadata?: TMetadata;\n}\n\n/**\n * JSON-safe broker envelope, deliberately separate from {@link DomainEvent}.\n * Standard message relationships are explicit headers rather than payload or\n * custom metadata. Its source cursor supports ordered, gap-aware projection\n * consumption.\n */\nexport interface IntegrationMessage<\n\tTType extends string = string,\n\tTPayload extends JsonValue = JsonValue,\n\tTMetadata extends JsonObject = JsonObject,\n> extends IntegrationMessageContent<TType, TPayload, TMetadata> {\n\treadonly messageId: string;\n\treadonly occurredAt: string;\n\treadonly source: AggregateAddress;\n\treadonly position: CommitPosition;\n}\n\n/** Maps a private domain event to its explicit public message schema. */\nexport type IntegrationMessageMapper<\n\tEvt extends AnyDomainEvent,\n\tTType extends string,\n\tTPayload extends JsonValue,\n\tTMetadata extends JsonObject = JsonObject,\n> = (event: Evt) => IntegrationMessageContent<TType, TPayload, TMetadata>;\n\n/**\n * Maps a committed domain event to a deeply frozen JSON-safe message. The\n * mapper explicitly chooses every public relationship header; producer-private\n * domain metadata is never copied implicitly. Values JSON would change or\n * discard reject as {@link InvalidIntegrationMessageError}.\n */\nexport function createIntegrationMessage<\n\tEvt extends AnyDomainEvent,\n\tTType extends string,\n\tTPayload extends JsonValue,\n\tTMetadata extends JsonObject = JsonObject,\n>(\n\trecord: CommittedDomainEvent<Evt>,\n\tmapper: IntegrationMessageMapper<Evt, TType, TPayload, TMetadata>,\n): IntegrationMessage<TType, TPayload, TMetadata> {\n\tconst content = mapper(record.event);\n\treturn stabilizeIntegrationMessage({\n\t\tmessageId: record.event.eventId,\n\t\ttype: content.type,\n\t\tversion: content.version,\n\t\toccurredAt: record.event.occurredAt.toISOString(),\n\t\t...relationshipHeaders(content),\n\t\tpayload: content.payload,\n\t\t...(content.metadata === undefined ? {} : { metadata: content.metadata }),\n\t\tsource: record.source,\n\t\tposition: record.position,\n\t});\n}\n\n/** Validates and serializes an integration message without lossy coercion. */\nexport function encodeIntegrationMessage(message: IntegrationMessage): string {\n\tassertIntegrationMessage(message);\n\treturn JSON.stringify(message);\n}\n\n/**\n * Parses and validates a broker body, normalizes supported RFC 3339 timestamps\n * to canonical UTC milliseconds, then defensively copies and deeply freezes it.\n */\nexport function decodeIntegrationMessage(\n\tserialized: string,\n): IntegrationMessage {\n\ttry {\n\t\treturn stabilizeIntegrationMessage(JSON.parse(serialized), \"wire\");\n\t} catch (error) {\n\t\tif (error instanceof InvalidIntegrationMessageError) throw error;\n\t\tthrow new InvalidIntegrationMessageError(\n\t\t\t\"$\",\n\t\t\t\"body is not valid JSON\",\n\t\t\terror,\n\t\t);\n\t}\n}\n\n/**\n * Composes a validated public message into a minted local projector input.\n * Relationship headers become local event metadata. The public JSON schema is\n * retained; producer-private domain types are not reconstructed.\n */\nexport function integrationMessageToCommittedEvent<\n\tTType extends string,\n\tTPayload extends JsonValue,\n\tTMetadata extends JsonObject = JsonObject,\n>(\n\tmessage: IntegrationMessage<TType, TPayload, TMetadata>,\n): CommittedDomainEvent<DomainEvent<TType, TPayload>> {\n\tconst stableMessage = stabilizeIntegrationMessage(message);\n\tconst metadata = localEventMetadata(stableMessage);\n\treturn {\n\t\tevent: createDomainEvent(stableMessage.type, stableMessage.payload, {\n\t\t\teventId: stableMessage.messageId,\n\t\t\taggregateId: stableMessage.source.aggregateId,\n\t\t\taggregateType: stableMessage.source.aggregateType,\n\t\t\toccurredAt: new Date(stableMessage.occurredAt),\n\t\t\tversion: stableMessage.version,\n\t\t\tmetadata,\n\t\t}),\n\t\tsource: stableMessage.source,\n\t\tposition: stableMessage.position,\n\t};\n}\n\nfunction stabilizeIntegrationMessage<T>(\n\tvalue: T,\n\ttimestampFormat: \"canonical\" | \"wire\" = \"canonical\",\n): T {\n\tassertIntegrationMessage(value, timestampFormat);\n\tconst copy = JSON.parse(JSON.stringify(value));\n\tif (timestampFormat === \"wire\") {\n\t\tcopy.occurredAt = normalizeWireTimestamp(copy.occurredAt);\n\t}\n\treturn deepFreeze(copy) as T;\n}\n\nfunction assertIntegrationMessage(\n\tvalue: unknown,\n\ttimestampFormat: \"canonical\" | \"wire\" = \"canonical\",\n): asserts value is IntegrationMessage {\n\tassertJsonValue(value, \"$\", invalid);\n\tif (!isJsonObject(value)) {\n\t\tinvalid(\"$\", \"envelope must be a plain JSON object\");\n\t}\n\tif (typeof value.messageId !== \"string\" || value.messageId.length === 0) {\n\t\tinvalid(\"$.messageId\", \"must be a non-empty string\");\n\t}\n\tfor (const field of RELATIONSHIP_FIELDS) {\n\t\tif (!Object.hasOwn(value, field)) continue;\n\t\tconst relationshipId = value[field];\n\t\tif (typeof relationshipId !== \"string\" || relationshipId.length === 0) {\n\t\t\tinvalid(`$.${field}`, \"must be a non-empty string when present\");\n\t\t}\n\t}\n\tif (typeof value.type !== \"string\" || value.type.length === 0) {\n\t\tinvalid(\"$.type\", \"must be a non-empty string\");\n\t}\n\tconst version = value.version;\n\tif (\n\t\ttypeof version !== \"number\" ||\n\t\t!Number.isInteger(version) ||\n\t\tversion < 1\n\t) {\n\t\tinvalid(\"$.version\", \"must be an integer >= 1\");\n\t}\n\tif (\n\t\ttypeof value.occurredAt !== \"string\" ||\n\t\t(timestampFormat === \"canonical\"\n\t\t\t? !isCanonicalIsoTimestamp(value.occurredAt)\n\t\t\t: normalizeWireTimestamp(value.occurredAt) === undefined)\n\t) {\n\t\tinvalid(\n\t\t\t\"$.occurredAt\",\n\t\t\ttimestampFormat === \"canonical\"\n\t\t\t\t? \"must be a canonical UTC ISO-8601 timestamp\"\n\t\t\t\t: \"must be an RFC 3339 timestamp with an explicit offset and at most millisecond precision\",\n\t\t);\n\t}\n\tif (!Object.hasOwn(value, \"payload\")) {\n\t\tinvalid(\"$.payload\", \"is required (use null for an empty JSON payload)\");\n\t}\n\tif (\n\t\tObject.hasOwn(value, \"metadata\") &&\n\t\tvalue.metadata !== undefined &&\n\t\t!isJsonObject(value.metadata)\n\t) {\n\t\tinvalid(\"$.metadata\", \"must be a plain JSON object when present\");\n\t}\n\tif (isJsonObject(value.metadata)) {\n\t\tfor (const field of RELATIONSHIP_FIELDS) {\n\t\t\tif (Object.hasOwn(value.metadata, field)) {\n\t\t\t\tinvalid(\n\t\t\t\t\t`$.metadata.${field}`,\n\t\t\t\t\t\"is reserved for the explicit message envelope header\",\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\tif (!isJsonObject(value.source)) {\n\t\tinvalid(\"$.source\", \"must be a plain JSON object\");\n\t}\n\tif (\n\t\ttypeof value.source.aggregateType !== \"string\" ||\n\t\tvalue.source.aggregateType.length === 0\n\t) {\n\t\tinvalid(\"$.source.aggregateType\", \"must be a non-empty string\");\n\t}\n\tif (\n\t\ttypeof value.source.aggregateId !== \"string\" ||\n\t\tvalue.source.aggregateId.length === 0\n\t) {\n\t\tinvalid(\"$.source.aggregateId\", \"must be a non-empty string\");\n\t}\n\tif (!isJsonObject(value.position)) {\n\t\tinvalid(\"$.position\", \"must be a plain JSON object\");\n\t}\n\tconst { position } = value;\n\tconst aggregateVersion = position.aggregateVersion;\n\tif (\n\t\ttypeof aggregateVersion !== \"number\" ||\n\t\t!Number.isInteger(aggregateVersion) ||\n\t\taggregateVersion < 0\n\t) {\n\t\tinvalid(\"$.position.aggregateVersion\", \"must be an integer >= 0\");\n\t}\n\tconst commitSequence = position.commitSequence;\n\tif (\n\t\ttypeof commitSequence !== \"number\" ||\n\t\t!Number.isInteger(commitSequence) ||\n\t\tcommitSequence < 0\n\t) {\n\t\tinvalid(\"$.position.commitSequence\", \"must be an integer >= 0\");\n\t}\n\tconst commitSize = position.commitSize;\n\tif (\n\t\ttypeof commitSize !== \"number\" ||\n\t\t!Number.isInteger(commitSize) ||\n\t\tcommitSize <= commitSequence\n\t) {\n\t\tinvalid(\n\t\t\t\"$.position.commitSize\",\n\t\t\t\"must be a positive integer greater than commitSequence\",\n\t\t);\n\t}\n\tif (!Object.hasOwn(position, \"previousEventfulAggregateVersion\")) {\n\t\tinvalid(\n\t\t\t\"$.position.previousEventfulAggregateVersion\",\n\t\t\t\"is required (use null at genesis)\",\n\t\t);\n\t}\n\tconst previous = position.previousEventfulAggregateVersion;\n\tif (\n\t\tprevious !== null &&\n\t\t(typeof previous !== \"number\" ||\n\t\t\t!Number.isInteger(previous) ||\n\t\t\tprevious < 0 ||\n\t\t\tprevious >= aggregateVersion)\n\t) {\n\t\tinvalid(\n\t\t\t\"$.position.previousEventfulAggregateVersion\",\n\t\t\t\"must be null at genesis or an earlier non-negative aggregate version\",\n\t\t);\n\t}\n}\n\nconst RELATIONSHIP_FIELDS = [\n\t\"correlationId\",\n\t\"conversationId\",\n\t\"causationId\",\n] as const;\n\nfunction relationshipHeaders(\n\tprimary: IntegrationMessageRelationships,\n): IntegrationMessageRelationships {\n\tconst { correlationId, conversationId, causationId } = primary;\n\treturn {\n\t\t...(correlationId === undefined ? {} : { correlationId }),\n\t\t...(conversationId === undefined ? {} : { conversationId }),\n\t\t...(causationId === undefined ? {} : { causationId }),\n\t};\n}\n\nfunction localEventMetadata(\n\tmessage: IntegrationMessage,\n): EventMetadata | undefined {\n\tconst relationships = relationshipHeaders(message);\n\tif (\n\t\tmessage.metadata === undefined &&\n\t\tObject.keys(relationships).length === 0\n\t) {\n\t\treturn undefined;\n\t}\n\treturn { ...message.metadata, ...relationships };\n}\n\nfunction isCanonicalIsoTimestamp(value: string): boolean {\n\tconst timestamp = new Date(value);\n\treturn (\n\t\t!Number.isNaN(timestamp.getTime()) && timestamp.toISOString() === value\n\t);\n}\n\nconst WIRE_TIMESTAMP =\n\t/^(\\d{4})-(\\d{2})-(\\d{2})T(\\d{2}):(\\d{2}):(\\d{2})(?:\\.(\\d{1,3}))?(Z|[+-](\\d{2}):(\\d{2}))$/;\n\nfunction normalizeWireTimestamp(value: string): string | undefined {\n\tconst match = WIRE_TIMESTAMP.exec(value);\n\tif (match === null) return undefined;\n\n\tconst [\n\t\t,\n\t\tyear,\n\t\tmonth,\n\t\tday,\n\t\thour,\n\t\tminute,\n\t\tsecond,\n\t\t,\n\t\t,\n\t\toffsetHour,\n\t\toffsetMinute,\n\t] = match;\n\tconst numericYear = Number(year);\n\tconst numericMonth = Number(month);\n\tconst numericDay = Number(day);\n\tif (\n\t\tnumericMonth < 1 ||\n\t\tnumericMonth > 12 ||\n\t\tnumericDay < 1 ||\n\t\tnumericDay > daysInMonth(numericYear, numericMonth) ||\n\t\tNumber(hour) > 23 ||\n\t\tNumber(minute) > 59 ||\n\t\tNumber(second) > 59 ||\n\t\t(offsetHour !== undefined && Number(offsetHour) > 23) ||\n\t\t(offsetMinute !== undefined && Number(offsetMinute) > 59)\n\t) {\n\t\treturn undefined;\n\t}\n\n\tconst timestamp = new Date(value);\n\treturn Number.isNaN(timestamp.getTime())\n\t\t? undefined\n\t\t: timestamp.toISOString();\n}\n\nfunction daysInMonth(year: number, month: number): number {\n\tif (month === 2) {\n\t\treturn year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0) ? 29 : 28;\n\t}\n\treturn month === 4 || month === 6 || month === 9 || month === 11 ? 30 : 31;\n}\n\nfunction invalid(path: string, reason: string): never {\n\tthrow new InvalidIntegrationMessageError(path, reason);\n}\n","/**\n * Stable value address of one aggregate instance.\n *\n * Aggregate ids are type-scoped, so the raw id alone is not globally unique:\n * `SalesOrder 1` and `FulfillmentOrder 1` are different aggregates. Event\n * streams, snapshots, committed-event sources, and projection checkpoints\n * therefore carry both fields instead of defining boundary-specific variants.\n *\n * `aggregateType` is a stable technical stream category. Renaming it changes\n * persistence keys and orphans checkpoints unless the stored addresses are\n * migrated. When bounded contexts share infrastructure and reuse a domain\n * name, qualify it at the source (`sales.order`, `fulfillment.order`). The kit\n * deliberately adds no separate `boundedContext` field: qualification remains\n * the consumer's naming decision.\n */\nexport interface AggregateAddress<TAggregateId extends string = string> {\n\treadonly aggregateType: string;\n\treadonly aggregateId: TAggregateId;\n}\n\n/**\n * Collision-safe map-key encoding shared by the in-memory adapters.\n * Internal: durable adapters key on the two storage columns themselves.\n */\nexport function encodeAggregateAddress(address: AggregateAddress): string {\n\treturn JSON.stringify([address.aggregateType, address.aggregateId]);\n}\n","import {\n\ttype AggregateAddress,\n\tencodeAggregateAddress,\n} from \"../aggregate/aggregate-address\";\nimport type { AnyDomainEvent } from \"../aggregate/domain-event\";\nimport {\n\tEventHarvestError,\n\tInMemoryCapacityExceededError,\n} from \"../core/errors\";\nimport {\n\tassertPositiveInteger,\n\tassertPositiveSafeInteger,\n} from \"../utils/validate\";\nimport type {\n\tDeadLetterRecord,\n\tDispatchTrackingOutbox,\n\tEventCommitCandidate,\n\tEventCommitCandidatePosition,\n\tOutboxRecord,\n\tOutboxWriter,\n} from \"./ports\";\n\n/**\n * An {@link OutboxWriter} that deliberately drops every event: the\n * no-op (noop) writer, named for its consequence rather than its\n * mechanism, so the call site reads as the decision it is.\n *\n * `withCommit` and `UnitOfWork` require an outbox on purpose: the\n * asymmetry against the optional `bus` is the design. The bus is the\n * best-effort in-process fast path (post-commit, no durability), so it\n * may be omitted; the outbox is the delivery GUARANTEE, so running\n * without one is a decision, not a default. This writer is that\n * decision, made readable at the call site.\n *\n * Legitimate uses: aggregates that emit no events (`TEvent = never`,\n * nothing will ever be written), and deliberate best-effort setups\n * where the in-process bus is the only delivery and event loss on a\n * crash between commit and publish is ACCEPTED. Do not reach for an\n * undrained `InMemoryOutbox` instead: its pending map grows unbounded\n * (see the class docs).\n *\n * The name is long on purpose, same discipline as\n * `setStateWithoutVersionBump`: the dangerous variant carries the loud\n * name.\n */\nexport function outboxWriterAcceptingEventLoss<\n\tEvt extends AnyDomainEvent,\n>(): OutboxWriter<Evt> {\n\treturn {\n\t\tadd: async () => {},\n\t};\n}\n\n/** Construction options for {@link InMemoryOutbox}. */\nexport interface InMemoryOutboxOptions {\n\t/** Maximum records retained across pending and dead-letter states. */\n\treadonly maxRecords?: number;\n\n\t/** Maximum qualified aggregate source cursors retained by this instance. */\n\treadonly maxSources?: number;\n\n\t/**\n\t * Failed-delivery ceiling: once `markFailed` has been reported this\n\t * many times for a record, it moves to {@link InMemoryOutbox.deadLetters}\n\t * and stops coming back from `getPending`. Default `5`.\n\t */\n\tmaxDeliveryAttempts?: number;\n\n\t/**\n\t * Maximum recently dispatched event receipts (id, qualified source, and\n\t * candidate commit position) retained for idempotent `add` retries and\n\t * collision detection. Older receipts are evicted in dispatch order; a later\n\t * candidate behind its source head then rejects instead of rewinding the\n\t * cursor.\n\t * Default `10_000`.\n\t */\n\tmaxRetainedDispatchedEventIds?: number;\n}\n\ntype TrackedRecord<Evt extends AnyDomainEvent> = {\n\tdispatchId: string;\n\tevent: Evt;\n\tsource: OutboxRecord<Evt>[\"source\"];\n\tposition: OutboxRecord<Evt>[\"position\"];\n\tattempts: number;\n\tlastError?: string;\n};\n\ntype EventSourceCursor = {\n\taggregateVersion: number;\n\tpreviousEventfulAggregateVersion: number | null;\n\tcommitSize: number;\n\teventIdsBySequence: ReadonlyMap<number, string>;\n};\n\ntype DispatchedEventReceipt = {\n\treadonly source: AggregateAddress;\n\treadonly position: EventCommitCandidatePosition;\n};\n\n/**\n * In-memory reference implementation of `DispatchTrackingOutbox<Evt>`\n * (and therefore of the plain `Outbox<Evt>` port).\n *\n * Intended for finite-lifetime tests and quick-start demos. Without\n * `maxRecords` and `maxSources`, active delivery state and source cursors are\n * unbounded. Long-lived processes must configure both limits or use a durable\n * adapter. Exhaustion rejects the complete `add` batch before mutation;\n * correctness state is never silently evicted.\n * Uses the event's own `eventId` as the dispatch id: the common, clean\n * choice. Active storage is a `Map` keyed by `eventId`, and a bounded\n * recent-dispatch receipt cache keeps retries idempotent after acknowledgement.\n * Re-adding a pending event refreshes the stored commit envelope while the\n * delivery attempt count survives. Its commit sequence and size remain\n * immutable; only this transaction-unaware adapter may move a still-pending\n * event to another aggregate version after an outer rollback leaked the first\n * add. Dead-lettered and acknowledged retries must match the complete original\n * candidate receipt. Reusing an `eventId` for another source or commit position\n * throws {@link EventHarvestError} while the pending, dead-letter, or bounded\n * dispatched receipt still proves the collision. Insertion order is preserved:\n * `getPending` returns records in commit order, as the port contract requires.\n *\n * Dispatch tracking: `markFailed` increments the record's attempt count\n * and, at `maxDeliveryAttempts`, moves it to the dead-letter set\n * exposed by `deadLetters()`. Re-`add`ing a dead-lettered event\n * requeues it with a fresh attempts budget (the operator-facing\n * inverse of `deadLetters()`); `markDispatched` acks pending AND\n * dead-lettered records (manual redelivery then ack).\n * To link future eventful commits, the implementation also retains one\n * source cursor per qualified aggregate after dispatch. Consequently a\n * long-lived instance is bounded only when `maxRecords` and `maxSources` are\n * configured, plus `maxRetainedDispatchedEventIds`; use a durable adapter with\n * an explicit source-head lifecycle and an event-id unique key for unbounded\n * production workloads.\n *\n * For production, back the outbox with a transactional store so the\n * outbox row participates in the same transaction as the aggregate\n * write (see `TransactionScope` + `withCommit`). This class lives in\n * memory only: events are lost on process restart. Do NOT use it as a\n * dummy for bus-only setups without a dispatcher draining it: records\n * that are never `markDispatched` accumulate until `maxRecords` rejects a new\n * add, or without that option grow unbounded. For a deliberate no-delivery\n * setup use {@link outboxWriterAcceptingEventLoss} instead. Sharper still:\n * events `add()`ed inside a transaction that later rolls back are NOT\n * removed (the Map knows nothing about your scope's rollback). Tests\n * that assert rollback purity need an outbox that participates in the\n * test store's transactional semantics; see the reference adapter at\n * https://github.com/shi-rudo/ddd-kit-ts/blob/main/src/testing/repository-contract.test.ts\n * (repo-only, not shipped to npm).\n *\n * @example\n * ```ts\n * import { InMemoryOutbox, EventBusImpl } from \"@shirudo/ddd-kit\";\n *\n * const outbox = new InMemoryOutbox<OrderEvent>();\n * const bus = new EventBusImpl<OrderEvent>();\n *\n * const uow = makeOrderUnitOfWork({ outbox, bus });\n * await uow.run(async ({ repositories }) => {\n * const order = await repositories.orders.getById(id);\n * order.confirm();\n * repositories.orders.update(order);\n * return order.id;\n * });\n * ```\n */\nexport class InMemoryOutbox<Evt extends AnyDomainEvent>\n\timplements DispatchTrackingOutbox<Evt>\n{\n\tprivate readonly pending = new Map<string, TrackedRecord<Evt>>();\n\tprivate readonly dead = new Map<string, DeadLetterRecord<Evt>>();\n\t/** Latest eventful commit and its predecessor per qualified source. */\n\tprivate readonly sourceCursors = new Map<string, EventSourceCursor>();\n\t/** Bounded insertion-ordered receipts for exact retries after acknowledgement. */\n\tprivate readonly dispatchedEventIds = new Map<\n\t\tstring,\n\t\tDispatchedEventReceipt\n\t>();\n\tprivate readonly maxDeliveryAttempts: number;\n\tprivate readonly maxRetainedDispatchedEventIds: number;\n\tprivate readonly maxRecords: number | undefined;\n\tprivate readonly maxSources: number | undefined;\n\n\tconstructor(options?: InMemoryOutboxOptions) {\n\t\tconst max = options?.maxDeliveryAttempts ?? 5;\n\t\tassertPositiveInteger(\"InMemoryOutbox\", \"maxDeliveryAttempts\", max);\n\t\tthis.maxDeliveryAttempts = max;\n\t\tconst retained = options?.maxRetainedDispatchedEventIds ?? 10_000;\n\t\tassertPositiveInteger(\n\t\t\t\"InMemoryOutbox\",\n\t\t\t\"maxRetainedDispatchedEventIds\",\n\t\t\tretained,\n\t\t);\n\t\tthis.maxRetainedDispatchedEventIds = retained;\n\t\tif (options?.maxRecords !== undefined) {\n\t\t\tassertPositiveSafeInteger(\n\t\t\t\t\"InMemoryOutbox\",\n\t\t\t\t\"maxRecords\",\n\t\t\t\toptions.maxRecords,\n\t\t\t);\n\t\t}\n\t\tif (options?.maxSources !== undefined) {\n\t\t\tassertPositiveSafeInteger(\n\t\t\t\t\"InMemoryOutbox\",\n\t\t\t\t\"maxSources\",\n\t\t\t\toptions.maxSources,\n\t\t\t);\n\t\t}\n\t\tthis.maxRecords = options?.maxRecords;\n\t\tthis.maxSources = options?.maxSources;\n\t}\n\n\tasync add(events: ReadonlyArray<EventCommitCandidate<Evt>>): Promise<void> {\n\t\t// Prove identity/receipt and source-position consistency for the whole input\n\t\t// before mutating pending records or source heads. Otherwise a conflict later\n\t\t// in one add() call could reject only after its earlier prefix had leaked.\n\t\tthis.assertBatchEventReceiptIntegrity(events);\n\t\tthis.assertBatchPositionIntegrity(events);\n\t\tthis.assertCapacity(events);\n\t\tfor (const message of events) {\n\t\t\tconst { event, source, position } = message;\n\t\t\tconst dispatchedReceipt = this.dispatchedEventIds.get(event.eventId);\n\t\t\tif (dispatchedReceipt !== undefined) {\n\t\t\t\tassertSameEventSource(event, source, dispatchedReceipt.source);\n\t\t\t\tassertSameCandidateReceipt(\n\t\t\t\t\tevent,\n\t\t\t\t\tposition,\n\t\t\t\t\tdispatchedReceipt.position,\n\t\t\t\t);\n\t\t\t\t// eventId is the outbox idempotency key. Refresh its LRU position\n\t\t\t\t// without recreating a pending record or touching the source head.\n\t\t\t\tthis.rememberDispatched(\n\t\t\t\t\tevent.eventId,\n\t\t\t\t\tdispatchedReceipt.source,\n\t\t\t\t\tdispatchedReceipt.position,\n\t\t\t\t);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst existing = this.pending.get(event.eventId);\n\t\t\tconst deadLetter = this.dead.get(event.eventId);\n\t\t\tif (existing !== undefined) {\n\t\t\t\tassertSameEventSource(event, source, existing.source);\n\t\t\t\t// A pending record may move to another aggregateVersion only because\n\t\t\t\t// this in-memory adapter cannot observe rollback and the same event is\n\t\t\t\t// re-harvested. Its index and commit cardinality remain immutable.\n\t\t\t\tassertSameCandidateReceiptAllowingVersionRefresh(\n\t\t\t\t\tevent,\n\t\t\t\t\tposition,\n\t\t\t\t\texisting.position,\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (deadLetter) {\n\t\t\t\tassertSameEventSource(event, source, deadLetter.source);\n\t\t\t\tassertSameCandidateReceipt(event, position, deadLetter.position);\n\t\t\t\t// Requeue the durable record exactly as committed. A dead letter is a\n\t\t\t\t// delivery state, not a new aggregate commit to re-finalize.\n\t\t\t\tthis.dead.delete(event.eventId);\n\t\t\t\tthis.pending.set(event.eventId, {\n\t\t\t\t\tdispatchId: deadLetter.dispatchId,\n\t\t\t\t\tevent: deadLetter.event,\n\t\t\t\t\tsource: deadLetter.source,\n\t\t\t\t\tposition: deadLetter.position,\n\t\t\t\t\tattempts: 0,\n\t\t\t\t});\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst ownedSource = Object.freeze({ ...source });\n\t\t\tconst sourceKey = encodeAggregateAddress(source);\n\t\t\tconst sourceCursor = this.sourceCursors.get(sourceKey);\n\t\t\tlet staleHeadVersion: number | undefined;\n\t\t\tif (\n\t\t\t\texisting !== undefined &&\n\t\t\t\tposition.aggregateVersion < existing.position.aggregateVersion\n\t\t\t) {\n\t\t\t\tstaleHeadVersion = existing.position.aggregateVersion;\n\t\t\t} else if (\n\t\t\t\texisting === undefined &&\n\t\t\t\tsourceCursor !== undefined &&\n\t\t\t\tposition.aggregateVersion < sourceCursor.aggregateVersion\n\t\t\t) {\n\t\t\t\tstaleHeadVersion = sourceCursor.aggregateVersion;\n\t\t\t}\n\t\t\tif (staleHeadVersion !== undefined) {\n\t\t\t\tthrow staleHeadError(event, source, position, staleHeadVersion);\n\t\t\t}\n\t\t\tif (sourceCursor?.aggregateVersion === position.aggregateVersion) {\n\t\t\t\tif (sourceCursor.commitSize !== position.commitSize) {\n\t\t\t\t\tthrow new EventHarvestError(\n\t\t\t\t\t\t`InMemoryOutbox rejected event \"${event.eventId}\" for ` +\n\t\t\t\t\t\t\t`${source.aggregateType} ${source.aggregateId}: aggregate version ` +\n\t\t\t\t\t\t\t`${position.aggregateVersion} was already recorded with commitSize ` +\n\t\t\t\t\t\t\t`${sourceCursor.commitSize}, not ${position.commitSize}.`,\n\t\t\t\t\t\tevent.type,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tconst positionOwner = sourceCursor.eventIdsBySequence.get(\n\t\t\t\t\tposition.commitSequence,\n\t\t\t\t);\n\t\t\t\tif (positionOwner !== undefined && positionOwner !== event.eventId) {\n\t\t\t\t\tthrow new EventHarvestError(\n\t\t\t\t\t\t`InMemoryOutbox rejected event \"${event.eventId}\" for ` +\n\t\t\t\t\t\t\t`${source.aggregateType} ${source.aggregateId}: source position ` +\n\t\t\t\t\t\t\t`(${position.aggregateVersion}, ${position.commitSequence}) is ` +\n\t\t\t\t\t\t\t`already owned by event \"${positionOwner}\". One qualified source ` +\n\t\t\t\t\t\t\t\"position must identify exactly one immutable event.\",\n\t\t\t\t\t\tevent.type,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t\tlet previousEventfulAggregateVersion: number | null;\n\t\t\tconst refreshesLeakedCommit =\n\t\t\t\texisting !== undefined &&\n\t\t\t\texisting.position.aggregateVersion !== position.aggregateVersion;\n\t\t\tif (refreshesLeakedCommit) {\n\t\t\t\t// InMemoryOutbox cannot observe transaction rollback. A pending\n\t\t\t\t// record with the same eventId but a new commit version is therefore\n\t\t\t\t// a replacement for the leaked attempt, not its successor. Preserve\n\t\t\t\t// the event-source predecessor and move the in-memory source head.\n\t\t\t\tpreviousEventfulAggregateVersion =\n\t\t\t\t\texisting.position.previousEventfulAggregateVersion;\n\t\t\t\tif (\n\t\t\t\t\tsourceCursor?.aggregateVersion === existing.position.aggregateVersion\n\t\t\t\t) {\n\t\t\t\t\tthis.sourceCursors.set(sourceKey, {\n\t\t\t\t\t\taggregateVersion: position.aggregateVersion,\n\t\t\t\t\t\tpreviousEventfulAggregateVersion,\n\t\t\t\t\t\tcommitSize: position.commitSize,\n\t\t\t\t\t\teventIdsBySequence: new Map([\n\t\t\t\t\t\t\t[position.commitSequence, event.eventId],\n\t\t\t\t\t\t]),\n\t\t\t\t\t});\n\t\t\t\t} else if (\n\t\t\t\t\tsourceCursor?.aggregateVersion === position.aggregateVersion &&\n\t\t\t\t\t!sourceCursor.eventIdsBySequence.has(position.commitSequence)\n\t\t\t\t) {\n\t\t\t\t\tthis.sourceCursors.set(\n\t\t\t\t\t\tsourceKey,\n\t\t\t\t\t\tcursorWithEvent(\n\t\t\t\t\t\t\tsourceCursor,\n\t\t\t\t\t\t\tposition.commitSequence,\n\t\t\t\t\t\t\tevent.eventId,\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t} else if (existing !== undefined) {\n\t\t\t\tpreviousEventfulAggregateVersion =\n\t\t\t\t\texisting.position.previousEventfulAggregateVersion;\n\t\t\t} else if (sourceCursor?.aggregateVersion === position.aggregateVersion) {\n\t\t\t\tpreviousEventfulAggregateVersion =\n\t\t\t\t\tsourceCursor.previousEventfulAggregateVersion;\n\t\t\t\tif (!sourceCursor.eventIdsBySequence.has(position.commitSequence)) {\n\t\t\t\t\tthis.sourceCursors.set(\n\t\t\t\t\t\tsourceKey,\n\t\t\t\t\t\tcursorWithEvent(\n\t\t\t\t\t\t\tsourceCursor,\n\t\t\t\t\t\t\tposition.commitSequence,\n\t\t\t\t\t\t\tevent.eventId,\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tpreviousEventfulAggregateVersion =\n\t\t\t\t\tsourceCursor?.aggregateVersion ?? null;\n\t\t\t\tthis.sourceCursors.set(sourceKey, {\n\t\t\t\t\taggregateVersion: position.aggregateVersion,\n\t\t\t\t\tpreviousEventfulAggregateVersion,\n\t\t\t\t\tcommitSize: position.commitSize,\n\t\t\t\t\teventIdsBySequence: new Map([\n\t\t\t\t\t\t[position.commitSequence, event.eventId],\n\t\t\t\t\t]),\n\t\t\t\t});\n\t\t\t}\n\t\t\tconst ownedPosition = Object.freeze({\n\t\t\t\t...position,\n\t\t\t\tpreviousEventfulAggregateVersion,\n\t\t\t});\n\t\t\tif (existing) {\n\t\t\t\t// Re-add refreshes the stored COPY but keeps the delivery\n\t\t\t\t// bookkeeping: a failed-commit-then-retry re-adds the same\n\t\t\t\t// eventId with a new commit position. Dispatching the stale\n\t\t\t\t// envelope would hand consumers a position from a commit that\n\t\t\t\t// never happened. Attempts belong to delivery, so they survive.\n\t\t\t\texisting.event = event;\n\t\t\t\texisting.source = ownedSource;\n\t\t\t\texisting.position = ownedPosition;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tthis.pending.set(event.eventId, {\n\t\t\t\tdispatchId: event.eventId,\n\t\t\t\tevent,\n\t\t\t\tsource: ownedSource,\n\t\t\t\tposition: ownedPosition,\n\t\t\t\tattempts: 0,\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate assertCapacity(\n\t\tevents: ReadonlyArray<EventCommitCandidate<Evt>>,\n\t): void {\n\t\tconst newRecordIds = new Set<string>();\n\t\tconst newSourceKeys = new Set<string>();\n\t\tfor (const { event, source } of events) {\n\t\t\tif (\n\t\t\t\tthis.pending.has(event.eventId) ||\n\t\t\t\tthis.dead.has(event.eventId) ||\n\t\t\t\tthis.dispatchedEventIds.has(event.eventId)\n\t\t\t) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tnewRecordIds.add(event.eventId);\n\t\t\tconst sourceKey = encodeAggregateAddress(source);\n\t\t\tif (!this.sourceCursors.has(sourceKey)) newSourceKeys.add(sourceKey);\n\t\t}\n\n\t\tconst currentRecords = this.pending.size + this.dead.size;\n\t\tif (\n\t\t\tthis.maxRecords !== undefined &&\n\t\t\tcurrentRecords + newRecordIds.size > this.maxRecords\n\t\t) {\n\t\t\tthrow new InMemoryCapacityExceededError({\n\t\t\t\tstore: \"InMemoryOutbox\",\n\t\t\t\tresource: \"records\",\n\t\t\t\tlimit: this.maxRecords,\n\t\t\t\tcurrent: currentRecords,\n\t\t\t\tattempted: newRecordIds.size,\n\t\t\t});\n\t\t}\n\t\tif (\n\t\t\tthis.maxSources !== undefined &&\n\t\t\tthis.sourceCursors.size + newSourceKeys.size > this.maxSources\n\t\t) {\n\t\t\tthrow new InMemoryCapacityExceededError({\n\t\t\t\tstore: \"InMemoryOutbox\",\n\t\t\t\tresource: \"sources\",\n\t\t\t\tlimit: this.maxSources,\n\t\t\t\tcurrent: this.sourceCursors.size,\n\t\t\t\tattempted: newSourceKeys.size,\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate assertBatchEventReceiptIntegrity(\n\t\tevents: ReadonlyArray<EventCommitCandidate<Evt>>,\n\t): void {\n\t\tconst receiptsInBatch = new Map<\n\t\t\tstring,\n\t\t\t{\n\t\t\t\treadonly source: AggregateAddress;\n\t\t\t\treadonly position: EventCommitCandidatePosition;\n\t\t\t}\n\t\t>();\n\t\tfor (const { event, source, position } of events) {\n\t\t\tconst batchReceipt = receiptsInBatch.get(event.eventId);\n\t\t\tif (batchReceipt !== undefined) {\n\t\t\t\tassertSameEventSource(event, source, batchReceipt.source);\n\t\t\t\tassertSameCandidateReceipt(\n\t\t\t\t\tevent,\n\t\t\t\t\tposition,\n\t\t\t\t\tbatchReceipt.position,\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\treceiptsInBatch.set(event.eventId, { source, position });\n\t\t\t}\n\t\t\tconst dispatchedReceipt = this.dispatchedEventIds.get(event.eventId);\n\t\t\tif (dispatchedReceipt !== undefined) {\n\t\t\t\tassertSameEventSource(event, source, dispatchedReceipt.source);\n\t\t\t\tassertSameCandidateReceipt(\n\t\t\t\t\tevent,\n\t\t\t\t\tposition,\n\t\t\t\t\tdispatchedReceipt.position,\n\t\t\t\t);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst existing = this.pending.get(event.eventId);\n\t\t\tif (existing !== undefined) {\n\t\t\t\tassertSameEventSource(event, source, existing.source);\n\t\t\t\tassertSameCandidateReceiptAllowingVersionRefresh(\n\t\t\t\t\tevent,\n\t\t\t\t\tposition,\n\t\t\t\t\texisting.position,\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst deadLetter = this.dead.get(event.eventId);\n\t\t\tif (deadLetter !== undefined) {\n\t\t\t\tassertSameEventSource(event, source, deadLetter.source);\n\t\t\t\tassertSameCandidateReceipt(event, position, deadLetter.position);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate assertBatchPositionIntegrity(\n\t\tevents: ReadonlyArray<EventCommitCandidate<Evt>>,\n\t): void {\n\t\tconst simulatedCursors = new Map<string, EventSourceCursor>();\n\t\tfor (const { event, source, position } of events) {\n\t\t\tconst sourceKey = encodeAggregateAddress(source);\n\t\t\tconst cursor =\n\t\t\t\tsimulatedCursors.get(sourceKey) ?? this.sourceCursors.get(sourceKey);\n\t\t\tif (\n\t\t\t\tcursor === undefined ||\n\t\t\t\tposition.aggregateVersion > cursor.aggregateVersion\n\t\t\t) {\n\t\t\t\tsimulatedCursors.set(sourceKey, {\n\t\t\t\t\taggregateVersion: position.aggregateVersion,\n\t\t\t\t\tpreviousEventfulAggregateVersion: cursor?.aggregateVersion ?? null,\n\t\t\t\t\tcommitSize: position.commitSize,\n\t\t\t\t\teventIdsBySequence: new Map([\n\t\t\t\t\t\t[position.commitSequence, event.eventId],\n\t\t\t\t\t]),\n\t\t\t\t});\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (position.aggregateVersion < cursor.aggregateVersion) {\n\t\t\t\t// Mirror of the main loop's stale-head rejection. A silent\n\t\t\t\t// `continue` here would break add()'s all-or-nothing promise:\n\t\t\t\t// the main loop would insert every earlier candidate and only\n\t\t\t\t// then throw for this one, leaving a pending event for a\n\t\t\t\t// commit the caller rolled back. Exact retries still dedupe:\n\t\t\t\t// dispatched receipts, dead letters, and a pending record at\n\t\t\t\t// or below the candidate version pass through.\n\t\t\t\tconst dedupes =\n\t\t\t\t\tthis.dispatchedEventIds.has(event.eventId) ||\n\t\t\t\t\tthis.dead.has(event.eventId);\n\t\t\t\tconst pendingRecord = this.pending.get(event.eventId);\n\t\t\t\tconst staleAgainstPending =\n\t\t\t\t\tpendingRecord !== undefined &&\n\t\t\t\t\tposition.aggregateVersion < pendingRecord.position.aggregateVersion;\n\t\t\t\tconst staleAgainstHead = pendingRecord === undefined && !dedupes;\n\t\t\t\tif (staleAgainstPending || staleAgainstHead) {\n\t\t\t\t\tthrow staleHeadError(\n\t\t\t\t\t\tevent,\n\t\t\t\t\t\tsource,\n\t\t\t\t\t\tposition,\n\t\t\t\t\t\tpendingRecord?.position.aggregateVersion ??\n\t\t\t\t\t\t\tcursor.aggregateVersion,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (cursor.commitSize !== position.commitSize) {\n\t\t\t\tthrow new EventHarvestError(\n\t\t\t\t\t`InMemoryOutbox rejected event \"${event.eventId}\" for ` +\n\t\t\t\t\t\t`${source.aggregateType} ${source.aggregateId}: aggregate version ` +\n\t\t\t\t\t\t`${position.aggregateVersion} was already recorded with commitSize ` +\n\t\t\t\t\t\t`${cursor.commitSize}, not ${position.commitSize}.`,\n\t\t\t\t\tevent.type,\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst positionOwner = cursor.eventIdsBySequence.get(\n\t\t\t\tposition.commitSequence,\n\t\t\t);\n\t\t\tif (positionOwner !== undefined && positionOwner !== event.eventId) {\n\t\t\t\tthrow new EventHarvestError(\n\t\t\t\t\t`InMemoryOutbox rejected event \"${event.eventId}\" for ` +\n\t\t\t\t\t\t`${source.aggregateType} ${source.aggregateId}: source position ` +\n\t\t\t\t\t\t`(${position.aggregateVersion}, ${position.commitSequence}) is ` +\n\t\t\t\t\t\t`already owned by event \"${positionOwner}\". One qualified source ` +\n\t\t\t\t\t\t\"position must identify exactly one immutable event.\",\n\t\t\t\t\tevent.type,\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (positionOwner === undefined) {\n\t\t\t\tsimulatedCursors.set(\n\t\t\t\t\tsourceKey,\n\t\t\t\t\tcursorWithEvent(cursor, position.commitSequence, event.eventId),\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\tasync getPending(limit?: number): Promise<ReadonlyArray<OutboxRecord<Evt>>> {\n\t\t// Copies, not the tracked internals: a caller mutating a returned\n\t\t// record must not corrupt the attempt bookkeeping. Map iteration\n\t\t// preserves insertion order, satisfying the port's ordering\n\t\t// contract. Stop at the limit instead of materializing the whole\n\t\t// backlog: a dispatcher polling a large backlog with a small batch\n\t\t// pays O(limit), not O(total pending). The clamp keeps a negative\n\t\t// limit (batchSize - inFlight going negative) at \"nothing\", not\n\t\t// \"everything but the last records\".\n\t\t// NaN (e.g. batchSize - inFlight with an undefined operand) clamps\n\t\t// to zero like the old slice(0, NaN) did, never to \"everything\".\n\t\tconst max =\n\t\t\ttypeof limit === \"number\"\n\t\t\t\t? Math.max(0, Number.isNaN(limit) ? 0 : limit)\n\t\t\t\t: Number.POSITIVE_INFINITY;\n\t\tconst batch: Array<OutboxRecord<Evt>> = [];\n\t\tfor (const record of this.pending.values()) {\n\t\t\tif (batch.length >= max) break;\n\t\t\tbatch.push({\n\t\t\t\tdispatchId: record.dispatchId,\n\t\t\t\tevent: record.event,\n\t\t\t\tsource: record.source,\n\t\t\t\tposition: record.position,\n\t\t\t\tattempts: record.attempts,\n\t\t\t});\n\t\t}\n\t\treturn batch;\n\t}\n\n\tasync markDispatched(dispatchIds: ReadonlyArray<string>): Promise<void> {\n\t\tfor (const id of dispatchIds) {\n\t\t\tconst record = this.pending.get(id) ?? this.dead.get(id);\n\t\t\tif (record !== undefined) {\n\t\t\t\tthis.rememberDispatched(id, record.source, record.position);\n\t\t\t}\n\t\t\tthis.pending.delete(id);\n\t\t\t// Manual redelivery then ack: dispatching a dead-lettered record\n\t\t\t// clears it too.\n\t\t\tthis.dead.delete(id);\n\t\t}\n\t}\n\n\tprivate rememberDispatched(\n\t\teventId: string,\n\t\tsource: AggregateAddress,\n\t\tposition: EventCommitCandidatePosition,\n\t): void {\n\t\tthis.dispatchedEventIds.delete(eventId);\n\t\tthis.dispatchedEventIds.set(eventId, {\n\t\t\tsource: Object.freeze({ ...source }),\n\t\t\tposition: Object.freeze({\n\t\t\t\taggregateVersion: position.aggregateVersion,\n\t\t\t\tcommitSequence: position.commitSequence,\n\t\t\t\tcommitSize: position.commitSize,\n\t\t\t}),\n\t\t});\n\t\twhile (this.dispatchedEventIds.size > this.maxRetainedDispatchedEventIds) {\n\t\t\tconst oldest = this.dispatchedEventIds.keys().next();\n\t\t\tif (oldest.done) break;\n\t\t\tthis.dispatchedEventIds.delete(oldest.value);\n\t\t}\n\t}\n\n\tasync markFailed(\n\t\tdispatchId: string,\n\t\terror?: unknown,\n\t): Promise<DeadLetterRecord<Evt> | undefined> {\n\t\tconst record = this.pending.get(dispatchId);\n\t\t// Unknown or already-dispatched (or already dead-lettered) id: a\n\t\t// late failure report must not resurrect anything.\n\t\tif (!record) return undefined;\n\t\trecord.attempts += 1;\n\t\trecord.lastError =\n\t\t\terror instanceof Error ? error.message : String(error ?? \"unknown\");\n\t\tif (record.attempts >= this.maxDeliveryAttempts) {\n\t\t\tthis.pending.delete(dispatchId);\n\t\t\tconst deadLetter: DeadLetterRecord<Evt> = {\n\t\t\t\tdispatchId: record.dispatchId,\n\t\t\t\tevent: record.event,\n\t\t\t\tsource: record.source,\n\t\t\t\tposition: record.position,\n\t\t\t\tattempts: record.attempts,\n\t\t\t\tlastError: record.lastError,\n\t\t\t};\n\t\t\tthis.dead.set(dispatchId, deadLetter);\n\t\t\treturn { ...deadLetter };\n\t\t}\n\t\treturn undefined;\n\t}\n\n\tasync deadLetters(): Promise<ReadonlyArray<DeadLetterRecord<Evt>>> {\n\t\treturn [...this.dead.values()].map((record) => ({ ...record }));\n\t}\n}\n\nfunction cursorWithEvent(\n\tcursor: EventSourceCursor,\n\tcommitSequence: number,\n\teventId: string,\n): EventSourceCursor {\n\treturn {\n\t\t...cursor,\n\t\teventIdsBySequence: new Map(cursor.eventIdsBySequence).set(\n\t\t\tcommitSequence,\n\t\t\teventId,\n\t\t),\n\t};\n}\n\nfunction assertSameCandidateReceipt(\n\tevent: AnyDomainEvent,\n\treceived: EventCommitCandidatePosition,\n\trecorded: EventCommitCandidatePosition,\n): void {\n\tassertReceiptShape(event, received, recorded, false);\n}\n\n/**\n * The lenient variant for PENDING records only: this in-memory adapter\n * cannot observe rollback, so a re-harvested event may legitimately arrive\n * at a new aggregateVersion. Index and commit cardinality stay immutable.\n */\nfunction assertSameCandidateReceiptAllowingVersionRefresh(\n\tevent: AnyDomainEvent,\n\treceived: EventCommitCandidatePosition,\n\trecorded: EventCommitCandidatePosition,\n): void {\n\tassertReceiptShape(event, received, recorded, true);\n}\n\nfunction assertReceiptShape(\n\tevent: AnyDomainEvent,\n\treceived: EventCommitCandidatePosition,\n\trecorded: EventCommitCandidatePosition,\n\tallowAggregateVersionRefresh: boolean,\n): void {\n\tconst sameVersion =\n\t\tallowAggregateVersionRefresh ||\n\t\treceived.aggregateVersion === recorded.aggregateVersion;\n\tif (\n\t\tsameVersion &&\n\t\treceived.commitSequence === recorded.commitSequence &&\n\t\treceived.commitSize === recorded.commitSize\n\t) {\n\t\treturn;\n\t}\n\tthrow new EventHarvestError(\n\t\t`InMemoryOutbox rejected event \"${event.eventId}\": its commit candidate ` +\n\t\t\t`changed from (${recorded.aggregateVersion}, ${recorded.commitSequence}; ` +\n\t\t\t`commitSize=${recorded.commitSize}) to (${received.aggregateVersion}, ` +\n\t\t\t`${received.commitSequence}; commitSize=${received.commitSize}). ` +\n\t\t\t\"An exact redelivery must keep its source position immutable.\",\n\t\tevent.type,\n\t);\n}\n\nfunction staleHeadError(\n\tevent: { readonly eventId: string; readonly type: string },\n\tsource: AggregateAddress,\n\tposition: EventCommitCandidatePosition,\n\tstaleHeadVersion: number,\n): EventHarvestError {\n\treturn new EventHarvestError(\n\t\t`InMemoryOutbox rejected stale event \"${event.eventId}\" for ` +\n\t\t\t`${source.aggregateType} ${source.aggregateId} at aggregate version ` +\n\t\t\t`${position.aggregateVersion}: the event-source head is already ` +\n\t\t\t`${staleHeadVersion}. The dispatched-id receipt may have ` +\n\t\t\t\"expired; use a durable outbox with a transactional eventId unique key \" +\n\t\t\t\"for unbounded idempotency.\",\n\t\tevent.type,\n\t);\n}\n\nfunction assertSameEventSource(\n\tevent: AnyDomainEvent,\n\treceived: AggregateAddress,\n\trecorded: AggregateAddress,\n): void {\n\tif (\n\t\treceived.aggregateType === recorded.aggregateType &&\n\t\treceived.aggregateId === recorded.aggregateId\n\t) {\n\t\treturn;\n\t}\n\tthrow new EventHarvestError(\n\t\t`InMemoryOutbox rejected eventId collision for \"${event.eventId}\": ` +\n\t\t\t`it already belongs to ${recorded.aggregateType} ${recorded.aggregateId}, ` +\n\t\t\t`but was received for ${received.aggregateType} ${received.aggregateId}. ` +\n\t\t\t\"An eventId must identify one immutable event across all aggregate sources.\",\n\t\tevent.type,\n\t);\n}\n","import type { AnyDomainEvent } from \"../aggregate/domain-event\";\nimport {\n\tassessDeliveryFailure,\n\ttype DeliveryFailureAssessment,\n\ttype DeliveryFailureClassifier,\n} from \"../utils/delivery-failure\";\nimport {\n\tDEFAULT_EXECUTION_TIMEOUT_MS,\n\ttype ExecutionContext,\n\trunBoundedExecution,\n} from \"../utils/execution\";\nimport { captureObserverFunctions, reportToObserver } from \"../utils/observer\";\nimport { PollLoop } from \"../utils/poll-loop\";\nimport { assertNonNegativeFinite } from \"../utils/validate\";\nimport {\n\ttype DeadLetterRecord,\n\ttype DispatchTrackingOutbox,\n\ttype EventBus,\n\tisDispatchTrackingOutbox,\n\ttype Outbox,\n\ttype OutboxRecord,\n} from \"./ports\";\n\n/**\n * Required operational observers for {@link OutboxDispatcher}. All hooks are\n * best-effort notifications: synchronous throws and rejected promises are\n * neutralized so observability cannot change delivery state. The dispatcher\n * captures and freezes these function references at construction, so later\n * mutation of the supplied object cannot disable an operational channel.\n *\n * `onDeadLetter` fires immediately after `markFailed` reports the exact\n * transition. It is not a durable notification boundary: a process can stop\n * after the store commits the transition and before the callback runs. Keep\n * polling {@link DispatchTrackingOutbox.deadLetters} for durable alerting and\n * reconciliation; the hook provides low-latency diagnostics.\n */\nexport interface OutboxDispatcherObservers<Evt extends AnyDomainEvent> {\n\t/**\n\t * A publish, acknowledgement, or failure-tracking operation failed.\n\t * Delivery failures include their accounting assessment. Store failures do\n\t * not; they are operationally distinct from poison-message attempts.\n\t */\n\treadonly onDispatchError: (\n\t\terror: unknown,\n\t\trecord: OutboxRecord<Evt>,\n\t\tassessment?: DeliveryFailureAssessment,\n\t) => void;\n\t/** Reading the pending page failed. */\n\treadonly onPollError: (error: unknown) => void;\n\t/** A tracked record crossed the store's dead-letter threshold. */\n\treadonly onDeadLetter: (record: DeadLetterRecord<Evt>) => void;\n}\n\n/**\n * Delivery target of the {@link OutboxDispatcher}: one driven port with a\n * single question, \"deliver this record's event\". The consumer implements\n * it against the real transport (message broker, webhook, queue\n * producer); {@link eventBusSink} adapts the in-process `EventBus` for\n * setups without a broker.\n *\n * The sink is called once per record, sequentially, in commit order. A\n * throw signals delivery failure; the dispatcher stops the batch,\n * reports the failure, and retries later (see the dispatcher contract).\n * Sinks must tolerate duplicate delivery: the dispatcher is\n * at-least-once by construction (a crash or ack failure between\n * `publish` and `markDispatched` redelivers). Dedupe on\n * `record.event.eventId`; projection sinks use the event's full gap-proof\n * commit cursor.\n *\n * **Resolve only after the transport acknowledged.** The dispatcher\n * calls `markDispatched` as soon as `publish` resolves, so the\n * resolution IS the delivery confirmation: await the broker's ack\n * (Kafka producer confirm, SQS SendMessage response, JetStream publish\n * ack, HTTP 2xx) before returning. A fire-and-forget publish that\n * resolves early marks records dispatched that the broker may never\n * have stored, which silently voids the at-least-once guarantee the\n * outbox exists to provide.\n *\n * Pass `context.signal` into the transport or enforce a native timeout no\n * later than `context.deadlineAt`. The dispatcher bounds its own wait, but it\n * cannot terminate a foreign promise that ignores cancellation; such an\n * adapter can leave zombie I/O overlapping the retry and is not production\n * conforming. The record remains pending unless `publish` had already resolved\n * and its dispatch acknowledgement was persisted.\n */\nexport interface OutboxSink<Evt extends AnyDomainEvent> {\n\tpublish: (\n\t\trecord: OutboxRecord<Evt>,\n\t\tcontext: ExecutionContext,\n\t) => Promise<void>;\n}\n\n/**\n * Adapts the in-process {@link EventBus} as an {@link OutboxSink}: the\n * zero-broker setup where the outbox still provides durability and\n * replay, and subscribers run in-process. Handler errors propagate as\n * delivery failures, so failed events retry through the normal\n * dispatcher loop instead of being lost.\n *\n * **Do not combine with `withCommit`'s `bus` fast path on the same\n * bus.** `withCommit({ scope, outbox, bus })` already publishes every\n * committed event to that bus post-commit, and the outbox record stays\n * pending regardless; a dispatcher with `eventBusSink(bus)` then\n * publishes the same event to the same subscribers a second time, on\n * EVERY commit, by construction. Pick one: omit `bus` from `withCommit`\n * and let the dispatcher deliver (durable, replayable), or keep the\n * fast path and point the dispatcher's sink at a different transport.\n *\n * **Retries are per event, not per handler.** One `publish` fans out to\n * ALL subscribers of the event's type, and the bus reports errors only\n * after every handler ran; the outbox tracks the EVENT, not individual\n * handlers. When one subscriber keeps failing, each retry re-executes\n * its co-subscribers too, up to the attempt ceiling. In-process\n * handlers are therefore consumers in the checklist sense: they must\n * be idempotent (dedupe on `eventId`), or non-idempotent reactions\n * (send mail, charge a card) must not share an event subscription with\n * failure-prone handlers. Per-handler delivery tracking is what broker\n * consumer groups (or per-subscriber checkpoints, see the read-model\n * guide) provide; this sink deliberately does not reimplement it.\n *\n * **Subscribe first, then start the dispatcher.** Publishing to a bus\n * with ZERO subscribers for the event's type resolves as delivered\n * (pub/sub semantics: delivery to all current subscribers, even none),\n * so the dispatcher acks the record and it never comes back. Records\n * polled in a startup window before module wiring registered its\n * subscriptions are therefore consumed without any handler seeing\n * them; register every subscription before `run()`/`drainOnce()`. A\n * `subscribeAll` consumer counts as a subscriber for every type. The\n * same holds for reactions added later: a new subscriber does not see\n * already-dispatched history; replay is a read-model concern, not a\n * bus feature.\n */\nexport function eventBusSink<Evt extends AnyDomainEvent>(\n\tbus: EventBus<Evt>,\n): OutboxSink<Evt> {\n\treturn {\n\t\tpublish: (record, context) =>\n\t\t\tbus.publish([record.event], {\n\t\t\t\tsignal: context.signal,\n\t\t\t\ttimeoutMs: Math.max(0, context.deadlineAt - Date.now()),\n\t\t\t}),\n\t};\n}\n\n/** Construction options for {@link OutboxDispatcher}. */\nexport interface OutboxDispatcherOptions<Evt extends AnyDomainEvent> {\n\t/**\n\t * The poll surface. Pass a {@link DispatchTrackingOutbox} to get\n\t * bounded retries: the dispatcher reports each delivery failure via\n\t * `markFailed`, and the store dead-letters records past its attempt\n\t * ceiling so a poison message stops blocking the queue. With a plain\n\t * {@link Outbox}, a poison message retries forever, rate-limited by\n\t * the backoff ceiling (documented trade-off; prefer the tracking\n\t * port in production).\n\t *\n\t * The tracking capability is detected STRUCTURALLY at runtime\n\t * (`markFailed` and `deadLetters` both present). A wrapper or\n\t * decorator around a tracking outbox must forward both methods;\n\t * one that exposes only the plain `Outbox` surface silently turns\n\t * bounded retries off.\n\t */\n\toutbox: Outbox<Evt> | DispatchTrackingOutbox<Evt>;\n\n\t/** Where events go; see {@link OutboxSink}. */\n\tsink: OutboxSink<Evt>;\n\n\t/**\n\t * Complete, required operational observer bundle. A plain `Outbox` never\n\t * calls `onDeadLetter`, but the complete bundle remains required so changing\n\t * the adapter to a tracking outbox cannot silently omit the alarm path.\n\t */\n\tobservers: OutboxDispatcherObservers<Evt>;\n\n\t/** Records fetched per poll. Default `32`. */\n\tbatchSize?: number;\n\n\t/** Idle sleep between polls when the outbox is empty. Default `250`ms. */\n\tpollIntervalMs?: number;\n\n\t/**\n\t * First backoff delay after a failure; grows exponentially with the\n\t * failing record's attempt count or the dispatcher's own\n\t * consecutive-failure streak (whichever is larger, so the delay grows\n\t * even when the store does not track attempts) and is jittered.\n\t * Default `50`ms.\n\t */\n\tbaseDelayMs?: number;\n\n\t/** Ceiling for the failure backoff. Default `5000`ms. */\n\tmaxDelayMs?: number;\n\n\t/**\n\t * Maximum time to await one sink publication. The sink receives the same\n\t * deadline as an AbortSignal and an absolute `deadlineAt`. Default `30000`ms.\n\t */\n\tdeliveryTimeoutMs?: number;\n\n\t/**\n\t * Maximum time to await one poll-store read, acknowledgement, or failure\n\t * update. The store receives the same cooperative context. This bounds the\n\t * worker's wait; production adapters must also cancel or natively bound the\n\t * underlying I/O. Default `30000`ms.\n\t */\n\tstorageTimeoutMs?: number;\n\n\t/**\n\t * Jitter source for the failure backoff, injectable for deterministic\n\t * tests. Default `Math.random`.\n\t */\n\trandom?: () => number;\n\n\t/**\n\t * Classifies delivery errors as transient, permanent, or unknown. Transient\n\t * failures back off without consuming the poison ceiling; permanent and\n\t * unknown failures count. The default walks the cause chain: native\n\t * `TimeoutError` and `retryable: true` are transient, `retryable: false` is\n\t * permanent, and unmapped errors are unknown. A throwing or invalid custom\n\t * classifier becomes unknown and is exposed through the observer assessment\n\t * without replacing the original delivery error.\n\t */\n\tclassifyFailure?: DeliveryFailureClassifier;\n}\n\n/**\n * Minimal polling dispatcher over the {@link Outbox} poll surface: the\n * delivery half of the transactional outbox for setups that do not plug\n * in an external delivery solution (see the outbox guide, \"External\n * dispatchers\", for that path). Intended for tests, moduliths without a\n * broker, and single-process deployments; it is deliberately a loop\n * over the kit's own port, not a messaging framework.\n *\n * Contract:\n *\n * - **At-least-once.** `markDispatched` runs only AFTER successful\n * `sink.publish` calls (the delivered prefix of a batch is acked in\n * one call); a crash or a failed ack between publish and ack\n * redelivers. Sinks and subscribers dedupe on `eventId` or the\n * full gap-proof commit cursor\n * (`domain-event-design.md`).\n * - **Sequential, stop-on-failure.** Records dispatch one at a time in\n * commit order, and the first failure stops the batch: continuing\n * past a failed event would break the per-aggregate causal order\n * `withCommit` promises subscribers. The price is head-of-line\n * blocking; the escape is the tracking outbox's attempt ceiling,\n * which dead-letters a poison record so the queue flows again.\n * - **Never rejects, always backs off.** Storage errors from\n * `getPending` and `markDispatched` are reported to the observers and\n * absorbed; every failed cycle grows the backoff (per the failing\n * record's attempts or the dispatcher's consecutive-failure streak)\n * toward `maxDelayMs`, so a persistent fault degrades to a slow,\n * observable retry cadence instead of a hot loop or a dead loop.\n * - **Bounded retries only with tracking.** With a\n * {@link DispatchTrackingOutbox}, permanent and unknown delivery failures\n * are reported via `markFailed`; transient failures back off without\n * consuming the poison ceiling. The shared default recognizes native\n * timeouts and `retryable` markers, and consumers can override it through\n * {@link OutboxDispatcherOptions.classifyFailure};\n * the store owns the ceiling and the dead-letter set (wire\n * `deadLetters()` to alerting). An ack failure\n * (`markDispatched` throwing) is NOT reported as a delivery failure:\n * the events were delivered, and counting them toward the poison\n * ceiling would dead-letter healthy records; they surface via\n * `onDispatchError`, once per record of the delivered prefix (every\n * one of them will redeliver), and a persistent ack fault is an\n * operational incident the observer makes visible on every cycle.\n * - **One logical instance per outbox** unless the adapter's\n * `getPending` claims records (see the port contract). The dispatcher\n * itself adds no cross-instance coordination.\n * - **Graceful stop.** `run(signal)` resolves (never rejects) when the\n * signal fires: mid-sleep immediately, mid-batch after the in-flight\n * record settles.\n *\n * For cron triggers and serverless runtimes, use {@link drainOnce} per\n * tick instead of the long-running `run`.\n *\n * @example\n * ```ts\n * const dispatcher = new OutboxDispatcher({\n * outbox,\n * sink,\n * observers: {\n * onDispatchError: (error, record) =>\n * log.warn({ error, eventId: record.event.eventId }, \"dispatch failed\"),\n * onPollError: (error) => log.warn({ error }, \"outbox poll failed\"),\n * onDeadLetter: (record) =>\n * alerts.page({ eventId: record.event.eventId }, \"outbox dead letter\"),\n * },\n * });\n * const stop = new AbortController();\n * void dispatcher.run(stop.signal);\n * // on shutdown:\n * stop.abort();\n * ```\n */\nexport class OutboxDispatcher<Evt extends AnyDomainEvent> extends PollLoop {\n\tprivate readonly outbox: Outbox<Evt> | DispatchTrackingOutbox<Evt>;\n\tprivate readonly sink: OutboxSink<Evt>;\n\tprivate readonly classifyFailure?: DeliveryFailureClassifier;\n\tprivate readonly observers: OutboxDispatcherObservers<Evt>;\n\tprivate readonly deliveryTimeoutMs: number;\n\tprivate readonly storageTimeoutMs: number;\n\n\t/**\n\t * Whether the outbox passed at construction implements the\n\t * dispatch-tracking protocol (`markFailed` AND `deadLetters`), i.e.\n\t * whether bounded retries and dead-lettering are active. Detection\n\t * is structural and happens ONCE, here. Assert this in your wiring\n\t * tests: a decorator that forwards only the plain `Outbox` methods\n\t * silently turns tracking off, and this flag is where that loss\n\t * becomes visible instead of surfacing as an endless poison retry.\n\t */\n\treadonly usesDispatchTracking: boolean;\n\n\t/** The tracking view of the outbox, when it qualifies (see above). */\n\tprivate readonly trackingOutbox?: DispatchTrackingOutbox<Evt>;\n\n\tconstructor(options: OutboxDispatcherOptions<Evt>) {\n\t\tsuper(\"OutboxDispatcher\", options);\n\t\tthis.observers = captureObserverFunctions(\n\t\t\t\"OutboxDispatcher\",\n\t\t\toptions.observers,\n\t\t\t[\"onDispatchError\", \"onPollError\", \"onDeadLetter\"],\n\t\t);\n\t\tthis.outbox = options.outbox;\n\t\tthis.trackingOutbox = isDispatchTrackingOutbox(options.outbox)\n\t\t\t? options.outbox\n\t\t\t: undefined;\n\t\tthis.usesDispatchTracking = this.trackingOutbox !== undefined;\n\t\tthis.sink = options.sink;\n\t\tthis.classifyFailure = options.classifyFailure;\n\t\tthis.deliveryTimeoutMs =\n\t\t\toptions.deliveryTimeoutMs ?? DEFAULT_EXECUTION_TIMEOUT_MS;\n\t\tthis.storageTimeoutMs =\n\t\t\toptions.storageTimeoutMs ?? DEFAULT_EXECUTION_TIMEOUT_MS;\n\t\tassertNonNegativeFinite(\n\t\t\t\"OutboxDispatcher\",\n\t\t\t\"deliveryTimeoutMs\",\n\t\t\tthis.deliveryTimeoutMs,\n\t\t);\n\t\tassertNonNegativeFinite(\n\t\t\t\"OutboxDispatcher\",\n\t\t\t\"storageTimeoutMs\",\n\t\t\tthis.storageTimeoutMs,\n\t\t);\n\t}\n\n\t/**\n\t * One full dispatch pass (the `run`/`drainOnce` shell lives on\n\t * {@link PollLoop}): dispatches pending records batch by batch until\n\t * the backlog is empty or a failure stops progress. A `\"stopped\"`\n\t * pass leaves the failed record pending (or dead-lettered by a\n\t * tracking outbox); the next cycle retries it.\n\t */\n\tprotected async pass(signal?: AbortSignal): Promise<\"drained\" | \"stopped\"> {\n\t\twhile (!signal?.aborted) {\n\t\t\tlet batch: ReadonlyArray<OutboxRecord<Evt>>;\n\t\t\ttry {\n\t\t\t\tbatch = await runBoundedExecution(\n\t\t\t\t\t\"OutboxDispatcher.getPending\",\n\t\t\t\t\t{ signal, timeoutMs: this.storageTimeoutMs },\n\t\t\t\t\t(context) => this.outbox.getPending(this.batchSize, context),\n\t\t\t\t);\n\t\t\t} catch (error) {\n\t\t\t\tif (signal?.aborted) return \"stopped\";\n\t\t\t\tthis.consecutiveFailures += 1;\n\t\t\t\treportToObserver(() => this.observers.onPollError(error));\n\t\t\t\treturn \"stopped\";\n\t\t\t}\n\t\t\tif (batch.length === 0) {\n\t\t\t\t// An empty backlog is proof of a healthy state: reset the\n\t\t\t\t// failure streak so the next, unrelated failure starts its\n\t\t\t\t// backoff at attempt 1 instead of inheriting an old streak\n\t\t\t\t// (e.g. after the store dead-lettered a poison record).\n\t\t\t\tthis.consecutiveFailures = 0;\n\t\t\t\treturn \"drained\";\n\t\t\t}\n\t\t\tconst completed = await this.dispatchBatch(batch, signal);\n\t\t\tif (!completed) return \"stopped\";\n\t\t}\n\t\treturn \"stopped\";\n\t}\n\n\t/**\n\t * Dispatches one batch sequentially and acks the delivered prefix in\n\t * a single `markDispatched` call. Returns `true` when every record\n\t * was delivered and acked, `false` when the pass stopped early\n\t * (publish failure, ack failure, or abort).\n\t */\n\tprivate async dispatchBatch(\n\t\tbatch: ReadonlyArray<OutboxRecord<Evt>>,\n\t\tsignal?: AbortSignal,\n\t): Promise<boolean> {\n\t\tconst delivered: string[] = [];\n\t\tlet failedRecord: OutboxRecord<Evt> | undefined;\n\t\tlet failure: unknown;\n\t\tfor (const record of batch) {\n\t\t\tif (signal?.aborted) break;\n\t\t\ttry {\n\t\t\t\tawait runBoundedExecution(\n\t\t\t\t\t\"OutboxDispatcher.publish\",\n\t\t\t\t\t{ signal, timeoutMs: this.deliveryTimeoutMs },\n\t\t\t\t\t(context) => this.sink.publish(record, context),\n\t\t\t\t);\n\t\t\t\tdelivered.push(record.dispatchId);\n\t\t\t} catch (error) {\n\t\t\t\tif (signal?.aborted) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tfailedRecord = record;\n\t\t\t\tfailure = error;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\t// Ack the delivered prefix in one round-trip, before handling the\n\t\t// failure, so delivered records do not redeliver.\n\t\tlet acked = true;\n\t\tif (delivered.length > 0) {\n\t\t\ttry {\n\t\t\t\t// A broker acknowledgement that won the publish/abort race must still\n\t\t\t\t// get one bounded persistence attempt. If shutdown had already fired\n\t\t\t\t// before this ack starts, the storage timeout owns that short grace\n\t\t\t\t// period; an ack already in flight remains owner-cancellable.\n\t\t\t\tconst acknowledgementSignal = signal?.aborted ? undefined : signal;\n\t\t\t\tawait runBoundedExecution(\n\t\t\t\t\t\"OutboxDispatcher.markDispatched\",\n\t\t\t\t\t{\n\t\t\t\t\t\tsignal: acknowledgementSignal,\n\t\t\t\t\t\ttimeoutMs: this.storageTimeoutMs,\n\t\t\t\t\t},\n\t\t\t\t\t(context) => this.outbox.markDispatched(delivered, context),\n\t\t\t\t);\n\t\t\t\tthis.consecutiveFailures = 0;\n\t\t\t} catch (error) {\n\t\t\t\t// The events WERE delivered; a failed ack means they will\n\t\t\t\t// redeliver (the documented at-least-once duplicates), so it\n\t\t\t\t// must not count toward the poison ceiling. The growing\n\t\t\t\t// consecutive-failure backoff rate-limits the duplicates.\n\t\t\t\t// Every record in the delivered prefix is affected; report\n\t\t\t\t// each one, so the operator can match the coming duplicates\n\t\t\t\t// to this ack failure instead of chasing them individually.\n\t\t\t\tacked = false;\n\t\t\t\tif (!signal?.aborted) {\n\t\t\t\t\tfor (const context of batch.slice(0, delivered.length)) {\n\t\t\t\t\t\treportToObserver(() =>\n\t\t\t\t\t\t\tthis.observers.onDispatchError(error, context),\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (failedRecord !== undefined) {\n\t\t\tconst record = failedRecord;\n\t\t\tconst error = failure;\n\t\t\tconst assessment = assessDeliveryFailure(error, this.classifyFailure);\n\t\t\treportToObserver(() =>\n\t\t\t\tthis.observers.onDispatchError(error, record, assessment),\n\t\t\t);\n\t\t\tconst tracking = this.trackingOutbox;\n\t\t\tif (tracking !== undefined && assessment.kind !== \"transient\") {\n\t\t\t\ttry {\n\t\t\t\t\tconst deadLetter = await runBoundedExecution(\n\t\t\t\t\t\t\"OutboxDispatcher.markFailed\",\n\t\t\t\t\t\t{ signal, timeoutMs: this.storageTimeoutMs },\n\t\t\t\t\t\t(context) => tracking.markFailed(record.dispatchId, error, context),\n\t\t\t\t\t);\n\t\t\t\t\tif (deadLetter !== undefined) {\n\t\t\t\t\t\treportToObserver(() => this.observers.onDeadLetter(deadLetter));\n\t\t\t\t\t}\n\t\t\t\t} catch (markError) {\n\t\t\t\t\tif (!signal?.aborted) {\n\t\t\t\t\t\treportToObserver(() =>\n\t\t\t\t\t\t\tthis.observers.onDispatchError(markError, record),\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// One streak bump per failed cycle, whatever combination of ack and\n\t\t// publish failures occurred, so the backoff grows exactly one\n\t\t// exponential step per cycle as documented.\n\t\tif (failedRecord !== undefined || !acked) {\n\t\t\tthis.consecutiveFailures = Math.max(\n\t\t\t\tthis.consecutiveFailures + 1,\n\t\t\t\t(failedRecord?.attempts ?? 0) + 1,\n\t\t\t);\n\t\t}\n\t\tif (failedRecord !== undefined) return false;\n\t\tif (!acked) return false;\n\t\t// An abort mid-batch left records unpublished; not a failure, but\n\t\t// not a completed batch either.\n\t\tif (signal?.aborted && delivered.length < batch.length) return false;\n\t\treturn true;\n\t}\n}\n","import type { AggregateAddress } from \"../aggregate/aggregate-address\";\nimport type { AnyDomainEvent } from \"../aggregate/domain-event\";\nimport type { CommitPosition } from \"../events/ports\";\n\n/**\n * A projection's gap-proof cursor into one aggregate's commit chain.\n * `aggregateVersion` plus `commitSequence` orders events; `commitSize`\n * proves the current commit is complete; `previousEventfulAggregateVersion`\n * links the next commit to the eventful predecessor. `withCommit` supplies\n * the current commit facts; the event source finalizes the predecessor on the\n * surrounding `CommittedDomainEvent`.\n *\n * A source MUST map exactly one immutable receipt to each qualified position:\n * one `eventId`, one `commitSize`, and one eventful predecessor. Custom\n * envelopes may translate another store's cursor into these fields, but\n * changing any part of an already observed receipt destroys the proof and is\n * a source-adapter bug.\n */\nexport type ProjectionPosition = CommitPosition;\n\n/**\n * Durable receipt for the last event one projection applied from an aggregate\n * stream. The position answers \"how far?\"; `lastAppliedEventId` identifies the\n * event at exactly that watermark. Together they let the projector distinguish\n * a true watermark redelivery from a source changing the event identity,\n * commit cardinality, or predecessor at the same position. Older positions\n * still rely on the source's immutable-receipt-per-position contract because a\n * checkpoint deliberately retains no full history.\n */\nexport interface ProjectionCheckpoint {\n\treadonly position: ProjectionPosition;\n\treadonly lastAppliedEventId: string;\n}\n\n/**\n * `true` when `candidate` comes strictly after `reference` in the\n * per-aggregate tuple order (higher version, or same version and higher\n * commit sequence). This comparison alone does not prove continuity;\n * the projector checks the boundary fields before advancing.\n */\nexport function isPositionAfter(\n\tcandidate: ProjectionPosition,\n\treference: ProjectionPosition,\n): boolean {\n\tif (candidate.aggregateVersion !== reference.aggregateVersion) {\n\t\treturn candidate.aggregateVersion > reference.aggregateVersion;\n\t}\n\treturn candidate.commitSequence > reference.commitSequence;\n}\n\n/**\n * Driven port for projection checkpoints: the per-`(projection,\n * aggregateType, aggregateId)` watermark receipt that makes a projection\n * idempotent and rebuild-safe. The {@link\n * ProjectionCheckpointStore.withCheckpointLocks} callback and every\n * {@link ProjectionCheckpointStore.load} / {@link\n * ProjectionCheckpointStore.save} it contains run inside the SAME transaction\n * as the read-model update (the `Projector` guarantees the pairing); the store\n * itself is a dumb last-write-wins record, monotonicity is the projector's job.\n *\n * Production adapters put the checkpoint table in the same database\n * as the read model, so update and checkpoint commit atomically: a\n * checkpoint without its update loses events, an update without its\n * checkpoint replays work. Verify an adapter with\n * `createProjectionCheckpointStoreContractTests` from\n * `@shirudo/ddd-kit/testing`.\n *\n * @template TCtx - The transaction context of the ambient\n * `TransactionScope` (a knex trx, a drizzle tx, a pg client)\n */\nexport interface ProjectionCheckpointStore<TCtx = unknown> {\n\t/**\n\t * Runs the complete checkpoint read / read-model update / checkpoint save\n\t * critical section with exclusive access to every supplied\n\t * `(projection, aggregateType, aggregateId)` key.\n\t *\n\t * Exclusivity MUST cover keys for which no checkpoint row exists yet. A\n\t * plain `SELECT ... FOR UPDATE` against the checkpoint table is therefore\n\t * insufficient at genesis: use transaction-scoped advisory/key locks, or\n\t * first materialize durable lock rows and lock those. Acquire multiple keys\n\t * in a deterministic order to avoid deadlocks, and keep database locks until\n\t * the surrounding transaction commits or rolls back. On entry, `work` must\n\t * observe checkpoint commits made by the preceding lock holder; choose the\n\t * transaction isolation level accordingly, or surface and retry a\n\t * serialization conflict instead of applying against a stale snapshot.\n\t *\n\t * Implementations may serialize more than the requested keys, but never\n\t * less. The callback is non-reentrant for an overlapping key set.\n\t */\n\twithCheckpointLocks<R>(\n\t\tctx: TCtx,\n\t\tprojection: string,\n\t\taddresses: ReadonlyArray<AggregateAddress>,\n\t\twork: () => Promise<R>,\n\t): Promise<R>;\n\n\t/**\n\t * The stored watermark receipt for `(projection, address)`, or `undefined`\n\t * when this projection has never applied an event of that\n\t * aggregate. Called inside the projector's transaction.\n\t */\n\tload(\n\t\tctx: TCtx,\n\t\tprojection: string,\n\t\taddress: AggregateAddress,\n\t): Promise<ProjectionCheckpoint | undefined>;\n\n\t/**\n\t * Persists the watermark receipt, overwriting a previous one (last write\n\t * wins; the projector only calls this with advancing checkpoints).\n\t * Called inside the projector's transaction, after the read-model\n\t * update it accounts for.\n\t */\n\tsave(\n\t\tctx: TCtx,\n\t\tprojection: string,\n\t\taddress: AggregateAddress,\n\t\tcheckpoint: ProjectionCheckpoint,\n\t): Promise<void>;\n\n\t/**\n\t * The wait-for-version building block: `true` when the stored\n\t * watermark for `(projection, address)` is at or past\n\t * `position`. Runs OUTSIDE any transaction (a query-side poll).\n\t *\n\t * Pass the position of the LAST event your commit emitted: all\n\t * events of one commit share the `aggregateVersion`, so comparing\n\t * on the version alone would report \"reached\" while later events\n\t * of the same commit are still unapplied.\n\t */\n\thasReached(\n\t\tprojection: string,\n\t\taddress: AggregateAddress,\n\t\tposition: ProjectionPosition,\n\t): Promise<boolean>;\n\n\t/**\n\t * Deletes every checkpoint of `projection` (other projections'\n\t * checkpoints are untouched): the rebuild entry point. Called\n\t * inside the rebuild transaction, together with the projection's\n\t * `truncate`, so a rebuild starts from a consistent zero.\n\t */\n\treset(ctx: TCtx, projection: string): Promise<void>;\n}\n\n/**\n * One projection: the consumer-owned mapping from events to ONE read\n * model (one table/view per projection; run several `Projector`s for\n * several read shapes). The kit owns the mechanics around it\n * (cursor skip, atomic checkpointing, rebuild); the handler owns the\n * read-model writes.\n *\n * The projector feed MUST contain every committed envelope for each aggregate\n * address it carries, including event types this read model does not use.\n * Handle those events as explicit no-ops in `apply`: the projector still\n * advances their cursor. Filtering a broker subscription by event type drops\n * positions from the source chain and turns the next commit into a real gap.\n * For correctness-critical read models, use `projectionFromHandlers` to make\n * every event in the declared union a compile-time handler-or-ignore decision;\n * implement this interface directly when intentionally partial routing is the\n * better fit.\n */\nexport interface Projection<Evt extends AnyDomainEvent, TCtx = unknown> {\n\t/**\n\t * Stable unique name; keys the checkpoints. Renaming it orphans the\n\t * old checkpoints and replays everything under the new name.\n\t */\n\tname: string;\n\n\t/**\n\t * Applies ONE event's read-model change inside the ambient\n\t * transaction. The projector's cursor already filtered duplicates\n\t * and stale events, so plain writes are safe; route on\n\t * `event.type` and handle creates, updates, deletes, corrections,\n\t * and tombstones explicitly (an upsert-only handler silently\n\t * retains stale rows). For a known event type this projection does not use,\n\t * return without writing; that explicit no-op still consumes and checkpoints\n\t * the envelope's source position.\n\t *\n\t * MUST be side-effect-free beyond the read model: no mails, no\n\t * external calls, no commands. A rebuild replays every event; side\n\t * effects would fire again.\n\t */\n\tapply(ctx: TCtx, event: Evt): Promise<void>;\n\n\t/**\n\t * Optional: clears the read model, called by `Projector.reset()`\n\t * in the same transaction as the checkpoint reset, so a rebuild\n\t * never observes a half-cleared state. Without it, truncating the\n\t * read model before a rebuild is the caller's responsibility.\n\t */\n\ttruncate?(ctx: TCtx): Promise<void>;\n}\n","import {\n\ttype AggregateAddress,\n\tencodeAggregateAddress,\n} from \"../aggregate/aggregate-address\";\nimport { InMemoryCapacityExceededError } from \"../core/errors\";\nimport { assertPositiveSafeInteger } from \"../utils/validate\";\nimport {\n\tisPositionAfter,\n\ttype ProjectionCheckpoint,\n\ttype ProjectionCheckpointStore,\n\ttype ProjectionPosition,\n} from \"./ports\";\n\nexport interface InMemoryProjectionCheckpointStoreOptions {\n\t/** Maximum checkpoints across all projection names and aggregate addresses. */\n\treadonly maxCheckpoints?: number;\n}\n\n/**\n * In-memory reference implementation of\n * {@link ProjectionCheckpointStore}: defines the port's semantics and\n * serves tests and in-memory read models.\n *\n * Its checkpoint-key locks serialize competing projectors only inside one\n * process and only when they share this store instance. It is **not\n * transaction-aware** (the `ctx` parameter is ignored): a rolled-back\n * projector batch does not roll back its checkpoints. Use it for tests and\n * disposable in-memory read models; production atomicity is the durable\n * adapter's contract, proved with `createProjectionCheckpointStoreContractTests`\n * and its rollback capability.\n *\n * Without `maxCheckpoints`, checkpoint retention is unbounded and supported\n * only for finite-lifetime tests and demos. A configured limit rejects a new\n * address before mutation; existing watermarks remain updatable and are never\n * evicted because forgetting one would change projection correctness.\n *\n * Do not nest `withCheckpointLocks` calls whose key sets overlap. This\n * reference has no async-context tracking for reentrancy: a nested call waits\n * on the key its caller still holds and therefore neither enters nor fails\n * loudly.\n */\nexport class InMemoryProjectionCheckpointStore\n\timplements ProjectionCheckpointStore<unknown>\n{\n\t/** projection name -> JSON [aggregateType, aggregateId] -> receipt */\n\tprivate readonly checkpoints = new Map<\n\t\tstring,\n\t\tMap<string, ProjectionCheckpoint>\n\t>();\n\t/** Full checkpoint key -> tail of the process-local exclusive-access queue. */\n\tprivate readonly lockTails = new Map<string, Promise<void>>();\n\tprivate readonly maxCheckpoints: number | undefined;\n\tprivate checkpointCount = 0;\n\n\tconstructor(options: InMemoryProjectionCheckpointStoreOptions = {}) {\n\t\tif (options.maxCheckpoints !== undefined) {\n\t\t\tassertPositiveSafeInteger(\n\t\t\t\t\"InMemoryProjectionCheckpointStore\",\n\t\t\t\t\"maxCheckpoints\",\n\t\t\t\toptions.maxCheckpoints,\n\t\t\t);\n\t\t}\n\t\tthis.maxCheckpoints = options.maxCheckpoints;\n\t}\n\n\tasync withCheckpointLocks<R>(\n\t\t_ctx: unknown,\n\t\tprojection: string,\n\t\taddresses: ReadonlyArray<AggregateAddress>,\n\t\twork: () => Promise<R>,\n\t): Promise<R> {\n\t\tconst keys = [\n\t\t\t...new Set(\n\t\t\t\taddresses.map((address) =>\n\t\t\t\t\tJSON.stringify([\n\t\t\t\t\t\tprojection,\n\t\t\t\t\t\taddress.aggregateType,\n\t\t\t\t\t\taddress.aggregateId,\n\t\t\t\t\t]),\n\t\t\t\t),\n\t\t\t),\n\t\t].sort();\n\t\tconst releases: Array<() => void> = [];\n\n\t\tfor (const key of keys) {\n\t\t\tconst previous = this.lockTails.get(key) ?? Promise.resolve();\n\t\t\tlet releaseCurrent!: () => void;\n\t\t\tconst current = new Promise<void>((resolve) => {\n\t\t\t\treleaseCurrent = resolve;\n\t\t\t});\n\t\t\tconst tail = previous.then(() => current);\n\t\t\tthis.lockTails.set(key, tail);\n\t\t\tawait previous;\n\t\t\treleases.push(() => {\n\t\t\t\treleaseCurrent();\n\t\t\t\tif (this.lockTails.get(key) === tail) this.lockTails.delete(key);\n\t\t\t});\n\t\t}\n\n\t\ttry {\n\t\t\treturn await work();\n\t\t} finally {\n\t\t\tfor (let index = releases.length - 1; index >= 0; index -= 1) {\n\t\t\t\treleases[index]?.();\n\t\t\t}\n\t\t}\n\t}\n\n\tasync load(\n\t\t_ctx: unknown,\n\t\tprojection: string,\n\t\taddress: AggregateAddress,\n\t): Promise<ProjectionCheckpoint | undefined> {\n\t\tconst stored = this.checkpoints\n\t\t\t.get(projection)\n\t\t\t?.get(encodeAggregateAddress(address));\n\t\t// Detached copy: a caller mutating the loaded receipt must not\n\t\t// move the stored watermark.\n\t\treturn stored === undefined\n\t\t\t? undefined\n\t\t\t: { ...stored, position: { ...stored.position } };\n\t}\n\n\tasync save(\n\t\t_ctx: unknown,\n\t\tprojection: string,\n\t\taddress: AggregateAddress,\n\t\tcheckpoint: ProjectionCheckpoint,\n\t): Promise<void> {\n\t\tconst addressKey = encodeAggregateAddress(address);\n\t\tlet perAggregate = this.checkpoints.get(projection);\n\t\tconst isNewCheckpoint = perAggregate?.has(addressKey) !== true;\n\t\tif (\n\t\t\tisNewCheckpoint &&\n\t\t\tthis.maxCheckpoints !== undefined &&\n\t\t\tthis.checkpointCount >= this.maxCheckpoints\n\t\t) {\n\t\t\tthrow new InMemoryCapacityExceededError({\n\t\t\t\tstore: \"InMemoryProjectionCheckpointStore\",\n\t\t\t\tresource: \"checkpoints\",\n\t\t\t\tlimit: this.maxCheckpoints,\n\t\t\t\tcurrent: this.checkpointCount,\n\t\t\t\tattempted: 1,\n\t\t\t});\n\t\t}\n\t\tif (perAggregate === undefined) {\n\t\t\tperAggregate = new Map();\n\t\t\tthis.checkpoints.set(projection, perAggregate);\n\t\t}\n\t\tperAggregate.set(addressKey, {\n\t\t\t...checkpoint,\n\t\t\tposition: { ...checkpoint.position },\n\t\t});\n\t\tif (isNewCheckpoint) this.checkpointCount += 1;\n\t}\n\n\tasync hasReached(\n\t\tprojection: string,\n\t\taddress: AggregateAddress,\n\t\tposition: ProjectionPosition,\n\t): Promise<boolean> {\n\t\tconst stored = this.checkpoints\n\t\t\t.get(projection)\n\t\t\t?.get(encodeAggregateAddress(address));\n\t\tif (stored === undefined) return false;\n\t\treturn !isPositionAfter(position, stored.position);\n\t}\n\n\tasync reset(_ctx: unknown, projection: string): Promise<void> {\n\t\tthis.checkpointCount -= this.checkpoints.get(projection)?.size ?? 0;\n\t\tthis.checkpoints.delete(projection);\n\t}\n}\n","import type { AnyDomainEvent } from \"../aggregate/domain-event\";\nimport { MissingHandlerError } from \"../core/errors\";\nimport type { Projection } from \"./ports\";\n\n/**\n * Explicit no-op entry for {@link ProjectionHandlers}. The projector still\n * consumes and checkpoints the event; only the read-model write is skipped.\n */\nexport const ignoreProjectionEvent = Symbol(\"ignoreProjectionEvent\");\n\n/** One discriminator-narrowed projection handler. */\nexport type ProjectionEventHandler<Evt extends AnyDomainEvent, TCtx> = (\n\tctx: TCtx,\n\tevent: Evt,\n) => Promise<void>;\n\n/**\n * Exhaustive handler map for a declared event union. Every discriminator needs\n * either a narrowed handler or {@link ignoreProjectionEvent}; adding an event\n * to `Evt` therefore creates a compile error until the projection decides how\n * to handle it.\n */\nexport type ProjectionHandlers<Evt extends AnyDomainEvent, TCtx> = {\n\treadonly [K in Evt[\"type\"]]:\n\t\t| ProjectionEventHandler<Extract<Evt, { type: K }>, TCtx>\n\t\t| typeof ignoreProjectionEvent;\n};\n\ntype RuntimeProjectionHandlerEntry<TCtx, Evt extends AnyDomainEvent> =\n\t| ProjectionEventHandler<Evt, TCtx>\n\t| typeof ignoreProjectionEvent;\n\n/** Construction options for {@link projectionFromHandlers}. */\nexport interface ProjectionFromHandlersOptions<\n\tEvt extends AnyDomainEvent,\n\tTCtx,\n> {\n\t/** Stable projection name used by its checkpoints. */\n\treadonly name: string;\n\t/** One handler or explicit ignore token for every event in `Evt`. */\n\treadonly handlers: ProjectionHandlers<Evt, TCtx>;\n\t/** Optional read-model reset passed through to {@link Projection.truncate}. */\n\treadonly truncate?: (ctx: TCtx) => Promise<void>;\n}\n\n/**\n * Builds a {@link Projection} from an exhaustive, discriminator-narrowed\n * handler map. This is the correctness-oriented alternative to a free-form\n * `Projection.apply`: extending `Evt` forces every projection using that union\n * to add a handler or an explicit {@link ignoreProjectionEvent} entry.\n *\n * The compile-time proof is only as complete as the supplied `Evt` union.\n * At runtime, an undeclared type (including object-prototype names such as\n * `constructor`) throws {@link MissingHandlerError}; the projector rejects the\n * batch without advancing its checkpoint.\n *\n * @example\n * ```ts\n * const projection = projectionFromHandlers<OrderEvent, DbTx>({\n * name: \"order-list\",\n * handlers: {\n * OrderPlaced: async (tx, event) => {\n * await tx.orders.insert({ id: event.aggregateId });\n * },\n * OrderShipped: ignoreProjectionEvent,\n * },\n * });\n * ```\n */\nexport function projectionFromHandlers<Evt extends AnyDomainEvent, TCtx>(\n\toptions: ProjectionFromHandlersOptions<Evt, TCtx>,\n): Projection<Evt, TCtx> {\n\treturn {\n\t\tname: options.name,\n\t\ttruncate: options.truncate,\n\t\tapply: async (ctx, event) => {\n\t\t\tconst entry = Object.hasOwn(options.handlers, event.type)\n\t\t\t\t? (options.handlers[event.type as Evt[\"type\"]] as\n\t\t\t\t\t\t| RuntimeProjectionHandlerEntry<TCtx, Evt>\n\t\t\t\t\t\t| undefined)\n\t\t\t\t: undefined;\n\t\t\tif (entry === undefined) {\n\t\t\t\tthrow new MissingHandlerError(event.type);\n\t\t\t}\n\t\t\tif (entry === ignoreProjectionEvent) return;\n\t\t\tawait entry(ctx, event);\n\t\t},\n\t};\n}\n","import {\n\ttype AggregateAddress,\n\tencodeAggregateAddress,\n} from \"../aggregate/aggregate-address\";\nimport type { AnyDomainEvent } from \"../aggregate/domain-event\";\nimport {\n\tForeignEventError,\n\tProjectionGapError,\n\tProjectionIdentityViolationError,\n\tProjectionOrderViolationError,\n\tProjectionReceiptViolationError,\n\tUnprojectableEventError,\n} from \"../core/errors\";\nimport type { OutboxSink } from \"../events/outbox-dispatcher\";\nimport type { CommittedDomainEvent } from \"../events/ports\";\nimport type { TransactionScope } from \"../repo/scope\";\nimport { abortReason } from \"../utils/abort\";\nimport {\n\tisPositionAfter,\n\ttype Projection,\n\ttype ProjectionCheckpoint,\n\ttype ProjectionCheckpointStore,\n\ttype ProjectionPosition,\n} from \"./ports\";\n\n/** Construction options for {@link Projector}. */\nexport interface ProjectorOptions<Evt extends AnyDomainEvent, TCtx> {\n\t/**\n\t * The transaction boundary that makes read-model update and\n\t * checkpoint atomic. Wire the SAME scope (same database) the\n\t * read model and the checkpoint table live in.\n\t */\n\tscope: TransactionScope<TCtx>;\n\n\t/** The checkpoint store; see {@link ProjectionCheckpointStore}. */\n\tcheckpoints: ProjectionCheckpointStore<TCtx>;\n\n\t/** The consumer-owned event-to-read-model mapping. */\n\tprojection: Projection<Evt, TCtx>;\n}\n\n/** Controls one atomic projection batch. */\nexport interface ProjectOptions {\n\t/** Cancellation forwarded cooperatively to the projection transaction. */\n\treadonly signal?: AbortSignal;\n}\n\n/** Outcome of one {@link Projector.project} batch. */\nexport interface ProjectionBatchResult {\n\t/** Events applied and checkpointed in this batch. */\n\tapplied: number;\n\t/** Events skipped at positions already traversed under the source contract. */\n\tskipped: number;\n}\n\n/**\n * The projection runner: applies event batches to ONE projection with\n * the mechanics `read-model-design.md` demands, so the consumer's\n * {@link Projection.apply} can be a plain mapping.\n *\n * Contract:\n *\n * - **Update and checkpoint commit atomically.** One batch runs in one\n * `TransactionScope` transaction; each advanced aggregate's watermark\n * is saved once, inside that transaction, after its events applied. A\n * failure anywhere rolls back the WHOLE batch (updates and\n * checkpoints together), so redelivery replays it from the previous\n * watermark. It is never possible to checkpoint an unapplied event or\n * apply an uncheckpointed one, and a retrying scope re-runs the\n * callback from zero (counts included).\n * - **Gaps reject instead of becoming silent skips.** `commitSize`\n * proves every event in a commit was consumed, while\n * `previousEventfulAggregateVersion` links the next eventful commit to the\n * checkpoint. A missing sequence, incomplete commit, missing aggregate\n * commit, or non-genesis first event throws before its event is applied.\n * Because checkpoints advance only across a verified chain, a position\n * at or behind the watermark is already traversed and can be skipped under\n * the source's one-logical-event-per-position contract.\n * - **Feeds are complete per aggregate address.** Once a feed supplies one\n * address, it must supply every committed envelope in that address's cursor\n * chain. Do not event-type-filter a projector subscription. Irrelevant event\n * types are explicit no-ops in `Projection.apply`; invoking the handler and\n * checkpointing their positions preserves continuity.\n * - **The watermark carries an exact receipt.** A different `eventId` at the\n * exact stored watermark, or at one position inside the current batch,\n * throws {@link ProjectionIdentityViolationError} before `apply`. The same\n * ID with a changed commit size or predecessor throws\n * {@link ProjectionReceiptViolationError}. The checkpoint deliberately keeps\n * no full position history, so older skips continue to rely on the source\n * contract rather than claiming a receipt proof it cannot provide.\n * - **Batch inversions reject as transport violations.** Before applying, the\n * projector scans distinct positions that were still unseen at batch start.\n * A descending pair for one aggregate throws\n * {@link ProjectionOrderViolationError}; positions the stored checkpoint had\n * already covered and exact receipts repeated inside the batch remain valid\n * redeliveries.\n * - **Malformed envelopes reject loudly.** A missing/empty `eventId`, a\n * missing/invalid `position`, missing `source.aggregateId` /\n * `source.aggregateType`, or an optional event address contradicting its\n * authoritative envelope source fails the batch BEFORE anything is applied.\n * The domain event remains persistence-agnostic.\n * - **Competing instances serialize by checkpoint key.** The required\n * {@link ProjectionCheckpointStore.withCheckpointLocks} callback covers the\n * complete load / apply / save critical section for every addressed\n * aggregate. The adapter must lock a key even when its checkpoint row does\n * not exist yet; a plain row lock is insufficient at genesis. Without that\n * adapter guarantee, only a hard single-projector deployment is safe.\n *\n * Feeding: hand batches to {@link Projector.project} from any source\n * (an outbox poll, a queue consumer, a replay), or wire the projector\n * straight into an `OutboxDispatcher` via {@link Projector.toOutboxSink}.\n *\n * Rebuild: {@link Projector.reset} clears checkpoints and (when the\n * projection provides `truncate`) the read model in one transaction;\n * then replay the source through `project` again. Rebuild-safety is\n * exactly why {@link Projection.apply} must be side-effect-free.\n */\nexport class Projector<Evt extends AnyDomainEvent, TCtx = unknown> {\n\tprivate readonly scope: TransactionScope<TCtx>;\n\tprivate readonly checkpoints: ProjectionCheckpointStore<TCtx>;\n\tprivate readonly projection: Projection<Evt, TCtx>;\n\n\tconstructor(options: ProjectorOptions<Evt, TCtx>) {\n\t\tthis.scope = options.scope;\n\t\tthis.checkpoints = options.checkpoints;\n\t\tthis.projection = options.projection;\n\t}\n\n\t/**\n\t * Applies one batch: one transaction and one exclusive checkpoint-key\n\t * section, per envelope a cursor check and `apply`, then one checkpoint save\n\t * per advanced aggregate. Rejects\n\t * (after rollback) when a handler throws or an envelope carries no\n\t * valid cursor; the caller's at-least-once redelivery retries the batch.\n\t * The input must be a complete, ordered feed per aggregate address; an\n\t * event-type-filtered subscription cannot satisfy the cursor contract.\n\t * An already-aborted signal rejects before validation or transaction setup.\n\t * In-flight cancellation is forwarded to the transaction scope rather than\n\t * raced, so the adapter remains the authority on rollback and atomicity.\n\t */\n\tasync project(\n\t\tevents: ReadonlyArray<CommittedDomainEvent<Evt>>,\n\t\toptions: ProjectOptions = {},\n\t): Promise<ProjectionBatchResult> {\n\t\tif (options.signal?.aborted) {\n\t\t\tthrow abortReason(\n\t\t\t\toptions.signal,\n\t\t\t\t\"Projector.project aborted before opening a transaction\",\n\t\t\t);\n\t\t}\n\t\t// Validate cursors BEFORE opening the transaction: a malformed\n\t\t// batch must not burn a transaction or apply a prefix.\n\t\tconst cursored = events.map(({ event, source, position }) => {\n\t\t\tif (typeof event.eventId !== \"string\" || event.eventId.length === 0) {\n\t\t\t\tthrow new UnprojectableEventError(\n\t\t\t\t\tthis.projection.name,\n\t\t\t\t\ttypeof event.eventId === \"string\" ? event.eventId : \"<missing>\",\n\t\t\t\t\t\"carries no non-empty eventId. Projection checkpoints retain the \" +\n\t\t\t\t\t\t\"event identity at their watermark, so every projectable event must \" +\n\t\t\t\t\t\t\"have a stable identifier.\",\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (position === undefined) {\n\t\t\t\tthrow new UnprojectableEventError(\n\t\t\t\t\tthis.projection.name,\n\t\t\t\t\tevent.eventId,\n\t\t\t\t\t\"carries no complete projection cursor envelope. Events written \" +\n\t\t\t\t\t\t\"by withCommit are wrapped automatically; other sources must \" +\n\t\t\t\t\t\t\"provide source and position explicitly.\",\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (!isValidPosition(position)) {\n\t\t\t\tthrow new UnprojectableEventError(\n\t\t\t\t\tthis.projection.name,\n\t\t\t\t\tevent.eventId,\n\t\t\t\t\t\"carries an invalid projection cursor: aggregateVersion and \" +\n\t\t\t\t\t\t\"commitSequence must be non-negative integers, commitSize must \" +\n\t\t\t\t\t\t\"be a positive integer greater than commitSequence, and \" +\n\t\t\t\t\t\t\"previousEventfulAggregateVersion must be an earlier non-negative \" +\n\t\t\t\t\t\t\"version or null at genesis.\",\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (source === undefined) {\n\t\t\t\tthrow new UnprojectableEventError(\n\t\t\t\t\tthis.projection.name,\n\t\t\t\t\tevent.eventId,\n\t\t\t\t\t\"carries no aggregateId/aggregateType in its commit envelope source.\",\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst { aggregateId, aggregateType } = source;\n\t\t\tif (!aggregateId || !aggregateType) {\n\t\t\t\tthrow new UnprojectableEventError(\n\t\t\t\t\tthis.projection.name,\n\t\t\t\t\tevent.eventId,\n\t\t\t\t\t\"carries no aggregateId/aggregateType; the checkpoint watermark \" +\n\t\t\t\t\t\t\"is keyed per (aggregateType, aggregateId), because ids are \" +\n\t\t\t\t\t\t\"type-scoped. Events written by withCommit carry both stamps.\",\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst idContradictsSource =\n\t\t\t\tevent.aggregateId !== undefined && event.aggregateId !== aggregateId;\n\t\t\tconst typeContradictsSource =\n\t\t\t\tevent.aggregateType !== undefined &&\n\t\t\t\tevent.aggregateType !== aggregateType;\n\t\t\tif (idContradictsSource || typeContradictsSource) {\n\t\t\t\tthrow new ForeignEventError(\n\t\t\t\t\taggregateId,\n\t\t\t\t\taggregateType,\n\t\t\t\t\tevent.type,\n\t\t\t\t\tevent.aggregateId,\n\t\t\t\t\tevent.aggregateType,\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst address: AggregateAddress = { aggregateType, aggregateId };\n\t\t\treturn { event, position, address };\n\t\t});\n\t\tconst lockAddresses = [\n\t\t\t...new Map(\n\t\t\t\tcursored.map(\n\t\t\t\t\t({ address }) => [encodeAggregateAddress(address), address] as const,\n\t\t\t\t),\n\t\t\t).entries(),\n\t\t]\n\t\t\t.sort(([left], [right]) => (left < right ? -1 : left > right ? 1 : 0))\n\t\t\t.map(([, address]) => address);\n\n\t\t// Everything mutable lives INSIDE the transactional callback: a\n\t\t// retrying scope re-runs it from zero, so a rolled-back attempt\n\t\t// can never leak counts or watermarks into the next one.\n\t\tconst projectWithLocks = async (\n\t\t\tctx: TCtx,\n\t\t): Promise<ProjectionBatchResult> => {\n\t\t\tlet applied = 0;\n\t\t\tlet skipped = 0;\n\t\t\t// Load and validate every addressed checkpoint before any handler\n\t\t\t// runs. Legacy/partial rows therefore cannot turn a batch prefix\n\t\t\t// into visible work even under the in-memory passthrough scope.\n\t\t\tconst checkpointsAtBatchStart = new Map<\n\t\t\t\tstring,\n\t\t\t\tProjectionCheckpoint | undefined\n\t\t\t>();\n\t\t\tconst watermarks = new Map<string, ProjectionPosition | undefined>();\n\t\t\tfor (const { event, address } of cursored) {\n\t\t\t\tconst key = encodeAggregateAddress(address);\n\t\t\t\tif (watermarks.has(key)) continue;\n\t\t\t\tconst stored = await this.checkpoints.load(\n\t\t\t\t\tctx,\n\t\t\t\t\tthis.projection.name,\n\t\t\t\t\taddress,\n\t\t\t\t);\n\t\t\t\tif (stored !== undefined && !isValidCheckpoint(stored)) {\n\t\t\t\t\tthrow new UnprojectableEventError(\n\t\t\t\t\t\tthis.projection.name,\n\t\t\t\t\t\tevent.eventId,\n\t\t\t\t\t\t\"found a stored checkpoint with an invalid or legacy cursor. \" +\n\t\t\t\t\t\t\t\"Migrate the commitSize/previousEventfulAggregateVersion/\" +\n\t\t\t\t\t\t\t\"lastAppliedEventId columns or \" +\n\t\t\t\t\t\t\t\"reset and rebuild this projection.\",\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tcheckpointsAtBatchStart.set(key, stored);\n\t\t\t\twatermarks.set(key, stored?.position);\n\t\t\t}\n\n\t\t\t// A checkpoint remembers the complete receipt at exactly its watermark. A\n\t\t\t// different eventId or different commit-boundary metadata at that same\n\t\t\t// ordered position is therefore a provable source collision. Older\n\t\t\t// positions cannot be identity-checked without retaining an unbounded\n\t\t\t// per-position ledger and continue to rely on the source contract that one\n\t\t\t// position names one immutable logical event receipt.\n\t\t\tfor (const { event, position, address } of cursored) {\n\t\t\t\tconst stored = checkpointsAtBatchStart.get(\n\t\t\t\t\tencodeAggregateAddress(address),\n\t\t\t\t);\n\t\t\t\tif (\n\t\t\t\t\tstored !== undefined &&\n\t\t\t\t\tisSameOrderedPosition(position, stored.position)\n\t\t\t\t) {\n\t\t\t\t\tif (event.eventId !== stored.lastAppliedEventId) {\n\t\t\t\t\t\tthrow new ProjectionIdentityViolationError(\n\t\t\t\t\t\t\tthis.projection.name,\n\t\t\t\t\t\t\tevent.eventId,\n\t\t\t\t\t\t\tstored.lastAppliedEventId,\n\t\t\t\t\t\t\tformatPosition(position),\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\tif (!isSamePositionReceipt(position, stored.position)) {\n\t\t\t\t\t\tthrow new ProjectionReceiptViolationError(\n\t\t\t\t\t\t\tthis.projection.name,\n\t\t\t\t\t\t\tevent.eventId,\n\t\t\t\t\t\t\tformatReceipt(stored.position),\n\t\t\t\t\t\t\tformatReceipt(position),\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst batchReceiptsByPosition = new Map<\n\t\t\t\tstring,\n\t\t\t\t{ eventId: string; position: ProjectionPosition }\n\t\t\t>();\n\t\t\tfor (const { event, position, address } of cursored) {\n\t\t\t\tconst key = addressedPositionKey(address, position);\n\t\t\t\tconst recorded = batchReceiptsByPosition.get(key);\n\t\t\t\tif (recorded !== undefined && recorded.eventId !== event.eventId) {\n\t\t\t\t\tthrow new ProjectionIdentityViolationError(\n\t\t\t\t\t\tthis.projection.name,\n\t\t\t\t\t\tevent.eventId,\n\t\t\t\t\t\trecorded.eventId,\n\t\t\t\t\t\tformatPosition(position),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tif (\n\t\t\t\t\trecorded !== undefined &&\n\t\t\t\t\t!isSamePositionReceipt(position, recorded.position)\n\t\t\t\t) {\n\t\t\t\t\tthrow new ProjectionReceiptViolationError(\n\t\t\t\t\t\tthis.projection.name,\n\t\t\t\t\t\tevent.eventId,\n\t\t\t\t\t\tformatReceipt(recorded.position),\n\t\t\t\t\t\tformatReceipt(position),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tbatchReceiptsByPosition.set(key, {\n\t\t\t\t\teventId: event.eventId,\n\t\t\t\t\tposition,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\t// A descending pair among DISTINCT positions that were still unseen at\n\t\t\t// batch start is direct evidence of transport reordering. Ignore positions\n\t\t\t// the stored checkpoint had already covered and exact receipts already seen\n\t\t\t// in this batch: those are harmless redeliveries. The preceding collision\n\t\t\t// pass proved that a repeated ordered position has the same eventId and full\n\t\t\t// receipt, so this skip cannot hide conflicting source data.\n\t\t\tconst newestUnprocessed = new Map<string, ProjectionPosition>();\n\t\t\tconst positionsSeenInBatch = new Set<string>();\n\t\t\tfor (const { event, position, address } of cursored) {\n\t\t\t\tconst key = encodeAggregateAddress(address);\n\t\t\t\tconst stored = watermarks.get(key);\n\t\t\t\tif (stored !== undefined && !isPositionAfter(position, stored))\n\t\t\t\t\tcontinue;\n\t\t\t\tconst positionKey = addressedPositionKey(address, position);\n\t\t\t\tif (positionsSeenInBatch.has(positionKey)) continue;\n\t\t\t\tpositionsSeenInBatch.add(positionKey);\n\t\t\t\tconst newest = newestUnprocessed.get(key);\n\t\t\t\tif (newest !== undefined && isPositionAfter(newest, position)) {\n\t\t\t\t\tthrow new ProjectionOrderViolationError(\n\t\t\t\t\t\tthis.projection.name,\n\t\t\t\t\t\tevent.eventId,\n\t\t\t\t\t\tformatPosition(newest),\n\t\t\t\t\t\tformatPosition(position),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tif (newest === undefined || isPositionAfter(position, newest)) {\n\t\t\t\t\tnewestUnprocessed.set(key, position);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Prove the whole batch's cursor chain before mutating the read\n\t\t\t// model. The simulated watermark also provides intra-batch dedupe\n\t\t\t// without relying on checkpoint-store read-your-writes behavior.\n\t\t\tconst advanced = new Map<\n\t\t\t\tstring,\n\t\t\t\t{ address: AggregateAddress; checkpoint: ProjectionCheckpoint }\n\t\t\t>();\n\t\t\tconst toApply: Array<{ event: Evt }> = [];\n\t\t\tfor (const { event, position, address } of cursored) {\n\t\t\t\tconst key = encodeAggregateAddress(address);\n\t\t\t\tconst watermark = watermarks.get(key);\n\t\t\t\tif (watermark !== undefined && !isPositionAfter(position, watermark)) {\n\t\t\t\t\tskipped += 1;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (!isContiguousPosition(position, watermark)) {\n\t\t\t\t\tthrow new ProjectionGapError(\n\t\t\t\t\t\tthis.projection.name,\n\t\t\t\t\t\tevent.eventId,\n\t\t\t\t\t\tformatPosition(watermark),\n\t\t\t\t\t\tformatPosition(position),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\twatermarks.set(key, position);\n\t\t\t\tadvanced.set(key, {\n\t\t\t\t\taddress,\n\t\t\t\t\tcheckpoint: {\n\t\t\t\t\t\tposition,\n\t\t\t\t\t\tlastAppliedEventId: event.eventId,\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t\ttoApply.push({ event });\n\t\t\t\tapplied += 1;\n\t\t\t}\n\t\t\tfor (const { event } of toApply) {\n\t\t\t\tawait this.projection.apply(ctx, event);\n\t\t\t}\n\t\t\tfor (const { address, checkpoint } of advanced.values()) {\n\t\t\t\tawait this.checkpoints.save(\n\t\t\t\t\tctx,\n\t\t\t\t\tthis.projection.name,\n\t\t\t\t\taddress,\n\t\t\t\t\tcheckpoint,\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn { applied, skipped };\n\t\t};\n\t\treturn this.scope.transactional(\n\t\t\t(ctx) =>\n\t\t\t\tthis.checkpoints.withCheckpointLocks(\n\t\t\t\t\tctx,\n\t\t\t\t\tthis.projection.name,\n\t\t\t\t\tlockAddresses,\n\t\t\t\t\t() => projectWithLocks(ctx),\n\t\t\t\t),\n\t\t\t{ signal: options.signal },\n\t\t);\n\t}\n\n\t/**\n\t * The wait-for-version query: `true` when this projection has\n\t * processed the addressed aggregate at least up to `position`. Pass the\n\t * position of the last event the awaited commit emitted (see\n\t * {@link ProjectionCheckpointStore.hasReached} for why the full\n\t * cursor, not just the version).\n\t */\n\thasProcessed(\n\t\taddress: AggregateAddress,\n\t\tposition: ProjectionPosition,\n\t): Promise<boolean> {\n\t\treturn this.checkpoints.hasReached(this.projection.name, address, position);\n\t}\n\n\t/**\n\t * Rebuild entry point: one transaction that clears this\n\t * projection's checkpoints and, when the projection provides\n\t * `truncate`, the read model with them. Replay the source through\n\t * {@link Projector.project} afterwards. Stop all live consumers for this\n\t * projection before reset and keep them stopped through catch-up replay;\n\t * rebuild is not coordinated by the per-address delivery locks.\n\t */\n\tasync reset(): Promise<void> {\n\t\tawait this.scope.transactional(async (ctx) => {\n\t\t\tawait this.projection.truncate?.(ctx);\n\t\t\tawait this.checkpoints.reset(ctx, this.projection.name);\n\t\t});\n\t}\n\n\t/**\n\t * Adapts this projector as an `OutboxSink`, so an `OutboxDispatcher`\n\t * can feed it directly: each record becomes a single-event batch\n\t * (apply + checkpoint in its own transaction), a throw leaves the\n\t * record pending for the dispatcher's retry/dead-letter mechanics.\n\t * Duplicates the dispatcher redelivers are absorbed by the cursor.\n\t *\n\t * **Dead-lettering a projection event stalls that aggregate chain.**\n\t * A later event cannot advance past the missing commit/sequence: it\n\t * fails with `ProjectionGapError` until the dead letter is repaired\n\t * and replayed (or the projection is reset and rebuilt). No unseen\n\t * event is silently classified as a duplicate.\n\t */\n\ttoOutboxSink(): OutboxSink<Evt> {\n\t\treturn {\n\t\t\tpublish: async (record, context) => {\n\t\t\t\tawait this.project([record], { signal: context.signal });\n\t\t\t},\n\t\t};\n\t}\n}\n\ntype GapAwareProjectionPosition = ProjectionPosition & {\n\tcommitSize: number;\n\tpreviousEventfulAggregateVersion: number | null;\n};\n\nfunction isGapAwarePosition(\n\tposition: ProjectionPosition,\n): position is GapAwareProjectionPosition {\n\treturn (\n\t\tNumber.isInteger(position.commitSize) &&\n\t\tObject.hasOwn(position, \"previousEventfulAggregateVersion\")\n\t);\n}\n\nfunction isValidPosition(\n\tposition: ProjectionPosition,\n): position is GapAwareProjectionPosition {\n\tif (!isGapAwarePosition(position)) return false;\n\tconst previous = position.previousEventfulAggregateVersion;\n\treturn (\n\t\tNumber.isInteger(position.aggregateVersion) &&\n\t\tposition.aggregateVersion >= 0 &&\n\t\tNumber.isInteger(position.commitSequence) &&\n\t\tposition.commitSequence >= 0 &&\n\t\tposition.commitSize > position.commitSequence &&\n\t\t(previous === null ||\n\t\t\t(Number.isInteger(previous) &&\n\t\t\t\tprevious >= 0 &&\n\t\t\t\tprevious < position.aggregateVersion))\n\t);\n}\n\nfunction isValidCheckpoint(\n\tcheckpoint: unknown,\n): checkpoint is ProjectionCheckpoint {\n\tif (typeof checkpoint !== \"object\" || checkpoint === null) return false;\n\tconst candidate = checkpoint as Partial<ProjectionCheckpoint>;\n\treturn (\n\t\ttypeof candidate.lastAppliedEventId === \"string\" &&\n\t\tcandidate.lastAppliedEventId.length > 0 &&\n\t\tcandidate.position !== undefined &&\n\t\tisValidPosition(candidate.position)\n\t);\n}\n\nfunction isSameOrderedPosition(\n\tleft: ProjectionPosition,\n\tright: ProjectionPosition,\n): boolean {\n\treturn (\n\t\tleft.aggregateVersion === right.aggregateVersion &&\n\t\tleft.commitSequence === right.commitSequence\n\t);\n}\n\nfunction isSamePositionReceipt(\n\tleft: ProjectionPosition,\n\tright: ProjectionPosition,\n): boolean {\n\treturn (\n\t\tisSameOrderedPosition(left, right) &&\n\t\tleft.commitSize === right.commitSize &&\n\t\tleft.previousEventfulAggregateVersion ===\n\t\t\tright.previousEventfulAggregateVersion\n\t);\n}\n\nfunction addressedPositionKey(\n\taddress: AggregateAddress,\n\tposition: ProjectionPosition,\n): string {\n\treturn JSON.stringify([\n\t\taddress.aggregateType,\n\t\taddress.aggregateId,\n\t\tposition.aggregateVersion,\n\t\tposition.commitSequence,\n\t]);\n}\n\nfunction isContiguousPosition(\n\tcandidate: GapAwareProjectionPosition,\n\twatermark: ProjectionPosition | undefined,\n): boolean {\n\tif (\n\t\tcandidate.commitSize < 1 ||\n\t\tcandidate.commitSequence < 0 ||\n\t\tcandidate.commitSequence >= candidate.commitSize\n\t) {\n\t\treturn false;\n\t}\n\tif (watermark === undefined) {\n\t\treturn (\n\t\t\tcandidate.commitSequence === 0 &&\n\t\t\tcandidate.previousEventfulAggregateVersion === null\n\t\t);\n\t}\n\tif (!isGapAwarePosition(watermark)) return false;\n\tif (candidate.aggregateVersion === watermark.aggregateVersion) {\n\t\treturn (\n\t\t\tcandidate.previousEventfulAggregateVersion ===\n\t\t\t\twatermark.previousEventfulAggregateVersion &&\n\t\t\tcandidate.commitSize === watermark.commitSize &&\n\t\t\tcandidate.commitSequence === watermark.commitSequence + 1\n\t\t);\n\t}\n\treturn (\n\t\twatermark.commitSequence === watermark.commitSize - 1 &&\n\t\tcandidate.commitSequence === 0 &&\n\t\tcandidate.previousEventfulAggregateVersion === watermark.aggregateVersion\n\t);\n}\n\nfunction formatPosition(position: ProjectionPosition | undefined): string {\n\tif (position === undefined) return \"genesis\";\n\treturn `(${position.aggregateVersion}, ${position.commitSequence})`;\n}\n\nfunction formatReceipt(position: ProjectionPosition): string {\n\treturn (\n\t\t`(${position.aggregateVersion}, ${position.commitSequence}; ` +\n\t\t`commitSize=${position.commitSize}, ` +\n\t\t`previousEventfulAggregateVersion=${String(\n\t\t\tposition.previousEventfulAggregateVersion,\n\t\t)})`\n\t);\n}\n","import {\n\ttype AggregateAddress,\n\tencodeAggregateAddress,\n} from \"../aggregate/aggregate-address\";\nimport type { AnyDomainEvent } from \"../aggregate/domain-event\";\nimport {\n\tConcurrencyConflictError,\n\tInMemoryCapacityExceededError,\n} from \"../core/errors\";\nimport { assertPositiveSafeInteger } from \"../utils/validate\";\nimport type {\n\tEventStore,\n\tEventStoreAppendOptions,\n\tReadStreamOptions,\n\tStreamReadResult,\n} from \"./event-store\";\n\n/** Optional fail-loud capacities for the finite-lifetime reference store. */\nexport interface InMemoryEventStoreOptions {\n\t/** Maximum aggregate streams retained by this instance. */\n\treadonly maxStreams?: number;\n\t/** Maximum events retained across every stream in this instance. */\n\treadonly maxEvents?: number;\n}\n\nfunction assertStreamPosition(\n\tname: \"fromVersion\" | \"toVersion\",\n\tvalue: number | undefined,\n): void {\n\tif (value !== undefined && (!Number.isSafeInteger(value) || value < 0)) {\n\t\tthrow new RangeError(\n\t\t\t`InMemoryEventStore: ${name} must be a non-negative safe integer, got ${String(value)}`,\n\t\t);\n\t}\n}\n\n/**\n * In-memory reference implementation of `EventStore<Evt>`.\n *\n * Intended for finite-lifetime tests and quick-start demos. With no capacity\n * options, streams and events are unbounded for the lifetime of the instance.\n * Long-lived processes must configure `maxStreams` and `maxEvents` or use a\n * durable adapter. Capacity exhaustion rejects before mutation with\n * `InMemoryCapacityExceededError`; histories are never silently evicted.\n * Implements the full port contract: expectedVersion-guarded appends\n * (throwing `ConcurrencyConflictError` on mismatch), atomic rejected\n * appends, explicit missing/existing stream state with the actual head,\n * append-order reads, mandatory page bounds, and `(fromVersion, toVersion]`\n * slicing. Invalid limits or positions reject with `RangeError`.\n *\n * For production, back the port with a durable store whose append and\n * the aggregate transaction share atomicity (a table with a\n * `(aggregate_type, aggregate_id, position)` unique key inside the same\n * transaction, or a dedicated event store). Same caveat as\n * `InMemoryOutbox`: this class\n * lives in memory only and knows nothing about your `TransactionScope`\n * rollbacks; events appended inside a transaction that later rolls back\n * are NOT removed. The event-sourced repository contract suite's\n * reference environment shows the snapshot/restore pattern for\n * rollback-pure in-memory testing.\n */\nexport class InMemoryEventStore<Evt extends AnyDomainEvent>\n\timplements EventStore<Evt>\n{\n\tprivate readonly streams = new Map<string, Evt[]>();\n\tprivate readonly maxStreams: number | undefined;\n\tprivate readonly maxEvents: number | undefined;\n\tprivate totalEvents = 0;\n\n\tconstructor(options: InMemoryEventStoreOptions = {}) {\n\t\tif (options.maxStreams !== undefined) {\n\t\t\tassertPositiveSafeInteger(\n\t\t\t\t\"InMemoryEventStore\",\n\t\t\t\t\"maxStreams\",\n\t\t\t\toptions.maxStreams,\n\t\t\t);\n\t\t}\n\t\tif (options.maxEvents !== undefined) {\n\t\t\tassertPositiveSafeInteger(\n\t\t\t\t\"InMemoryEventStore\",\n\t\t\t\t\"maxEvents\",\n\t\t\t\toptions.maxEvents,\n\t\t\t);\n\t\t}\n\t\tthis.maxStreams = options.maxStreams;\n\t\tthis.maxEvents = options.maxEvents;\n\t}\n\n\tasync append(\n\t\tstream: AggregateAddress,\n\t\tevents: ReadonlyArray<Evt>,\n\t\toptions: EventStoreAppendOptions,\n\t): Promise<void> {\n\t\tif (events.length === 0) return;\n\t\tconst key = encodeAggregateAddress(stream);\n\t\tconst existing = this.streams.get(key);\n\t\tif ((existing?.length ?? 0) !== options.expectedVersion) {\n\t\t\tthrow new ConcurrencyConflictError({\n\t\t\t\taggregateType: stream.aggregateType,\n\t\t\t\taggregateId: stream.aggregateId,\n\t\t\t\texpectedVersion: options.expectedVersion,\n\t\t\t\tactualVersion: existing?.length ?? 0,\n\t\t\t});\n\t\t}\n\t\tif (\n\t\t\texisting === undefined &&\n\t\t\tthis.maxStreams !== undefined &&\n\t\t\tthis.streams.size >= this.maxStreams\n\t\t) {\n\t\t\tthrow new InMemoryCapacityExceededError({\n\t\t\t\tstore: \"InMemoryEventStore\",\n\t\t\t\tresource: \"streams\",\n\t\t\t\tlimit: this.maxStreams,\n\t\t\t\tcurrent: this.streams.size,\n\t\t\t\tattempted: 1,\n\t\t\t});\n\t\t}\n\t\tif (\n\t\t\tthis.maxEvents !== undefined &&\n\t\t\tthis.totalEvents + events.length > this.maxEvents\n\t\t) {\n\t\t\tthrow new InMemoryCapacityExceededError({\n\t\t\t\tstore: \"InMemoryEventStore\",\n\t\t\t\tresource: \"events\",\n\t\t\t\tlimit: this.maxEvents,\n\t\t\t\tcurrent: this.totalEvents,\n\t\t\t\tattempted: events.length,\n\t\t\t});\n\t\t}\n\t\t// Atomic by construction: the conflict check above throws before\n\t\t// anything is written (including the get-or-create, so a rejected\n\t\t// append on a nonexistent stream leaves no empty entry behind).\n\t\t// Pushing in place keeps append O(batch) instead of O(stream) per\n\t\t// call; no caller ever holds the internal array (readStream\n\t\t// slices). Element-wise, not push(...events): a spread into\n\t\t// arguments overflows the engine's argument limit on huge batches.\n\t\tlet storedEvents = existing;\n\t\tif (storedEvents === undefined) {\n\t\t\tstoredEvents = [];\n\t\t\tthis.streams.set(key, storedEvents);\n\t\t}\n\t\tfor (const event of events) {\n\t\t\t// Detached on write and on read: the port forbids handing out\n\t\t\t// live internal state, and a caller-mutated plain event must not\n\t\t\t// rewrite stored history. Kit-minted events are already frozen;\n\t\t\t// the clone detaches them from the shared graph as well.\n\t\t\tstoredEvents.push(structuredClone(event));\n\t\t}\n\t\tthis.totalEvents += events.length;\n\t}\n\n\tasync readStream(\n\t\tstream: AggregateAddress,\n\t\toptions: ReadStreamOptions,\n\t): Promise<StreamReadResult<Evt>> {\n\t\tif (!Number.isSafeInteger(options?.limit) || options.limit < 1) {\n\t\t\tthrow new RangeError(\n\t\t\t\t`InMemoryEventStore: limit must be a positive safe integer, got ${String(options?.limit)}`,\n\t\t\t);\n\t\t}\n\t\tassertStreamPosition(\"fromVersion\", options.fromVersion);\n\t\tassertStreamPosition(\"toVersion\", options.toVersion);\n\t\tconst events = this.streams.get(encodeAggregateAddress(stream));\n\t\tif (events === undefined) {\n\t\t\treturn { exists: false, lastVersion: 0, events: [] };\n\t\t}\n\t\tconst fromVersion = options.fromVersion ?? 0;\n\t\tconst toVersion = options.toVersion;\n\t\tconst pageEnd = Math.min(\n\t\t\ttoVersion ?? events.length,\n\t\t\tfromVersion + options.limit,\n\t\t);\n\t\t// Cloned, not sliced: slice() copies the ARRAY but hands out live\n\t\t// references to the stored elements, and a reader mutating one would\n\t\t// silently corrupt every later replay.\n\t\treturn {\n\t\t\texists: true,\n\t\t\tlastVersion: events.length,\n\t\t\tevents: structuredClone(events.slice(fromVersion, pageEnd)),\n\t\t};\n\t}\n}\n","import type { AggregateSnapshot } from \"../aggregate/aggregate\";\nimport {\n\ttype AggregateAddress,\n\tencodeAggregateAddress,\n} from \"../aggregate/aggregate-address\";\nimport { assertPositiveSafeInteger } from \"../utils/validate\";\nimport type { SnapshotStore } from \"./snapshot-store\";\n\nexport interface InMemorySnapshotStoreOptions {\n\t/** Maximum retained snapshots. The least recently used entry is evicted. */\n\treadonly maxEntries?: number;\n\t/** Snapshot lifetime from the most recent save. Loads do not extend it. */\n\treadonly ttlMs?: number;\n\t/** Store-local clock used only when `ttlMs` is configured. */\n\treadonly clock?: () => Date;\n}\n\ninterface StoredSnapshot<TState> {\n\treadonly snapshot: AggregateSnapshot<TState>;\n\treadonly expiresAtMs?: number;\n}\n\n/**\n * In-memory reference implementation of {@link SnapshotStore}: defines\n * the port's semantics and serves tests and demos. Snapshots are\n * deep-copied on save AND load (`structuredClone`; snapshot state is\n * serialisable data by the `SnapshotModel` contract), so neither the caller\n * nor the store can mutate the other's copy.\n *\n * Unconfigured retention is intended only for finite-lifetime tests and\n * demos. Unlike event history, receipts, or checkpoints, snapshots are\n * rebuildable derived data, so `maxEntries` may evict the least recently used\n * entry and `ttlMs` may expire it safely. A load updates LRU recency but does\n * not extend TTL; only another save does.\n */\nexport class InMemorySnapshotStore<TState = unknown>\n\timplements SnapshotStore<TState>\n{\n\tprivate readonly snapshots = new Map<string, StoredSnapshot<TState>>();\n\tprivate readonly maxEntries: number | undefined;\n\tprivate readonly ttlMs: number | undefined;\n\tprivate readonly clock: () => Date;\n\n\tconstructor(options: InMemorySnapshotStoreOptions = {}) {\n\t\tif (options.maxEntries !== undefined) {\n\t\t\tassertPositiveSafeInteger(\n\t\t\t\t\"InMemorySnapshotStore\",\n\t\t\t\t\"maxEntries\",\n\t\t\t\toptions.maxEntries,\n\t\t\t);\n\t\t}\n\t\tif (options.ttlMs !== undefined) {\n\t\t\tassertPositiveSafeInteger(\n\t\t\t\t\"InMemorySnapshotStore\",\n\t\t\t\t\"ttlMs\",\n\t\t\t\toptions.ttlMs,\n\t\t\t);\n\t\t}\n\t\tthis.maxEntries = options.maxEntries;\n\t\tthis.ttlMs = options.ttlMs;\n\t\tthis.clock = options.clock ?? (() => new Date());\n\t}\n\n\tasync load(\n\t\taddress: AggregateAddress,\n\t): Promise<AggregateSnapshot<TState> | undefined> {\n\t\tconst key = encodeAggregateAddress(address);\n\t\tconst stored = this.snapshots.get(key);\n\t\tif (stored === undefined) return undefined;\n\t\tif (\n\t\t\tstored.expiresAtMs !== undefined &&\n\t\t\tthis.readClock() >= stored.expiresAtMs\n\t\t) {\n\t\t\tthis.snapshots.delete(key);\n\t\t\treturn undefined;\n\t\t}\n\t\t// Map order is the LRU order. A read makes this entry most recent but\n\t\t// deliberately preserves its original expiry.\n\t\tthis.snapshots.delete(key);\n\t\tthis.snapshots.set(key, stored);\n\t\treturn structuredClone(stored.snapshot);\n\t}\n\n\tasync save(\n\t\taddress: AggregateAddress,\n\t\tsnapshot: AggregateSnapshot<TState>,\n\t): Promise<void> {\n\t\t// Clone before changing retention state: an unsupported snapshot value\n\t\t// must not evict a valid entry.\n\t\tconst ownedSnapshot = structuredClone(snapshot);\n\t\tconst key = encodeAggregateAddress(address);\n\t\tlet expiresAtMs: number | undefined;\n\t\tif (this.ttlMs !== undefined) {\n\t\t\tconst nowMs = this.readClock();\n\t\t\tthis.deleteExpired(nowMs);\n\t\t\texpiresAtMs = nowMs + this.ttlMs;\n\t\t}\n\t\tif (this.snapshots.has(key)) {\n\t\t\tthis.snapshots.delete(key);\n\t\t} else if (\n\t\t\tthis.maxEntries !== undefined &&\n\t\t\tthis.snapshots.size >= this.maxEntries\n\t\t) {\n\t\t\tconst oldest = this.snapshots.keys().next();\n\t\t\tif (!oldest.done) this.snapshots.delete(oldest.value);\n\t\t}\n\t\tthis.snapshots.set(key, { snapshot: ownedSnapshot, expiresAtMs });\n\t}\n\n\tasync delete(address: AggregateAddress): Promise<void> {\n\t\tthis.snapshots.delete(encodeAggregateAddress(address));\n\t}\n\n\tprivate readClock(): number {\n\t\tconst now = this.clock();\n\t\tif (!(now instanceof Date) || !Number.isFinite(now.getTime())) {\n\t\t\tthrow new TypeError(\n\t\t\t\t\"InMemorySnapshotStore: clock must return a valid Date\",\n\t\t\t);\n\t\t}\n\t\treturn now.getTime();\n\t}\n\n\tprivate deleteExpired(nowMs: number): void {\n\t\tfor (const [key, stored] of this.snapshots) {\n\t\t\tif (stored.expiresAtMs !== undefined && nowMs >= stored.expiresAtMs) {\n\t\t\t\tthis.snapshots.delete(key);\n\t\t\t}\n\t\t}\n\t}\n}\n","import { someChainRetryable } from \"@shirudo/base-error\";\nimport { abortReason } from \"../utils/abort\";\nimport { computeBackoffDelay, neutralJitterSource } from \"../utils/backoff\";\nimport { reportToObserver } from \"../utils/observer\";\nimport { sleepRejectingOnAbort } from \"../utils/sleep\";\nimport {\n\tassertNonNegativeFinite,\n\tassertPositiveInteger,\n} from \"../utils/validate\";\nimport type { TransactionalOptions, TransactionScope } from \"./scope\";\n\n/**\n * Tuning for {@link RetryingTransactionScope}. All fields are optional;\n * the defaults suit optimistic-concurrency retries (a handful of writers\n * racing one aggregate), not high-fan-out hot-row contention.\n */\nexport interface RetryPolicy {\n\t/** Total tries, including the first. Default `3` (1 initial + 2 retries). */\n\tmaxAttempts?: number;\n\t/** First backoff delay; doubles each retry. Default `50`ms. */\n\tbaseDelayMs?: number;\n\t/** Ceiling for the backoff delay. Default `1000`ms. */\n\tmaxDelayMs?: number;\n\t/**\n\t * Classifier deciding whether an error is worth retrying. Default\n\t * {@link someChainRetryable} (walks the cause chain for the loose\n\t * `retryable === true` marker, so `ConcurrencyConflictError` matches\n\t * even when an adapter wraps it). Override to add driver-specific\n\t * serialization codes (Postgres 40001, MySQL 1213, SQLite SQLITE_BUSY)\n\t * that your adapter has not mapped to a retryable kit error.\n\t *\n\t * Guarded like `onRetry`: a THROWING classifier counts as \"not\n\t * retryable\" and the transaction's ORIGINAL error surfaces, never the\n\t * classifier's own failure.\n\t */\n\tisRetryable?: (error: unknown) => boolean;\n\t/**\n\t * Observer fired before each backoff wait (logging / metrics).\n\t * Neutralised like the `withCommit` observers: a synchronous throw or\n\t * an async rejection is swallowed, so a buggy observer can neither\n\t * abort the retry loop nor mask the original retryable error.\n\t */\n\tonRetry?: (info: {\n\t\tattempt: number;\n\t\terror: unknown;\n\t\tdelayMs: number;\n\t}) => void;\n\t/** Backoff wait. Default an abortable `setTimeout`. Injectable for tests. */\n\tsleep?: (ms: number, signal?: AbortSignal) => Promise<void>;\n\t/** Jitter source in `[0, 1)`. Default `Math.random`. Injectable for tests. */\n\trandom?: () => number;\n}\n\nconst DEFAULT_MAX_ATTEMPTS = 3;\nconst DEFAULT_BASE_DELAY_MS = 50;\nconst DEFAULT_MAX_DELAY_MS = 1000;\n\nconst ABORT_MESSAGE = \"RetryingTransactionScope aborted\";\n\n/** Abortable `setTimeout`; rejects with the signal reason if aborted. */\nfunction defaultSleep(ms: number, signal?: AbortSignal): Promise<void> {\n\treturn sleepRejectingOnAbort(ms, signal, ABORT_MESSAGE);\n}\n\n/**\n * A {@link TransactionScope} that retries its inner scope on transient\n * failures with exponential backoff and jitter. Compose it transparently:\n *\n * ```ts\n * const scope = new RetryingTransactionScope(drizzleScope, { maxAttempts: 5 });\n * const uow = new UnitOfWork({ scope, outbox, repositories });\n * ```\n *\n * **Retries the transaction only.** Each attempt re-invokes the inner\n * `transactional` with a fresh transaction, so the work callback must be\n * reload-safe (load aggregates via `findById` inside it, never capture an\n * aggregate from a previous attempt) and free of non-transactional side\n * effects before commit. `withCommit` publishes AFTER the commit, so the\n * in-process publish is outside the retried region and never duplicated;\n * publish failures are handled by `onPublishError`, not retried here.\n *\n * **Classification is by error, not by guesswork.** Only errors the\n * `isRetryable` predicate accepts are retried; everything else (a\n * `DomainError`, `EventHarvestError`, `UnenrolledChangesError`,\n * `DuplicateAggregateError`, a non-Error throw) surfaces immediately.\n * After `maxAttempts` the last error is rethrown unchanged, so a caller\n * can still match `ConcurrencyConflictError` and map it to HTTP 409.\n *\n * **Cancellation.** The `AbortSignal` from `transactional` options is\n * checked before each attempt and aborts the backoff wait, so an\n * `AbortSignal.timeout(ms)` bounds total elapsed time (there is\n * deliberately no separate max-elapsed knob).\n */\nexport class RetryingTransactionScope<TCtx> implements TransactionScope<TCtx> {\n\t// Policy resolved and validated once at construction (a misconfigured\n\t// policy is a wiring bug and fails fast, never at run time).\n\tprivate readonly maxAttempts: number;\n\tprivate readonly baseDelayMs: number;\n\tprivate readonly maxDelayMs: number;\n\tprivate readonly isRetryable: (error: unknown) => boolean;\n\tprivate readonly sleep: (ms: number, signal?: AbortSignal) => Promise<void>;\n\tprivate readonly random: () => number;\n\tprivate readonly onRetry?: RetryPolicy[\"onRetry\"];\n\n\tconstructor(\n\t\tprivate readonly inner: TransactionScope<TCtx>,\n\t\tpolicy: RetryPolicy = {},\n\t) {\n\t\tthis.maxAttempts = policy.maxAttempts ?? DEFAULT_MAX_ATTEMPTS;\n\t\tthis.baseDelayMs = policy.baseDelayMs ?? DEFAULT_BASE_DELAY_MS;\n\t\tthis.maxDelayMs = policy.maxDelayMs ?? DEFAULT_MAX_DELAY_MS;\n\t\tassertPositiveInteger(\n\t\t\t\"RetryingTransactionScope\",\n\t\t\t\"maxAttempts\",\n\t\t\tthis.maxAttempts,\n\t\t);\n\t\tassertNonNegativeFinite(\n\t\t\t\"RetryingTransactionScope\",\n\t\t\t\"baseDelayMs\",\n\t\t\tthis.baseDelayMs,\n\t\t);\n\t\tassertNonNegativeFinite(\n\t\t\t\"RetryingTransactionScope\",\n\t\t\t\"maxDelayMs\",\n\t\t\tthis.maxDelayMs,\n\t\t);\n\t\tthis.isRetryable = policy.isRetryable ?? someChainRetryable;\n\t\tthis.sleep = policy.sleep ?? defaultSleep;\n\t\t// Wrapped like the poll loop's jitter: an injected source that throws\n\t\t// or returns a non-finite value must not replace the transaction's\n\t\t// original retryable error or eliminate the backoff.\n\t\tthis.random = neutralJitterSource(policy.random ?? Math.random);\n\t\tthis.onRetry = policy.onRetry;\n\t}\n\n\tasync transactional<T>(\n\t\tfn: (ctx: TCtx) => Promise<T>,\n\t\toptions?: TransactionalOptions,\n\t): Promise<T> {\n\t\tconst { maxAttempts, isRetryable, sleep } = this;\n\t\tconst signal = options?.signal;\n\t\tconst isRetryableSafe = (error: unknown): boolean => {\n\t\t\ttry {\n\t\t\t\treturn isRetryable(error);\n\t\t\t} catch {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t};\n\n\t\tfor (let attempt = 1; attempt <= maxAttempts; attempt++) {\n\t\t\tif (signal?.aborted) {\n\t\t\t\tthrow abortReason(signal, ABORT_MESSAGE);\n\t\t\t}\n\t\t\ttry {\n\t\t\t\treturn await this.inner.transactional(fn, options);\n\t\t\t} catch (error) {\n\t\t\t\t// Exhausted, or a failure retrying cannot fix: surface it\n\t\t\t\t// unchanged so the caller keeps the original error type.\n\t\t\t\t// The classifier itself is guarded like the onRetry observer\n\t\t\t\t// below: a throwing classifier (a custom predicate bug, or\n\t\t\t\t// the default someChainRetryable on a circular cause chain)\n\t\t\t\t// must not replace the transaction's failure, so its throw\n\t\t\t\t// counts as \"not retryable\" and the ORIGINAL error surfaces.\n\t\t\t\tif (attempt === maxAttempts || !isRetryableSafe(error)) {\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t\tconst delayMs = computeBackoffDelay(attempt, {\n\t\t\t\t\tbaseDelayMs: this.baseDelayMs,\n\t\t\t\t\tmaxDelayMs: this.maxDelayMs,\n\t\t\t\t\trandom: this.random,\n\t\t\t\t});\n\t\t\t\t// Observer only: a throwing or async-rejecting onRetry must\n\t\t\t\t// neither abort the retry loop nor mask the original error.\n\t\t\t\treportToObserver(() => this.onRetry?.({ attempt, error, delayMs }));\n\t\t\t\t// An abort during the wait rejects out of the loop with the\n\t\t\t\t// signal reason: cancellation wins over another attempt.\n\t\t\t\tawait sleep(delayMs, signal);\n\t\t\t}\n\t\t}\n\t\t// Unreachable: the loop either returns or throws on the last attempt.\n\t\tthrow new Error(\"RetryingTransactionScope: exhausted without result\");\n\t}\n}\n","import type { AggregateSnapshot, Version } from \"../aggregate/aggregate\";\nimport { SnapshotTimeValidationError } from \"../aggregate/domain-event-errors\";\nimport {\n\tisDomainErrorLike,\n\tSnapshotCorruptedError,\n\tSnapshotSchemaMismatchError,\n} from \"../core/errors\";\nimport type { Id } from \"../core/id\";\nimport { isBuiltInObject } from \"../utils/array/is-built-in\";\nimport { assertPositiveSafeInteger } from \"../utils/validate\";\n\ninterface SnapshotAggregate {\n\treadonly id: Id<string>;\n\treadonly version: Version;\n}\n\n/**\n * Adapter-owned mapping between an OO aggregate and its stored snapshot DTO.\n *\n * Snapshot shape, schema migration, envelope construction, and reconstitution\n * are persistence concerns. The aggregate remains responsible for producing a\n * valid domain object; it does not know when or how snapshots are stored.\n */\nexport interface SnapshotModel<\n\tTAggregate extends SnapshotAggregate,\n\tTSnapshotState,\n> {\n\t/** Stable type name used to address schema errors and snapshot storage. */\n\treadonly aggregateType: string;\n\n\t/** Current schema version of the stored snapshot DTO. */\n\treadonly schemaVersion: number;\n\n\t/** Projects the current aggregate into a persistence DTO. */\n\tcapture(aggregate: TAggregate): TSnapshotState;\n\n\t/**\n\t * Reconstitutes a fresh, valid aggregate without recording a new decision.\n\t * This is normally a call to a static aggregate factory.\n\t *\n\t * A snapshot persisted under yesterday's decision rules must keep loading\n\t * after a rule change (\"replay from zero equals snapshot plus tail\"), so\n\t * prefer a factory path that does not re-run current `validateState`\n\t * rules against the stored blob. When the factory does validate and\n\t * throws a `DomainError`, `reconstituteAggregateFromSnapshot` surfaces it\n\t * as a {@link SnapshotCorruptedError} so the documented load recipe can\n\t * discard the derived snapshot and refold from the stream; the load then\n\t * still succeeds, at the cost of a full replay on every hit.\n\t */\n\treconstitute(\n\t\tid: TAggregate[\"id\"],\n\t\tstate: TSnapshotState,\n\t\tversion: Version,\n\t): TAggregate;\n\n\t/** Upgrades an older stored DTO into the model's current DTO shape. */\n\treadonly migrate?: (\n\t\tstored: unknown,\n\t\tstoredSchemaVersion: number,\n\t) => TSnapshotState;\n}\n\n/** Type-inference helper for declaring an adapter-owned snapshot model. */\nexport function defineSnapshotModel<\n\tTAggregate extends SnapshotAggregate,\n\tTSnapshotState,\n>(\n\tmodel: SnapshotModel<TAggregate, TSnapshotState>,\n): SnapshotModel<TAggregate, TSnapshotState> {\n\t// Validated AFTER the spread, on what actually survives it: the spread\n\t// copies own enumerable properties only, so capture/reconstitute carried\n\t// on a prototype (class instance) vanish silently and would surface much\n\t// later as a raw TypeError outside the corruption channel.\n\tconst detached = Object.freeze({ ...model });\n\tassertSnapshotModel(detached);\n\treturn detached;\n}\n\n/**\n * Captures a detached persistence envelope at an application-supplied time.\n * The application decides when snapshotting is worthwhile; this function does\n * not read a clock or perform I/O.\n */\nexport function captureAggregateSnapshot<\n\tTAggregate extends SnapshotAggregate,\n\tTSnapshotState,\n>(\n\tmodel: SnapshotModel<TAggregate, TSnapshotState>,\n\taggregate: TAggregate,\n\tsnapshotAt: Date,\n): AggregateSnapshot<TSnapshotState> {\n\tassertSnapshotModel(model);\n\tconst recordedAt = copySnapshotAt(snapshotAt);\n\tconst state = detachSnapshotState(model.capture(aggregate));\n\treturn Object.freeze({\n\t\tstate,\n\t\tversion: aggregate.version,\n\t\tsnapshotAt: recordedAt,\n\t\tschemaVersion: model.schemaVersion,\n\t});\n}\n\n/**\n * Reconstitutes a fresh aggregate from a stored snapshot through the owning\n * adapter model. A missing schema version denotes the original schema `1`.\n *\n * A `DomainError` thrown while interpreting the stored blob (the model's\n * `migrate`, or current `validateState` rules running inside the model's\n * reconstitution factory) is surfaced as a {@link SnapshotCorruptedError}:\n * a snapshot is DERIVED data, so the caller's discard-and-refold branch must\n * see one catchable corruption channel instead of a raw domain rejection\n * escaping `getById` after a rule change. `SnapshotSchemaMismatchError`\n * (a configuration gap, not corruption) and non-domain throws propagate.\n */\nexport function reconstituteAggregateFromSnapshot<\n\tTAggregate extends SnapshotAggregate,\n\tTSnapshotState,\n>(\n\tmodel: SnapshotModel<TAggregate, TSnapshotState>,\n\tid: TAggregate[\"id\"],\n\tsnapshot: AggregateSnapshot<unknown>,\n): TAggregate {\n\tassertSnapshotModel(model);\n\tconst storedSchemaVersion = snapshot.schemaVersion ?? 1;\n\tlet aggregate: TAggregate;\n\ttry {\n\t\tlet state: TSnapshotState;\n\t\tif (storedSchemaVersion === model.schemaVersion) {\n\t\t\tstate = detachSnapshotState(snapshot.state) as TSnapshotState;\n\t\t} else if (model.migrate) {\n\t\t\tstate = detachSnapshotState(\n\t\t\t\tmodel.migrate(detachSnapshotState(snapshot.state), storedSchemaVersion),\n\t\t\t);\n\t\t} else {\n\t\t\tthrow new SnapshotSchemaMismatchError({\n\t\t\t\taggregateType: model.aggregateType,\n\t\t\t\taggregateId: String(id),\n\t\t\t\texpectedSchemaVersion: model.schemaVersion,\n\t\t\t\tactualSchemaVersion: storedSchemaVersion,\n\t\t\t});\n\t\t}\n\t\taggregate = model.reconstitute(id, state, snapshot.version);\n\t} catch (error) {\n\t\t// Copy-safe: the model factory may run in another loaded copy of the\n\t\t// kit (adapter package, dual CJS/ESM load), whose DomainError fails a\n\t\t// plain instanceof; the corruption channel must catch it regardless.\n\t\tif (isDomainErrorLike(error)) {\n\t\t\tthrow new SnapshotCorruptedError(\n\t\t\t\t`Snapshot of ${model.aggregateType} ${String(id)} (schema ` +\n\t\t\t\t\t`${storedSchemaVersion}, version ${String(snapshot.version)}) was ` +\n\t\t\t\t\t\"rejected during reconstitution. Discard the derived snapshot and \" +\n\t\t\t\t\t\"refold from the stream.\",\n\t\t\t\terror,\n\t\t\t);\n\t\t}\n\t\tthrow error;\n\t}\n\t// Post-condition, not corruption: a factory that ignores the version\n\t// parameter (a forgotten markRestored) is a deterministic model wiring\n\t// bug. Routing it into the discard-and-refold channel would mask it as\n\t// perpetual silent refolding, so it throws raw instead.\n\tif (aggregate.version !== snapshot.version) {\n\t\tthrow new TypeError(\n\t\t\t`SnapshotModel.reconstitute for ${model.aggregateType} ${String(id)} ` +\n\t\t\t\t`returned an aggregate at version ${String(aggregate.version)} for a ` +\n\t\t\t\t`snapshot at version ${String(snapshot.version)}. Reconstitution must ` +\n\t\t\t\t\"restore the persisted version; call markRestored(version) inside \" +\n\t\t\t\t\"the aggregate factory.\",\n\t\t);\n\t}\n\treturn aggregate;\n}\n\nfunction assertSnapshotModel(model: {\n\treadonly aggregateType: string;\n\treadonly schemaVersion: number;\n\treadonly capture: unknown;\n\treadonly reconstitute: unknown;\n\treadonly migrate?: unknown;\n}): void {\n\tif (\n\t\ttypeof model.aggregateType !== \"string\" ||\n\t\tmodel.aggregateType.trim().length === 0\n\t) {\n\t\tthrow new TypeError(\n\t\t\t\"SnapshotModel.aggregateType must be a non-empty string\",\n\t\t);\n\t}\n\tassertPositiveSafeInteger(\"SnapshotModel\", \"schemaVersion\", model.schemaVersion);\n\tfor (const key of [\"capture\", \"reconstitute\"] as const) {\n\t\tif (typeof model[key] !== \"function\") {\n\t\t\tthrow new TypeError(\n\t\t\t\t`SnapshotModel.${key} is missing or not a function. ` +\n\t\t\t\t\t\"defineSnapshotModel copies own enumerable properties only; \" +\n\t\t\t\t\t\"prototype methods are not carried. Pass a plain object literal.\",\n\t\t\t);\n\t\t}\n\t}\n\tif (model.migrate !== undefined && typeof model.migrate !== \"function\") {\n\t\tthrow new TypeError(\"SnapshotModel.migrate must be a function when set\");\n\t}\n}\n\nfunction copySnapshotAt(snapshotAt: Date): Date {\n\tif (!(snapshotAt instanceof Date) || !Number.isFinite(snapshotAt.getTime())) {\n\t\tthrow new SnapshotTimeValidationError();\n\t}\n\treturn new Date(snapshotAt.getTime());\n}\n\nfunction detachSnapshotState<T>(state: T): T {\n\tassertSnapshotSafe(state, \"\", new WeakSet());\n\treturn structuredClone(state);\n}\n\n/**\n * Rejects graphs that structured cloning would lose or silently degrade.\n * Snapshot models map class-based domain state to plain persistence DTOs.\n */\nfunction assertSnapshotSafe(\n\tvalue: unknown,\n\tpath: string,\n\tseen: WeakSet<object>,\n): void {\n\tif (typeof value === \"function\") {\n\t\tthrow new TypeError(\n\t\t\t`snapshot state${path} is a function; map it to serialisable data in the snapshot model`,\n\t\t);\n\t}\n\t// Guided rejection instead of the raw DataCloneError DOMException that\n\t// structuredClone throws for symbols, which no recovery channel catches.\n\tif (typeof value === \"symbol\") {\n\t\tthrow new TypeError(\n\t\t\t`snapshot state${path} is a symbol; map it to serialisable data in the snapshot model`,\n\t\t);\n\t}\n\tif (value === null || typeof value !== \"object\") return;\n\tconst object = value as object;\n\tif (seen.has(object)) return;\n\tseen.add(object);\n\n\tif (Array.isArray(object)) {\n\t\tfor (let index = 0; index < object.length; index++) {\n\t\t\tassertSnapshotSafe(object[index], `${path}[${index}]`, seen);\n\t\t}\n\t\treturn;\n\t}\n\n\tconst tag = Object.prototype.toString.call(object);\n\tif (isBuiltInObject(object, tag)) {\n\t\tif (tag === \"[object Map]\") {\n\t\t\tlet index = 0;\n\t\t\tfor (const [key, entry] of object as Map<unknown, unknown>) {\n\t\t\t\tassertSnapshotSafe(key, `${path}<map key #${index}>`, seen);\n\t\t\t\tassertSnapshotSafe(entry, `${path}<map value #${index}>`, seen);\n\t\t\t\tindex++;\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tif (tag === \"[object Set]\") {\n\t\t\tlet index = 0;\n\t\t\tfor (const member of object as Set<unknown>) {\n\t\t\t\tassertSnapshotSafe(member, `${path}<set member #${index}>`, seen);\n\t\t\t\tindex++;\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tif (\n\t\t\ttag === \"[object Promise]\" ||\n\t\t\ttag === \"[object WeakMap]\" ||\n\t\t\ttag === \"[object WeakSet]\"\n\t\t) {\n\t\t\tthrow new TypeError(\n\t\t\t\t`snapshot state${path} is a ${tag.slice(8, -1)} and cannot be persisted`,\n\t\t\t);\n\t\t}\n\t\tif (tag === \"[object Error]\") {\n\t\t\tthrow new TypeError(\n\t\t\t\t`snapshot state${path} is an Error; map it to plain data in the snapshot model`,\n\t\t\t);\n\t\t}\n\t\treturn;\n\t}\n\n\tconst prototype = Object.getPrototypeOf(object);\n\tif (prototype === Object.prototype || prototype === null) {\n\t\tfor (const key of Reflect.ownKeys(object)) {\n\t\t\tconst descriptor = Object.getOwnPropertyDescriptor(object, key);\n\t\t\tif (!descriptor?.enumerable) continue;\n\t\t\tif (typeof key === \"symbol\") {\n\t\t\t\tthrow new TypeError(\n\t\t\t\t\t`snapshot state${path} has a symbol-keyed property; map it to plain data in the snapshot model`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tassertSnapshotSafe(\n\t\t\t\t(object as Record<PropertyKey, unknown>)[key],\n\t\t\t\t`${path}.${key}`,\n\t\t\t\tseen,\n\t\t\t);\n\t\t}\n\t\treturn;\n\t}\n\n\tconst name: string = prototype.constructor?.name || \"anonymous class\";\n\tthrow new TypeError(\n\t\t`snapshot state${path} is a class instance (${name}); map it to plain data in the snapshot model`,\n\t);\n}\n","/**\n * The composite structure of a combinator-built specification, exposed\n * for adapters that translate specifications into storage queries. An\n * adapter walks `composite` recursively down to the named leaves and\n * translates each one. This is deliberately not an expression tree:\n * predicates stay opaque functions, and only the boolean structure and\n * the leaf names are visible from outside.\n */\nexport type SpecificationComposite<T> =\n\t| {\n\t\t\treadonly operator: \"and\";\n\t\t\treadonly left: Specification<T>;\n\t\t\treadonly right: Specification<T>;\n\t }\n\t| {\n\t\t\treadonly operator: \"or\";\n\t\t\treadonly left: Specification<T>;\n\t\t\treadonly right: Specification<T>;\n\t }\n\t| { readonly operator: \"not\"; readonly inner: Specification<T> };\n\n/**\n * Specification: a named, executable domain criterion (Evans/Fowler).\n * \"Which candidates qualify?\" becomes an object in the ubiquitous\n * language instead of an inline predicate or a leaked query builder:\n * `overdueInvoices.and(highValue.not())` reads like the business rule\n * it encodes, evaluates in memory via {@link isSatisfiedBy}, and can be\n * translated by a repository adapter into its storage's query language.\n *\n * The same object serves three places. Domain logic calls\n * `spec.isSatisfiedBy(candidate)` directly. An in-memory repository or\n * test fake implements its lookup as a plain filter,\n * `rows.filter((r) => spec.isSatisfiedBy(r))`, with no translation\n * layer. And a storage adapter translates leaf specifications\n * explicitly (matching on {@link name}, or narrowing to the class for\n * parameterized leaves) while recursing through {@link composite} for\n * combinator nodes; the repository guide walks through it. The kit\n * ships this convention and deliberately no translation machinery:\n * no expression trees, no LINQ-style providers.\n *\n * The class is deliberately left open: the combinators can be\n * overridden and `composite` can be set by subclasses. That is what\n * makes a classic visitor/double-dispatch layer buildable on top,\n * for consumers who want the compiler to enforce translation\n * completeness across several targets; the repository guide's\n * \"A visitor layer on top\" section shows the full construction.\n *\n * Take the name from the ubiquitous language. It is what an adapter\n * matches on, what diagnostics print, and what ties the object back to\n * the rule as the domain expert stated it. If no expert would\n * recognize the name, what you have is a code predicate, not a\n * specification.\n *\n * Subclass for parameterized specifications, or use the\n * {@link specification} factory for flat ones:\n *\n * @example\n * ```typescript\n * class OverdueInvoice extends Specification<Invoice> {\n * readonly name = \"overdue invoice\";\n * constructor(private readonly today: Date) { super(); }\n * isSatisfiedBy(invoice: Invoice): boolean {\n * return invoice.dueDate < this.today && invoice.status === \"open\";\n * }\n * }\n *\n * const dunningCandidates = new OverdueInvoice(today)\n * .and(specification(\"in dunning grace period\", (i: Invoice) =>\n * i.remindersSent < 3,\n * ));\n * ```\n */\nexport abstract class Specification<T> {\n\t/**\n\t * The ubiquitous-language name of the criterion. Leaf names are what\n\t * adapters translate and diagnostics print; combinator nodes derive\n\t * theirs (`\"(a and b)\"`, `\"(not a)\"`).\n\t */\n\tabstract readonly name: string;\n\n\t/**\n\t * The composite structure for combinator-built specifications;\n\t * `undefined` on leaves. See {@link SpecificationComposite}.\n\t */\n\treadonly composite?: SpecificationComposite<T>;\n\n\t/** In-memory evaluation: does `candidate` meet the criterion? */\n\tabstract isSatisfiedBy(candidate: T): boolean;\n\n\t/** Both criteria must hold (short-circuits like `&&`). */\n\tand(other: Specification<T>): Specification<T> {\n\t\treturn new BinaryCompositeSpecification(\"and\", this, other);\n\t}\n\n\t/** Either criterion suffices (short-circuits like `||`). */\n\tor(other: Specification<T>): Specification<T> {\n\t\treturn new BinaryCompositeSpecification(\"or\", this, other);\n\t}\n\n\t/** The criterion must not hold. */\n\tnot(): Specification<T> {\n\t\treturn new NotSpecification(this);\n\t}\n\n\t/** The name, so diagnostics and test output read in domain language. */\n\ttoString(): string {\n\t\treturn this.name;\n\t}\n}\n\n/**\n * Builds a leaf specification from a name and a predicate: the\n * lightweight alternative to subclassing for criteria without\n * parameters worth a class of their own. The predicate must be pure\n * (no side effects, no mutation of the candidate): specifications are\n * evaluated freely and repeatedly, in tests, combinators, and\n * in-memory repositories.\n */\nexport function specification<T>(\n\tname: string,\n\tpredicate: (candidate: T) => boolean,\n): Specification<T> {\n\tif (name.trim().length === 0 || name !== name.trim()) {\n\t\tthrow new Error(\n\t\t\t\"specification: the name must be a non-empty ubiquitous-language term \" +\n\t\t\t\t\"without leading or trailing whitespace; adapters match it as an \" +\n\t\t\t\t\"exact string, and padding is invisible in every diagnostic\",\n\t\t);\n\t}\n\treturn new PredicateSpecification(name, predicate);\n}\n\nclass PredicateSpecification<T> extends Specification<T> {\n\tconstructor(\n\t\treadonly name: string,\n\t\tprivate readonly predicate: (candidate: T) => boolean,\n\t) {\n\t\tsuper();\n\t}\n\n\tisSatisfiedBy(candidate: T): boolean {\n\t\treturn this.predicate(candidate);\n\t}\n}\n\nclass BinaryCompositeSpecification<T> extends Specification<T> {\n\toverride readonly composite: {\n\t\treadonly operator: \"and\" | \"or\";\n\t\treadonly left: Specification<T>;\n\t\treadonly right: Specification<T>;\n\t};\n\tprivate cachedName?: string;\n\n\tconstructor(\n\t\toperator: \"and\" | \"or\",\n\t\tleft: Specification<T>,\n\t\tright: Specification<T>,\n\t) {\n\t\tsuper();\n\t\t// Frozen like every plain object the kit hands out: readonly is\n\t\t// compile-time only, and an adapter mutating the structure would\n\t\t// silently diverge from name and evaluation.\n\t\tthis.composite = Object.freeze({ operator, left, right });\n\t}\n\n\t// Lazy with a cache: deep chains would otherwise pay quadratic\n\t// string work at construction for names only diagnostics read.\n\tget name(): string {\n\t\tthis.cachedName ??= `(${this.composite.left.name} ${this.composite.operator} ${this.composite.right.name})`;\n\t\treturn this.cachedName;\n\t}\n\n\tisSatisfiedBy(candidate: T): boolean {\n\t\tconst { operator, left, right } = this.composite;\n\t\treturn operator === \"and\"\n\t\t\t? left.isSatisfiedBy(candidate) && right.isSatisfiedBy(candidate)\n\t\t\t: left.isSatisfiedBy(candidate) || right.isSatisfiedBy(candidate);\n\t}\n}\n\nclass NotSpecification<T> extends Specification<T> {\n\toverride readonly composite: {\n\t\treadonly operator: \"not\";\n\t\treadonly inner: Specification<T>;\n\t};\n\tprivate cachedName?: string;\n\n\tconstructor(inner: Specification<T>) {\n\t\tsuper();\n\t\tthis.composite = Object.freeze({ operator: \"not\", inner });\n\t}\n\n\tget name(): string {\n\t\tthis.cachedName ??= `(not ${this.composite.inner.name})`;\n\t\treturn this.cachedName;\n\t}\n\n\tisSatisfiedBy(candidate: T): boolean {\n\t\treturn !this.composite.inner.isSatisfiedBy(candidate);\n\t}\n}\n","import { ValidationError } from \"@shirudo/base-error\";\nimport { err, ok, type Result } from \"@shirudo/result\";\nimport { type VO, vo } from \"../value-object/value-object\";\n\n/**\n * Builds an immutable value object while collecting **all** validation\n * violations into a single {@link ValidationError}, instead of failing on the\n * first one. This is the Result-first, multi-error counterpart to\n * `voWithValidation` (which returns a single string message).\n *\n * The `validate` callback receives a fresh `ValidationError` to push field\n * issues onto (via `addIssue` / `addIssues`) and the raw input. When no issue\n * was recorded the input is frozen into a `VO<T>` and returned as `Ok`;\n * otherwise the populated `ValidationError` is returned as `Err`.\n *\n * `ValidationError` comes from `@shirudo/base-error`; import it from there to\n * narrow the `Err` branch, exactly as `Result` is imported from\n * `@shirudo/result`. At the HTTP boundary, `toProblemDetails` from\n * `@shirudo/ddd-kit/http` surfaces the issues as an RFC 9457 result.\n *\n * @example\n * ```ts\n * const result = voValidated(\n * { email, age },\n * (issues, m) => {\n * if (!isEmail(m.email))\n * issues.addIssue({ message: \"must be a valid email\", path: [\"email\"] });\n * if (m.age < 0)\n * issues.addIssue({ message: \"must not be negative\", path: [\"age\"] });\n * },\n * \"Registration is invalid\",\n * );\n * // result.isErr() → result.error.publicIssues() has both violations\n * ```\n */\nexport function voValidated<T>(\n\tt: T,\n\tvalidate: (issues: ValidationError, value: T) => void,\n\tmessage = \"Validation failed\",\n): Result<VO<T>, ValidationError> {\n\tconst issues = new ValidationError(message);\n\tvalidate(issues, t);\n\treturn issues.hasIssues() ? err(issues) : ok(vo(t));\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AA6GA,SAAgB,YACf,GACA,GACU;CACV,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE;AACzC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC6DA,IAAsB,SAAtB,MAEA;CACC,AAAgB;;;;;;;;;;;;;CAchB,IAAc,QAAgB;EAC7B,OAAO,KAAK;CACb;;;;;;;;CASA,AAAU;CAEV,AAAiB;CACjB,AAAiB;;;;;;;;;;;;;;;CAgBjB,AAAU,YACT,IACA,cACA,QACC;EACD,IAAI,OAAO,QAAQ,OAAO,QACzB,MAAM,IAAI,MAAM,uCAAuC;EAExD,KAAK,KAAK;EACV,KAAK,mBAAmB,QAAQ,mBAAmB,QAAQ,SAAS;EACpE,KAAK,gBAAgB,QAAQ,iBAAiB;EAM9C,KAAK,SAAS,kBACb,iBAAiB,YAAY,GAC7B,KAAK,gBACN;EACA,KAAK,cAAc,KAAK,MAAM;CAC/B;;;;;;;;;;CAWA,AAAU,YAAY,OAAuB;EAC5C,OAAO,kBAAkB,OAAO,KAAK,gBAAgB;CACtD;;;;;;;;;;;;;;;CAgBA,AAAU,SAAS,UAAwB;EAI1C,MAAM,OAAO,KAAK,YAAY,iBAAiB,QAAQ,CAAC;EACxD,KAAK,cAAc,IAAI;EACvB,KAAK,SAAS;CACf;AACD;AAEA,MAAM,0BAAmD,CAAC;AAK1D,SAAS,kBACR,OACA,MACS;CACT,OAAO,SAAS,SAAU,WAAW,KAAK,IAAe,cAAc,KAAK;AAC7E;;;;;;;;;;;;;;AAeA,SAAgB,cAAiB,OAAa;CAC7C,IAAI,UAAU,QAAQ,OAAO,UAAU,UACtC,OAAO,OAAO,OAAO,KAAK;CAE3B,OAAO;AACR;;;;;;;;;AAUA,SAAS,iBAAoB,OAAa;CACzC,IAAI,UAAU,QAAQ,OAAO,UAAU,UAAU,OAAO;CACxD,IAAI,MAAM,QAAQ,KAAK,GAAG;EACzB,2BAA2B,OAAO,cAAc;EAKhD,MAAM,OAAO,CAAC,GAAG,KAAK;EACtB,KAAK,MAAM,OAAO,QAAQ,QAAQ,KAAK,GAAG;GACzC,IAAI,QAAQ,YAAY,OAAO,OAAO,MAAM,GAAG,GAAG;GAElD,IAAI,CADe,OAAO,yBAAyB,OAAO,GAC5C,CAAC,EAAE,YAAY;GAC7B,OAAO,eAAe,MAAM,KAAK;IAChC,OAAQ,MAAuC;IAC/C,UAAU;IACV,YAAY;IACZ,cAAc;GACf,CAAC;EACF;EACA,OAAO;CACR;CACA,MAAM,QAAQ,OAAO,eAAe,KAAK;CACzC,IAAI,UAAU,OAAO,aAAa,UAAU,MAAM,OAAO;CACzD,2BAA2B,OAAO,cAAc;CAMhD,OACC,UAAU,OAAO,OAAO,OAAO,OAAO,OAAO,IAAI,GAAG,KAAK,IAAI,EAAE,GAAG,MAAM;AAE1E;;;;;;;;;;;;;;;;;;AAmBA,SAAgB,WACf,GACA,GACU;CACV,OAAO,EAAE,OAAO,EAAE;AACnB;;;;;;;;;;;;;;;;;;;;AAqBA,SAAgB,eAGd,UAA4B,IAAwB;CACrD,OAAO,SAAS,MAAM,WAAW,OAAO,OAAO,EAAE;AAClD;;;;;;;;;;;;;;;;;;AAmBA,SAAgB,YAGd,UAA4B,IAAkB;CAC/C,OAAO,SAAS,MAAM,WAAW,OAAO,OAAO,EAAE;AAClD;;;;;;;;;;;;;;;;;;;;;;AAuBA,SAAgB,iBAGd,UAA4B,IAA2B;CACxD,MAAM,WAAW,SAAS,QAAQ,WAAW,OAAO,OAAO,EAAE;CAC7D,OAAO,SAAS,WAAW,SAAS,SAAS,WAAW;AACzD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+BA,SAAgB,iBAIf,UACA,IACA,SACmB;CACnB,IAAI,UAAU;CACd,MAAM,SAAS,SAAS,KAAK,WAAW;EACvC,IAAI,OAAO,OAAO,IAAI,OAAO;EAC7B,MAAM,OAAO,QAAQ,MAAM;EAC3B,IAAI,SAAS,QAAQ,UAAU;EAC/B,OAAO;CACR,CAAC;CACD,OAAO,UAAU,SAAS;AAC3B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+BA,SAAgB,kBAGd,UAA4B,IAAS,aAAkC;CACxE,IAAI,UAAU;CACd,MAAM,SAAS,SAAS,KAAK,WAAW;EACvC,IAAI,OAAO,OAAO,IAAI,OAAO;EAC7B,IAAI,gBAAgB,QAAQ,UAAU;EACtC,OAAO;CACR,CAAC;CACD,OAAO,UAAU,SAAS;AAC3B;;;;;;;;;;;;;;;;;;AAmBA,SAAgB,UACf,UACQ;CACR,OAAO,SAAS,KAAK,WAAW,OAAO,EAAE;AAC1C;;;;;;;;;;;;;;;;;;AC5iBA,SAAgB,+BACf,KAC+B;CAC/B,MAAM,WAAW,OAAO,yBAAyB,YAAY,GAAG,CAAC,EAAE;CACnE,IAAI,oBAAoB,SACvB,OAAO;CAGR,MAAM,2BAAW,IAAI,QAA6B;CAClD,IAAI;EACH,OAAO,eAAe,YAAY,KAAK;GACtC,OAAO;GACP,YAAY;GACZ,UAAU;GACV,cAAc;EACf,CAAC;CACF,QAAQ,CAIR;CACA,OAAO;AACR;;;;ACMA,MAAMA,iBAAe,+BAJoB,OAAO,IAC/C,sDAI+B,CAChC;AAEA,SAAgB,wCACf,WACA,YACO;CACP,MAAM,SAAS,OAAO,OAAO,UAAU;CACvC,eAAa,IAAI,WAAW,MAAM;AACnC;AAEA,SAAgB,mCACf,WAC8C;CAC9C,OAAOA,eAAa,IAAI,SAAS;AAClC;;;;AC/BA,MAAMC,iBAAe,+BAJkB,OAAO,IAC7C,sDAI6B,CAC9B;AAEA,SAAgB,wCACf,WACA,YACO;CACP,eAAa,IAAI,WAAW,OAAO,OAAO,UAAU,CAAC;AACtD;AAEA,SAAgB,mCACf,WAC8C;CAC9C,OAAOA,eAAa,IAAI,SAAS;AAClC;;;;;;;;;;;;;;;;;;;;;;;;;;;ACOA,IAAsB,gBAAtB,cAKS,OAET;CAuBC,AAAQ,WAAoB;;;;;;;;CAS5B,AAAQ;CAER,AAAQ,iBAA+C,CAAC;CAExD,AAAU,YACT,IACA,cACA,QACC;EACD,MAAM,IAAI,cAAc,MAAM;EAC9B,wCAAwC,MAAM;GAC7C,cAAc,QAAQ,qBAAqB;IAC1C,KAAK,yBAAyB,QAAQ,gBAAgB;GACvD;GACA,uBAAuB,WAAW;IACjC,KAAK,kCAAkC,MAAM;GAC9C;GACA,wBAAwB,KAAK;GAC7B,yBAAyB,KAAK,eAAe;EAC9C,CAAC;EACD,wCAAwC,MAAM,EAC7C,SAAS,gBAAgB;GACxB,MAAM,UAAU,KAAK;GACrB,MAAM,eAAe,QAAQ;GAC7B,MAAM,WAAqB,QAAQ,KAAK,OAAO,UAAU;IACxD,MAAM,YAAY;IAClB,IAAI,cAAc,SAAS,GAAG,OAAO;IACrC,IAAI,CAAC,yBAAyB,SAAS,GACtC,MAAM,IAAI,mBACR,MAAoC,IACtC;IAED,OAAO,kBACN,WACA,YAAY,WAAW,KAAK,CAC7B;GACD,CAAC;GAKD,IACC,KAAK,mBAAmB,WACxB,KAAK,eAAe,WAAW,cAE/B,MAAM,IAAI,6BAA6B,OAAO,KAAK,EAAE,CAAC;GAKvD,MAAM,+BAAe,IAAI,IAAY;GACrC,KAAK,MAAM,SAAS,UAAU;IAC7B,MAAM,UAAW,MAAyB;IAC1C,IAAI,aAAa,IAAI,OAAO,GAC3B,MAAM,IAAI,sBAAsB,OAAO,KAAK,EAAE,GAAG,OAAO;IAEzD,aAAa,IAAI,OAAO;GACzB;GACA,KAAK,iBAAiB;GACtB,OAAO,OAAO,OAAO,SAAS,MAAM,CAAC;EACtC,EACD,CAAC;CACF;CAEA,AAAQ,yBACP,QACA,kBACO;EACP,KAAK,wBAAwB,MAAM;EAMnC,KAAK,oBAAqB,oBAAoB,KAAK;CACpD;;;;;;;CAQA,AAAQ,kCACP,QACO;EACP,KAAK,wBAAwB,MAAM;CACpC;CAEA,AAAQ,wBAAwB,QAAsC;EACrE,IACC,OAAO,SAAS,KAAK,eAAe,UACpC,OAAO,MAAM,OAAO,UAAU,UAAU,KAAK,eAAe,MAAM,GAElE,MAAM,IAAI,MACT,wEACD;EAED,KAAK,iBAAiB,KAAK,eAAe,MAAM,OAAO,MAAM;CAC9D;CAEA,IAAW,UAAmB;EAC7B,OAAO,KAAK;CACb;;;;;CAMA,IAAW,gBAA2D;EACrE,OAAO,OAAO,OAAO,KAAK,eAAe,MAAM,CAAC;CACjD;;;;;;CAOA,IAAc,oBAA4B;EACzC,OAAO,KAAK,eAAe;CAC5B;CAEA,AAAU,WAAW,SAAwB;EAC5C,KAAK,WAAW;CACjB;;;;;;CAOA,AAAU,cAAoB;EAC7B,KAAK,WAAY,KAAK,WAAW,CAAa;CAC/C;;;;;;;;;;;;;;;;;;;;;;;;;CA0BA,AAAU,aAAa,SAAwB;EAC9C,KAAK,WAAW,OAAO;EACvB,KAAK,oBAAoB;CAC1B;;;;;;;;;;;CAYA,AAAU,eAAe,OAAyC;EACjE,KAAK,kBAAkB,KAAK;EAC5B,KAAK,eAAe,KAAK,KAAK;CAC/B;;;;;;;;;;;CAYA,AAAU,kBAAkB,OAAyC;EACpE,IAAI,CAAC,cAAc,KAAK,KAAK,CAAC,yBAAyB,KAAK,GAC3D,MAAM,IAAI,mBACR,MAAqD,IACvD;CAEF;;;;;;;;;CAUA,AAAU,YACT,MACA,SACA,SAI8B;EAC9B,OAAO,6BAA6B,MAAM,SAAS;GAClD,GAAG;GACH,aAAa,KAAK;GAClB,eAAe,KAAK;EACrB,CAAC;CACF;AACD;;;;;;;;;;;;;;;;;;;AAoBA,SAAgB,qCAAqC,WAG5C;CACR,MAAM,UAAU,UAAU,cAAc;CACxC,IAAI,UAAU,GACb,MAAM,IAAI,2BACT,OAAO,UAAU,EAAE,GACnB,cAAc,QAAQ,yKAGvB;AAEF;;;;;;;;;;;;;ACpUA,IAAsB,gBAAtB,cAIU,cAAmC;;;;;;CAM5C,AAAU,OACT,UACA,SAE2C,CAAC,GACrC;EACP,MAAM,aAAoD,MAAM,QAC/D,MACD,IACG,SACA,CAAC,MAAoC;EACxC,KAAK,MAAM,SAAS,YAAY,KAAK,kBAAkB,KAAK;EAE5D,KAAK,SAAS,QAAQ;EACtB,KAAK,MAAM,SAAS,YAAY,KAAK,eAAe,KAAK;CAC1D;;CAGA,AAAmB,SAAS,UAAwB;EACnD,MAAM,SAAS,QAAQ;EACvB,KAAK,YAAY;CAClB;;;;;;;CAQA,AAAU,2BAA2B,UAAwB;EAC5D,MAAM,SAAS,QAAQ;CACxB;AACD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC+BA,IAAsB,wBAAtB,cAKS,cAET;;;;;;;;;;;;;;;CAeC,AAAU,cAAc,QAAgD,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;CA2BzE,AAAU,MACT,OACO;EAQP,MAAM,UAAU,KAAK,qBAAqB,KAAK;EAG/C,KAAK,cAAc,OAA2C;EAC9D,KAAK,SAAS,OAAO;EACrB,KAAK,eAAe,OAAO;EAC3B,KAAK,YAAY;CAClB;;;;;;;;;;CAWA,AAAQ,qBACP,OACmD;EAInD,KAAK,kBAAkB,KAAK;EAC5B,MAAM,EAAE,aAAa,kBAAkB;EACvC,MAAM,YAAY,gBAAgB,UAAa,gBAAgB,KAAK;EACpE,MAAM,cACL,kBAAkB,UAAa,kBAAkB,KAAK;EACvD,IAAI,aAAa,aAChB,MAAM,IAAI,uBACT,KAAK,IACL,KAAK,eACL,MAAM,MACN,aACA,aACD;EAED,IAAI,gBAAgB,UAAa,kBAAkB,QAClD,OAAO;EAOR,MAAM,OAAO;GACZ,GAAG;GACH,aAAa,KAAK;GAClB,eAAe,KAAK;EACrB;EAMA,OAL4D,cAC3D,KACD,IACG,iBAAiB,IAAI,IACrB,4BAA4B,IAAI;CAEpC;;;;;;;;;;;;;;;;;;;;;;;;;CA0BA,AAAQ,+BAA+B,OAAqB;EAC3D,MAAM,aACL,MAAM,gBAAgB,UAAa,MAAM,gBAAgB,KAAK;EAC/D,MAAM,eACL,MAAM,kBAAkB,UACxB,MAAM,kBAAkB,KAAK;EAC9B,IAAI,cAAc,cACjB,MAAM,IAAI,kBACT,KAAK,IACL,KAAK,eACL,MAAM,MACN,MAAM,aACN,MAAM,aACP;CAEF;CAEA,AAAQ,SAAS,OAAwD;EAKxE,MAAM,UAAU,OAAO,OAAO,KAAK,UAAU,MAAM,IAAI,IACnD,KAAK,SAAS,MAAM,QAIrB;EACH,IAAI,CAAC,SACJ,MAAM,IAAI,oBAAoB,MAAM,IAAI;EAGzC,MAAM,YAAY,QAAQ,KAAK,QAAQ,KAAK;EAG5C,KAAK,SAAS,KAAK,YAAY,SAAS;CACzC;;;;;;;;;;;;;;;;;;;;;;CAuBA,AAAO,gBACN,SAC4B;EAC5B,qCAAqC,IAAI;EAEzC,IAAI,QAAQ,WAAW,GAAG,OAAO,GAAG;EAEpC,MAAM,gBAAgB,KAAK;EAC3B,MAAM,eAAe,KAAK;EAC1B,KAAK,MAAM,SAAS,SACnB,IAAI;GACH,KAAK,+BAA+B,KAAK;GACzC,KAAK,SAAS,KAAK;EACpB,SAAS,GAAG;GACX,KAAK,SAAS;GACd,IAAI,aAAa,aAAa,OAAO,IAAI,CAAC;GAC1C,MAAM;EACP;EAED,KAAK,aAAc,eAAe,QAAQ,MAAkB;EAC5D,OAAO,GAAG;CACX;AAsBD;;;;;;;;;ACxRA,SAAgB,aACf,UACA,SACA,MACA,SACO;CACP,IAAI,SAAS,IAAI,IAAI,GACpB,MAAM,IAAI,kCAAkC;EAC3C;EACA,aAAa;CACd,CAAC;CAEF,SAAS,IAAI,MAAM,OAAO;AAC3B;;;;;;;AAQA,SAAgB,eACf,UACA,SACA,MACW;CACX,MAAM,UAAU,SAAS,IAAI,IAAI;CACjC,IAAI,CAAC,SACJ,MAAM,IAAI,yBAAyB;EAAE;EAAS,aAAa;CAAK,CAAC;CAElE,OAAO;AACR;;;;;;;;;AAUA,SAAgB,kBACf,OACA,kBACA,SACmB;CACnB,IACC,iBAAiB,4BACjB,iBAAiB,wBAEjB,MAAM;CAEP,IAAI,CAAC,kBAAkB,MAAM;CAE7B,IAAI;CACJ,IAAI;EACH,WAAW,iBAAiB,KAAK;CAClC,SAAS,aAAa;EACrB,MAAM,IAAI,uBAAuB;GAChC;GACA,cAAc;GACd;EACD,CAAC;CACF;CACA,IAAI,aAAa,QAAW,MAAM;CAElC,IAAI;CACJ,IAAI;EACH,MAAM,YAAqB;EAC3B,IACC,OAAO,cAAc,YACrB,cAAc,QACd,CAAC,OAAO,OAAO,WAAW,OAAO,GAEjC,MAAM,IAAI,UACT,qEACD;EAED,SAAU,UAAuC;CAClD,SAAS,aAAa;EACrB,MAAM,IAAI,uBAAuB;GAChC;GACA,cAAc;GACd;EACD,CAAC;CACF;CACA,OAAO,IAAI,MAAM;AAClB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACsBA,IAAa,aAAb,MAIA;CACC,AAAiB,2BAAW,IAAI,IAAqC;CACrE,AAAiB;CAEjB,YAAY,SAAgC;EAC3C,KAAK,mBAAmB,SAAS;CAClC;CAEA,SAGE,aAAgB,SAA8C;EAC/D,aAAa,KAAK,UAAU,WAAW,cAAc,QACpD,QAAQ,GAAQ,CACjB;CACD;CASA,MAAM,QAA8B,SAAmC;EAGtE,MAAM,UAAU,eAAe,KAAK,UAAU,WAAW,QAAQ,IAAI;EACrE,IAAI;GACH,OAAQ,MAAM,QAAQ,OAAO;EAC9B,SAAS,OAAO;GACf,OAAO,kBAAkB,OAAO,KAAK,kBAAkB,SAAS;EACjE;CACD;AACD;;;;;AC3LA,SAAgB,aAAa,OAAqC;CACjE,OAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAC3E;;;;;;AASA,SAAgB,gBACf,OACA,MACA,SACA,yBAAS,IAAI,QAAgB,GACA;CAC7B,IAAI,UAAU,MAAM;CACpB,QAAQ,OAAO,OAAf;EACC,KAAK;EACL,KAAK,WACJ;EACD,KAAK;GACJ,IAAI,CAAC,OAAO,SAAS,KAAK,GACzB,OAAO,QAAQ,MAAM,qCAAqC;GAI3D,IAAI,OAAO,GAAG,OAAO,EAAE,GACtB,OAAO,QAAQ,MAAM,oCAAoC;GAE1D;EACD,KAAK,UACJ;EACD,SACC,QAAQ,MAAM,iBAAiB,OAAO,MAAM,kBAAkB;CAChE;CAEA,IAAI,OAAO,IAAI,KAAK,GACnB,QAAQ,MAAM,qCAAqC;CAEpD,OAAO,IAAI,KAAK;CAChB,IAAI,MAAM,QAAQ,KAAK,GAAG;EACzB,KAAK,MAAM,OAAO,QAAQ,QAAQ,KAAK,GAAG;GACzC,IAAI,QAAQ,UAAU;GACtB,IAAI,OAAO,QAAQ,UAClB,QAAQ,MAAM,wDAAwD;GAEvE,MAAM,QAAQ,OAAO,GAAG;GACxB,IACC,CAAC,OAAO,UAAU,KAAK,KACvB,QAAQ,KACR,SAAS,MAAM,UACf,OAAO,KAAK,MAAM,KAElB,QACC,GAAG,KAAK,GAAG,OACX,iDACD;EAEF;EACA,KAAK,IAAI,QAAQ,GAAG,QAAQ,MAAM,QAAQ,SAAS,GAAG;GACrD,MAAM,aAAa,OAAO,yBAAyB,OAAO,KAAK;GAC/D,IAAI,eAAe,QAClB,QACC,GAAG,KAAK,GAAG,MAAM,IACjB,iDACD;GAED,IAAI,EAAE,WAAW,eAAe,CAAC,WAAW,YAC3C,QACC,GAAG,KAAK,GAAG,MAAM,IACjB,8DACD;GAED,gBAAgB,WAAW,OAAO,GAAG,KAAK,GAAG,MAAM,IAAI,SAAS,MAAM;EACvE;EACA,OAAO,OAAO,KAAK;EACnB;CACD;CAEA,MAAM,YAAY,OAAO,eAAe,KAAK;CAC7C,IAAI,cAAc,OAAO,aAAa,cAAc,MACnD,QACC,MACA,sHAED;CAED,KAAK,MAAM,OAAO,QAAQ,QAAQ,KAAK,GAAG;EACzC,IAAI,OAAO,QAAQ,UAClB,QAAQ,MAAM,kDAAkD;EAEjE,MAAM,aAAa,OAAO,yBAAyB,OAAO,GAAG;EAC7D,IAAI,eAAe,QAAW;EAC9B,MAAM,YAAY,GAAG,KAAK,GAAG;EAC7B,IAAI,QAAQ,aACX,QACC,WACA,mEACD;EAED,IAAI,EAAE,WAAW,eAAe,CAAC,WAAW,YAC3C,QACC,WACA,0DACD;EAED,gBAAgB,WAAW,OAAO,WAAW,SAAS,MAAM;CAC7D;CACA,OAAO,OAAO,KAAK;AACpB;;;;;;;;;;;;;;;;;;;;;ACCA,SAAgB,2BAIf,QACA,QACoB;CACpB,OAAO,EACN,KAAK,OAAO,WAAW;EACtB,MAAM,UAAU,OAAO,KAAK,cAC3B,gBAAgB,WAAW,MAAM,CAClC;EACA,MAAM,OAAO,IAAI,OAAO;CACzB,EACD;AACD;AAEA,SAAS,gBAIR,WACA,QACkC;CAClC,MAAM,SAAS,OAAO,UAAU,KAAK;CACrC,IAAI,CAAC,MAAM,QAAQ,MAAM,GACxB,MAAM,IAAI,UACT,gEACD;CAED,MAAM,WAAW,MAAM,KAAK,SAAS,SAAS,UAC7C,iBAAoB,UAAU,OAAO,SAAS,KAAK,CACpD;CACA,OAAO,WAAW;EACjB,QAAQ;GACP,SAAS,UAAU,MAAM;GACzB,QAAQ,EAAE,GAAG,UAAU,OAAO;GAC9B,UAAU,EAAE,GAAG,UAAU,SAAS;EACnC;EACA;CACD,CAAC;AACF;AAEA,SAAS,iBACR,OACA,SACA,OAC2B;CAC3B,IACC,YAAY,QACZ,OAAO,YAAY,YACnB,MAAM,QAAQ,OAAO,GAErB,MAAM,IAAI,UAAU,+CAA+C;CAEpE,MAAM,EACL,aACA,SAAS,eACT,eACA,gBACA,aACA,eACG;CACJ,eAAe,eAAe,WAAW;CACzC,IACC,kBAAkB,QAClB,OAAO,kBAAkB,YACzB,MAAM,QAAQ,aAAa,GAE3B,MAAM,IAAI,UAAU,0CAA0C;CAE/D,uBAAuB,aAAa;CACpC,uBAAuB,iBAAiB,aAAa;CACrD,uBAAuB,kBAAkB,cAAc;CACvD,mBAAmB,aAAa,UAAU;CAE1C,MAAM,UAAU,KAAK,MAAM,KAAK,UAAU,aAAa,CAAC;CACxD,OAAO,WAAW;EACjB,WAAW,GAAG,MAAM,QAAQ,WAAW;EACvC,YAAY,MAAM,WAAW,YAAY;EACzC;EACA;EACA,GAAI,kBAAkB,SAAY,CAAC,IAAI,EAAE,cAAc;EACvD,GAAI,mBAAmB,SAAY,CAAC,IAAI,EAAE,eAAe;EACzD,GAAI,gBAAgB,SAAY,CAAC,IAAI,EAAE,YAAY;EACnD,GAAI,eAAe,SAAY,CAAC,IAAI,EAAE,WAAW;EACjD,aAAa,MAAM;CACpB,CAAC;AACF;AAEA,SAAS,eACR,OACA,OAC0B;CAC1B,IAAI,OAAO,UAAU,YAAY,MAAM,KAAK,CAAC,CAAC,WAAW,GACxD,UAAQ,KAAK,SAAS,4BAA4B;AAEpD;AAEA,SAAS,uBAAuB,OAAe,OAAsB;CACpE,IAAI,UAAU,QAAW,eAAe,OAAO,KAAK;AACrD;AAEA,SAAS,uBACR,OACoC;CACpC,gBAAgB,OAAO,aAAaC,SAAO;CAC3C,IAAI,CAAC,aAAa,KAAK,GACtB,UAAQ,aAAa,6BAA6B;CAEnD,KAAK,MAAM,OAAO,OAAO,KAAK,KAAK,GAClC,IAAI,QAAQ,UAAU,QAAQ,aAAa,QAAQ,WAClD,UACC,aAAa,OACb,6CACD;CAGF,eAAe,gBAAgB,MAAM,IAAI;CACzC,IACC,OAAO,MAAM,YAAY,YACzB,CAAC,OAAO,UAAU,MAAM,OAAO,KAC/B,MAAM,UAAU,GAEhB,UAAQ,qBAAqB,yBAAyB;CAEvD,IAAI,CAAC,OAAO,OAAO,OAAO,SAAS,GAClC,UAAQ,qBAAqB,6CAA6C;AAE5E;AAEA,MAAM,cACL;AACD,MAAM,oBACL;AAED,SAAS,mBAAmB,aAAsB,YAA2B;CAC5E,IAAI,gBAAgB,QAAW;EAC9B,IAAI,eAAe,QAClB,UAAQ,gBAAgB,sBAAsB;EAE/C;CACD;CACA,IAAI,OAAO,gBAAgB,UAC1B,UAAQ,iBAAiB,kCAAkC;CAE5D,MAAM,QAAQ,YAAY,KAAK,WAAW;CAC1C,MAAM,UAAU,QAAQ;CACxB,MAAM,YAAY,QAAQ,MAAM;CAChC,IACC,UAAU,QACV,YAAY,QACZ,OAAO,KAAK,MAAM,MAAM,EAAE,KAC1B,OAAO,KAAK,MAAM,MAAM,EAAE,KACzB,YAAY,QAAQ,UAAU,SAAS,KACvC,YAAY,QACZ,UAAU,SAAS,MAClB,CAAC,UAAU,WAAW,GAAG,KAAK,UAAU,WAAW,IAErD,UACC,iBACA,wDACD;CAED,IAAI,eAAe,QAAW;CAC9B,IAAI,OAAO,eAAe,YAAY,WAAW,SAAS,KACzD,UACC,gBACA,kDACD;CAKD,MAAM,UAAU,WACd,MAAM,GAAG,CAAC,CACV,KAAK,WAAW,OAAO,KAAK,CAAC,CAAC,CAC9B,QAAQ,WAAW,OAAO,SAAS,CAAC;CACtC,IAAI,QAAQ,WAAW,GAAG;CAC1B,MAAM,uBAAO,IAAI,IAAY;CAC7B,IACC,QAAQ,SAAS,MACjB,QAAQ,MAAM,WAAW;EAExB,MAAM,MADc,kBAAkB,KAAK,MACrB,CAAC,GAAG;EAC1B,IAAI,QAAQ,UAAa,KAAK,IAAI,GAAG,GAAG,OAAO;EAC/C,KAAK,IAAI,GAAG;EACZ,OAAO;CACR,CAAC,GAED,UACC,gBACA,gEACD;AAEF;AAEA,SAASA,UAAQ,MAAc,QAAuB;CACrD,MAAM,IAAI,2BAA2B,MAAM,MAAM;AAClD;;;;;;;;;;;;;;;AC9SA,eAAsB,oBAIrB,WACA,gBACkD;CAClD,MAAM,uBAAuB,CAAC,GAAG,cAAc;CAC/C,2BAA2B,oBAAoB;CAE/C,IAAI;EACH,OAAO,GAAG,MAAM,UAAU,CAAC;CAC5B,SAAS,OAAO;EACf,KAAK,MAAM,cAAc,sBACxB,KACG,OAAO,UAAU,YAAY,UAAU,QACxC,OAAO,UAAU,eAClB,OAAO,UAAU,cAAc,KAAK,WAAW,WAAW,KAAK,GAE/D,OAAO,IAAI,KAAoC;EAGjD,MAAM;CACP;AACD;AAEA,SAAS,2BACR,cAC6E;CAC7E,IAAI,aAAa,WAAW,GAC3B,MAAM,IAAI,UACT,sEACD;CAED,KAAK,MAAM,cAAc,cACxB,IACC,OAAO,eAAe,cACtB,CAAC,OAAO,UAAU,cAAc,KAC/B,YAAY,WACZ,WAAW,SACZ,GAEA,MAAM,IAAI,UACT,gFACD;AAGH;;;;;;;;;;;;;;;;;;ACvDA,SAAgB,YACf,QACA,iBACU;CACV,OAAO,OAAO,UAAU,IAAI,MAAM,eAAe;AAClD;;;;;;;;;;ACZA,SAAgB,wBACf,SACA,OACA,OACO;CACP,IAAI,CAAC,OAAO,SAAS,KAAK,KAAK,QAAQ,GACtC,MAAM,IAAI,MACT,GAAG,QAAQ,IAAI,MAAM,6CAA6C,OACnE;AAEF;;AAGA,SAAgB,sBACf,SACA,OACA,OACO;CACP,IAAI,CAAC,OAAO,UAAU,KAAK,KAAK,QAAQ,GACvC,MAAM,IAAI,MACT,GAAG,QAAQ,IAAI,MAAM,gCAAgC,OACtD;AAEF;;AAGA,SAAgB,0BACf,SACA,OACA,OACO;CACP,IAAI,CAAC,OAAO,cAAc,KAAK,KAAK,QAAQ,GAC3C,MAAM,IAAI,WACT,GAAG,QAAQ,IAAI,MAAM,wCAAwC,OAC9D;AAEF;;;;;ACdA,MAAa,+BAA+B;;;;;;;;;;;;AAa5C,SAAgB,oBACf,OACA,SACA,WACa;CACb,IAAI,QAAQ,eAAe,QAC1B,wBAAwB,OAAO,aAAa,QAAQ,SAAS;MAE7D,wBAAwB,OAAO,cAAc,QAAQ,UAAU;CAEhE,MAAM,YAAY,KAAK,IAAI;CAC3B,MAAM,aAAa,QAAQ,cAAc,YAAY,QAAQ;CAC7D,MAAM,YAAY,KAAK,IAAI,GAAG,aAAa,SAAS;CACpD,MAAM,qBACL,IAAI,aAAa,GAAG,MAAM,mBAAmB,UAAU,KAAK,cAAc;CAC3E,MAAM,aAAa,IAAI,gBAAgB;CACvC,MAAM,UAAU,OAAO,OAAO;EAC7B,QAAQ,WAAW;EACnB;CACD,CAAC;CACD,MAAM,cAAc,QAAQ;CAC5B,MAAM,uBAA6B;EAClC,WAAW,MACV,gBAAgB,yBACb,IAAI,MAAM,GAAG,MAAM,SAAS,IAC5B,YAAY,aAAa,GAAG,MAAM,SAAS,CAC/C;CACD;CAEA,IAAI,aAAa,SAAS,eAAe;MACpC,aAAa,iBAAiB,SAAS,gBAAgB,EAAE,MAAM,KAAK,CAAC;CAC1E,IACC,CAAC,WAAW,OAAO,WACnB,QAAQ,eAAe,UACvB,cAAc,WAEd,WAAW,MAAM,aAAa,CAAC;CAGhC,MAAM,QAAQ,iBAAiB;EAC9B,WAAW,MAAM,aAAa,CAAC;CAChC,GAAG,SAAS;CAEZ,OAAO,IAAI,SAAY,SAAS,WAAW;EAC1C,IAAI,UAAU;EACd,MAAM,UAAU,aAA+B;GAC9C,IAAI,SAAS;GACb,UAAU;GACV,aAAa,KAAK;GAClB,aAAa,oBAAoB,SAAS,cAAc;GACxD,WAAW,OAAO,oBAAoB,SAAS,OAAO;GACtD,SAAS;EACV;EACA,MAAM,gBAAsB;GAI3B,qBACC,aACC,OAAO,YAAY,WAAW,QAAQ,GAAG,MAAM,SAAS,CAAC,CAC1D,CACD;EACD;EAEA,IAAI,WAAW,OAAO,SAAS;GAC9B,QAAQ;GACR;EACD;EACA,WAAW,OAAO,iBAAiB,SAAS,SAAS,EAAE,MAAM,KAAK,CAAC;EACnE,IAAI;EACJ,IAAI;GACH,UAAU,QAAQ,QAAQ,UAAU,OAAO,CAAC;EAC7C,SAAS,OAAO;GACf,aAAa,OAAO,KAAK,CAAC;GAC1B;EACD;EACA,QAAQ,MACN,UAAU,aAAa,QAAQ,KAAK,CAAC,IACrC,UAAU,aAAa,OAAO,KAAK,CAAC,CACtC;CACD,CAAC;AACF;;;;;;;;;;;;;;;;;;AC7GA,SAAgB,iBAAiB,QAA0B;CAC1D,IAAI;CACJ,IAAI;EACH,SAAS,OAAO;CACjB,QAAQ;EACP;CACD;CACA,IACC,WAAW,QACX,OAAO,WAAW,YAClB,OAAQ,OAA8B,SAAS,YAE/C,AAAC,OAA4B,KAAK,cAAiB,CAAC,CAAC;AAEvD;;AAGA,SAAgB,yBAGd,SAAiB,WAAc,UAA8C;CAC9E,IAAI,cAAc,QAAQ,OAAO,cAAc,UAC9C,MAAM,IAAI,UACT,GAAG,QAAQ,0BAA0B,SAAS,KAAK,IAAI,GACxD;CAED,MAAM,WAAqC,CAAC;CAC5C,KAAK,MAAM,QAAQ,UAAU;EAC5B,MAAM,WAAY,UAAsC;EACxD,IAAI,OAAO,aAAa,YACvB,MAAM,IAAI,UAAU,GAAG,QAAQ,aAAa,KAAK,oBAAoB;EAEtE,SAAS,QAAQ;CAClB;CACA,OAAO,OAAO,OAAO,QAAQ;AAC9B;;;;;;;;;;ACoIA,SAAS,mBACR,QACU;CACV,MAAM,UAAU,OAAO,UAAU;CACjC,OACC,OAAO,UAAU,YAAY,OAAO,WACpC,QAAQ,WAAW,OAAO,OAAO,UACjC,OAAO,OAAO,MAAM,OAAO,UAAU,UAAU,QAAQ,MAAM;AAE/D;;AASA,SAAS,yBAEkB;CAC1B,MAAM,iCAAiB,IAAI,QAA4C;CACvE,MAAM,oCAAoB,IAAI,QAG5B;CACF,IAAI,mBAAmB;CACvB,IAAI,OAAO;CAEX,MAAM,UACL,WACA,aACA,YAC+B;EAC/B,IAAI,CAAC,MACJ,MAAM,IAAI,kBACT,wJAGD;EAGD,MAAM,WAAW,kBAAkB,IAAI,SAAS;EAChD,IAAI,UAAU;GACb,MAAM,SAAS,eAAe,IAAI,QAAQ;GAC1C,IAAI,CAAC,QACJ,MAAM,IAAI,kBACT,6DACD;GAED,IAAI,OAAO,gBAAgB,aAAa,gBAAgB,SACvD,MAAM,IAAI,kBACT,yBAAyB,OAAO,UAAU,EAAE,EAAE,iFAE/C;GAKD,IACC,SAAS,oBAAoB,UAC7B,QAAQ,oBAAoB,OAAO,iBAEnC,MAAM,IAAI,kBACT,yBAAyB,OAAO,UAAU,EAAE,EAAE,wCACrB,OAAO,QAAQ,eAAe,EAAE,gCACjC,OAAO,OAAO,eAAe,EAAE,kEAExD;GAED,IAAI,mBAAmB,MAAM,GAC5B,MAAM,IAAI,kBACT,yBAAyB,OAAO,UAAU,EAAE,EAAE,gFAE/C;GAMD,IAAI,gBAAgB,WACnB,OAAO,cAAc;GAEtB,OAAO;EACR;EAEA,MAAM,iBAAiB,mCAAmC,SAAS;EACnE,IAAI,CAAC,gBACJ,MAAM,IAAI,kBACT,yBAAyB,OAAO,UAAU,EAAE,EAAE,mLAI/C;EAGD,MAAM,QAAQ,OAAO,OACpB,OAAO,OAAO,IAAI,CACnB;EAGA,MAAM,SAAS,UAAU;EAMzB,KAAK,MAAM,SAAS,QACnB,IAAI,CAAC,cAAc,KAAK,GACvB,MAAM,IAAI,kBACT,sBAAuB,MAAoC,KAAK,2IAI/D,MAAoC,IACtC;EAQF,MAAM,mBAAmB,eAAe,iBAAiB;EAGzD,kBAAkB,IAAI,WAAW,KAAK;EACtC,eAAe,IAAI,OAAO;GACzB;GACA;GACA;GACA,SAAS,UAAU;GACnB,iBAAiB,SAAS;GAC1B;GACA;EACD,CAAC;EACD,oBAAoB;EACpB,OAAO;CACR;CAEA,OAAO;EACN,YAAY,OAAO,OAAO;GACzB,cACC,WACA,YACI,OAAO,WAAW,SAAS,OAAO;GACvC,gBACC,WACA,YACI,OAAO,WAAW,WAAW,OAAO;EAC1C,CAAC;EACD,aAAa;GACZ,OAAO;EACR;EACA,UAAU,WAAW;GACpB,IAAI,CAAC,MAAM,QAAQ,MAAM,GACxB,MAAM,IAAI,kBACT,+JAGD;GAGD,MAAM,uBAAO,IAAI,IAAY;GAC7B,MAAM,UAAwC,CAAC;GAC/C,KAAK,MAAM,SAAS,QAAQ;IAC3B,IACC,UAAU,QACT,OAAO,UAAU,YAAY,OAAO,UAAU,YAE/C,MAAM,IAAI,kBACT,2HAED;IAED,MAAM,cAAc;IACpB,MAAM,SAAS,eAAe,IAAI,WAAW;IAC7C,IAAI,CAAC,QACJ,MAAM,IAAI,kBACT,2HAED;IAED,IAAI,KAAK,IAAI,WAAW,GAAG;IAC3B,KAAK,IAAI,WAAW;IAMpB,IAAI,mBAAmB,MAAM,GAC5B,MAAM,IAAI,kBACT,yBAAyB,OAAO,OAAO,UAAU,EAAE,EAAE,sMAKtD;IAED,QAAQ,KAAK,MAAM;GACpB;GACA,IAAI,KAAK,SAAS,kBACjB,MAAM,IAAI,kBACT,+KAGD;GAED,OAAO;EACR;CACD;AACD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAyHA,eAAsB,WACrB,MACA,IAIa;CACb,MAAM,sBACL,KAAK;CACN,wBACC,cACA,uBACA,mBACD;CAMA,IAAI,KAAK,QAAQ,SAChB,MAAM,YACL,KAAK,QACL,iDACD;CAGD,MAAM,EAAE,QAAQ,eAAe,WAAW,MAAM,KAAK,MAAM,cAC1D,OAAO,QAAQ;EACd,MAAM,aAAa,uBAA4B;EAC/C,IAAI;EACJ,IAAI;GACH,WAAW,MAAM,GAAG,KAAK,WAAW,UAAU;EAC/C,UAAU;GAIT,WAAW,MAAM;EAClB;EACA,MAAM,gBAAgB,WAAW,QAAQ,SAAS,OAAO;EAIzD,MAAM,aAAa,cAAc,SAAS,WAAW;GACpD,MAAM,MAAM,OAAO;GACnB,IACC,OAAO,OAAO,SAAS,KACvB,OAAO,qBAAqB,UAC3B,OAAO,WAAuB,OAAO,kBAEtC,MAAM,IAAI,kBACT,yBAAyB,OAAO,IAAI,EAAE,EAAE,iFAEnC,OAAO,OAAO,gBAAgB,EAAE,mIAGtC;GAED,OAAO,OAAO,OAAO,KAAK,OAAO,UAAU;IAC1C,IAAI,CAAC,cAAc,KAAK,GACvB,MAAM,IAAI,kBACT,sBAAsB,MAAM,KAAK,2IAGjC,MAAM,IACP;IAED,MAAM,gBAAgB;IACtB,MAAM,aAAa,OAAO,OAAO;IACjC,MAAM,cAAc,cAAc;IAClC,MAAM,gBAAgB,cAAc;IACpC,MAAM,UAAoB,CAAC;IAC3B,IAAI,CAAC,aAAa,QAAQ,KAAK,aAAa;IAC5C,IAAI,CAAC,eAAe,QAAQ,KAAK,eAAe;IAChD,IAAI,CAAC,eAAe,CAAC,eACpB,MAAM,IAAI,kBACT,sBAAsB,cAAc,KAAK,eAAe,QAAQ,KAC/D,OACD,EAAE,oOAKF,cAAc,IACf;IAED,OAAO,OAAO,OAAO;KACpB,OAAO;KACP,QAAQ,OAAO,OAAO;MAAE;MAAa;KAAc,CAAC;KACpD,UAAU,OAAO,OAAO;MACvB,kBAAkB,OAAO;MACzB,gBAAgB;MAChB;KACD,CAAC;IACF,CAAC;GACF,CAAC;EACF,CAAC;EACD,IAAI,WAAW,SAAS,GACvB,MAAM,KAAK,OAAO,IAAI,UAAU;EAEjC,OAAO;GACN,QAAQ,SAAS;GACjB;GACA,QAAQ,WAAW,KAAK,EAAE,YAAY,KAAK;EAC5C;CACD,GACA,EAAE,QAAQ,KAAK,OAAO,CACvB;CAQA,MAAM,wBAGD,CAAC;CACN,KAAK,MAAM,EACV,WACA,gBACA,aACA,SACA,QAAQ,qBACJ,eACJ,IAAI;EACH,IAAI,gBAAgB,WACnB,eAAe,qBAAqB,eAAe;OAC7C;GACN,eAAe,YAAY,iBAAiB,OAAiB;GAC7D,sBAAsB,KAAK;IAAE;IAAW;GAAQ,CAAC;EAClD;CACD,SAAS,OAAO;EAKf,uBAAuB,KAAK,iBAAiB,OAAO,SAAS,CAAC;CAC/D;CAQD,MAAM,uBAAuB,KAAK,IAAI,IAAI;CAC1C,MAAM,cAAc,KAAK;CACzB,IAAI,aACH,KAAK,MAAM,EAAE,WAAW,aAAa,uBACpC,IAAI;EACH,MAAM,oBACL,0BACA;GAAE,QAAQ,KAAK;GAAQ,YAAY;EAAqB,IACvD,YAAY,YAAY,WAAW,SAAS,OAAO,CACrD;CACD,SAAS,OAAO;EACf,uBAAuB,KAAK,iBAAiB,OAAO,SAAS,CAAC;CAC/D;CAIF,MAAM,MAAM,KAAK;CACjB,IAAI,OAAO,OAAO,SAAS,GAC1B,IAAI;EACH,MAAM,oBACL,0BACA;GAAE,QAAQ,KAAK;GAAQ,YAAY;EAAqB,IACvD,YACA,IAAI,QAAQ,QAAQ;GACnB,QAAQ,QAAQ;GAChB,WAAW,KAAK,IAAI,GAAG,QAAQ,aAAa,KAAK,IAAI,CAAC;EACvD,CAAC,CACH;CACD,SAAS,OAAO;EAMf,uBAAuB,KAAK,iBAAiB,OAAO,MAAM,CAAC;CAC5D;CAGD,OAAO;AACR;;;;AC3aA,SAAS,kBAAkB,OAAwB;CAClD,OAAO,OAAO,cAAc,KAAK,KAAK,QAAQ,KAAK,SAAS;AAC7D;AAEA,SAAS,oBACR,OACA,OAC6B;CAC7B,IAAI,CAAC,MAAM,OAAO,OAAO;CACzB,IAAI,UAAU;CACd,IAAI;CACJ,IAAI,WAA0B,QAAQ,QAAQ;CAC9C,IAAI;CAEJ,MAAM,YAAY,YAA0B;EAC3C,IAAI,CAAC,kBAAkB,OAAO,GAAG;GAChC,mCAAmB,IAAI,UACtB,sHACD;GACA;EACD;EACA,QAAQ,iBAAiB;GACxB,WAAW,MACT,MAAM,KAAK,CAAC,CACZ,MAAM,UAAU;IAChB,IAAI,CAAC,OACJ,MAAM,IAAI,UACT,kEACD;IAED,IAAI,SAAS;IACb,SAAS,MAAM,YAAY;GAC5B,CAAC,CAAC,CACD,OAAO,UAAmB;IAC1B,mBAAmB;GACpB,CAAC;EACH,GAAG,OAAO;CACX;CAEA,SAAS,MAAM,MAAM,YAAY;CACjC,OAAO;EACN,MAAM,YAAY;GACjB,UAAU;GACV,IAAI,UAAU,QAAW,aAAa,KAAK;GAC3C,MAAM;EACP;EACA,eAAe;CAChB;AACD;AAEA,SAAS,oBACR,QACgE;CAChE,IAAI,OAAO;CACX,MAAM,mBAAyB;EAC9B,IAAI,CAAC,MACJ,MAAM,IAAI,kBACT,yJAGD;CAEF;CAEA,OAAO;EACN,YAAY,OAAO,OAAO;GACzB,cACC,cACI;IACJ,WAAW;IACX,OAAO,OAAO,YAAY,SAAS;GACpC;GACA,gBACC,cACI;IACJ,WAAW;IACX,OAAO,OAAO,cAAc,SAAS;GACtC;EACD,CAAC;EACD,aAAa;GACZ,OAAO;EACR;CACD;AACD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6CA,eAAsB,qBACrB,MACA,SACA,IAKqC;CACrC,MAAM,QAAQ,KAAK;CACnB,MAAM,UAGF;EAAE,OAAO;EAAW,WAAW;CAAU;CAQ7C,MAAM,QAAgC,EACrC,eAAe,OAAO,MAAM,YAAY;EACvC,IAAI;GACH,OAAO,MAAM,KAAK,MAAM,cAAc,OAAO,QAAQ;IACrD,QAAQ,QAAQ;IAChB,QAAQ,YAAY;IACpB,IAAI;KACH,MAAM,SAAS,MAAM,KAAK,GAAG;KAC7B,MAAM,mBAAmB,QAAQ;KAGjC,MAAM,kBAAkB,KAAK;KAC7B,MAAM,mBAAmB,kBAAkB,QAAQ;KACnD,IAAI,qBAAqB,QAAW,MAAM;KAC1C,OAAO;IACR,SAAS,OAAO;KACf,MAAM,mBAAmB,QAAQ;KAGjC,MAAM,kBAAkB,KAAK;KAC7B,MAAM,mBAAmB,kBAAkB,QAAQ;KACnD,MAAM,eAAe,QAAQ;KAG7B,IACC,qBAAqB,UACrB,qBAAqB,SACrB,cAEA,uBACC,KAAK,qBAAqB,kBAAkB;MAC3C,WAAW;MACX,KAAK,aAAa;MAClB,OAAO,aAAa;KACrB,CAAC,CACF;KAED,MAAM,YAAY,QAAQ;KAC1B,IAAI,WAAW;MACd,QAAQ,QAAQ;MAChB,IAAI;OACH,MAAM,MAAM,QAAQ,SAAS;MAC9B,SAAS,cAAc;OAMtB,uBACC,KAAK,qBAAqB,cAAc;QACvC,WAAW;QACX,KAAK,UAAU;QACf,OAAO,UAAU;OAClB,CAAC,CACF;MACD;KACD;KACA,MAAM;IACP;GACD,GAAG,OAAO;EACV,SAAS,OAAO;GASf,MAAM,SAAS,QAAQ;GACvB,IAAI,QAAQ;IACX,QAAQ,QAAQ;IAChB,QAAQ,YAAY;IACpB,IAAI;KACH,MAAM,MAAM,QAAQ,MAAM;IAC3B,SAAS,cAAc;KACtB,uBACC,KAAK,qBAAqB,cAAc;MACvC,WAAW;MACX,KAAK,OAAO;MACZ,OAAO,OAAO;KACf,CAAC,CACF;IACD;GACD;GACA,MAAM;EACP;CACD,EACD;CAEA,MAAM,UAAU,MAAM,WACrB;EAAE,GAAG;EAAM;CAAM,GACjB,OAAO,KAAK,eAAe;EAC1B,IAAI,QAAQ,MAAM,MAAM,MAAM,KAAK,QAAQ,KAAK,QAAQ,WAAW;EACnE,IAAI,MAAM,WAAW,2BAA2B;GAC/C,MAAM,WAAW,KAAK,uBACnB,MAAM,KAAK,qBAAqB,MAAM,gBAAgB,GAAG,IACzD;GACH,IAAI,aAAa,WAChB,MAAM,IAAI,uCACT,MAAM,cACP;GAED,IAAI,aAAa,eAAe,aAAa,iBAC5C,MAAM,IAAI,UACT,uEACD;GAED,MAAM,MAAM,UAAU,MAAM,gBAAgB,QAAQ;GACpD,QAAQ,MAAM,MAAM,MAAM,KAAK,QAAQ,KAAK,QAAQ,WAAW;GAC/D,IAAI,MAAM,WAAW,2BACpB,MAAM,IAAI,uCACT,MAAM,cACP;EAEF;EACA,IAAI,MAAM,WAAW,aACpB,OAAO;GACN,QAAQ;IAAE,UAAU;IAAM,QAAQ,MAAM;GAAa;GACrD,SAAS,CAAC;EACX;EAED,QAAQ,QAAQ,MAAM;EACtB,QAAQ,YAAY,oBAAoB,OAAO,MAAM,KAAK;EAC1D,MAAM,iBAAiB,oBAAoB,UAAU;EACrD,IAAI;EACJ,IAAI;GACH,OAAO,MAAM,GAAG,KAAK,eAAe,YAAY;IAC/C,KAAK,QAAQ;IACb,aAAa,QAAQ;IACrB,YAAY,MAAM,MAAM;GACzB,CAAC;EACF,UAAU;GACT,eAAe,MAAM;EACtB;EAIA,MAAM,SAAS,KAAK;EACpB,MAAM,UAAU,MAAM,QAAQ,KAAK,OAAO,IACvC,OAAO,OAAO,CAAC,GAAG,KAAK,OAAO,CAAC,IAC/B,KAAK;EACR,MAAM,MAAM,SAAS,KAAK,MAAM,OAAO,MAAM;EAC7C,OAAO;GACN,QAAQ;IAAE,UAAU;IAAO;GAAO;GAClC;EACD;CACD,CACD;CAEA,IAAI,CAAC,QAAQ,UAAU;EAOtB,MAAM,iBAAiB,QAAQ;EAC/B,IAAI,CAAC,gBACJ,MAAM,IAAI,kBACT,2EACD;EAED,IAAI;GACH,MAAM,MAAM,QAAQ,cAAc;EACnC,SAAS,cAAc;GAItB,uBACC,KAAK,qBAAqB,cAAc;IACvC,WAAW;IACX,KAAK,eAAe;IACpB,OAAO,eAAe;GACvB,CAAC,CACF;EACD;CACD;CACA,OAAO;AACR;;;;ACjiBA,MAAM,4BAA4B;AAElC,SAAS,oBAAoB,OAAwB;CACpD,OAAO,OAAO,cAAc,KAAK,KAAK,QAAQ;AAC/C;;;;;;;;;;;;;;AAeA,IAAa,2BAAb,MAEA;CACC,AAAiB,0BAAU,IAAI,IAA8B;CAC7D,AAAiB;CACjB,AAAiB;CACjB,AAAiB;CACjB,AAAiB;CACjB,AAAiB;CACjB,AAAQ,kBAAkB;CAE1B,YAAY,UAA2C,CAAC,GAAG;EAC1D,KAAK,QAAQ,QAAQ,gCAAgB,IAAI,KAAK;EAC9C,KAAK,oBACJ,QAAQ,4BAA4B,WAAW,OAAO,WAAW;EAClE,KAAK,kBAAkB,QAAQ,mBAAmB;EAClD,KAAK,eACJ,QAAQ,gBAAgB,KAAK,MAAM,KAAK,kBAAkB,CAAC;EAC5D,IAAI,QAAQ,eAAe,QAC1B,0BACC,4BACA,cACA,QAAQ,UACT;EAED,KAAK,aAAa,QAAQ;EAC1B,IACC,CAAC,oBAAoB,KAAK,eAAe,KACzC,KAAK,kBAAkB,YAEvB,MAAM,IAAI,WACT,4EACD;EAED,IACC,CAAC,oBAAoB,KAAK,YAAY,KACtC,KAAK,gBAAgB,KAAK,mBAC1B,KAAK,eAAe,YAEpB,MAAM,IAAI,WACT,mGACD;CAEF;CAEA,MAAM,MACL,MACA,KACA,aAC4B;EAC5B,MAAM,MAAM,KAAK,MAAM;EACvB,MAAM,WAAW,KAAK,QAAQ,IAAI,GAAG;EACrC,IAAI,aAAa,QAAW;GAC3B,IACC,KAAK,eAAe,UACpB,KAAK,QAAQ,QAAQ,KAAK,YAE1B,MAAM,IAAI,8BAA8B;IACvC,OAAO;IACP,UAAU;IACV,OAAO,KAAK;IACZ,SAAS,KAAK,QAAQ;IACtB,WAAW;GACZ,CAAC;GAEF,OAAO,KAAK,cAAc,KAAK,aAAa,GAAG;EAChD;EACA,IAAI,SAAS,gBAAgB,aAC5B,MAAM,IAAI,yBAAyB;GAClC;GACA,mBAAmB,SAAS;GAC5B,qBAAqB;EACtB,CAAC;EAEF,IAAI,SAAS,WAAW,aACvB,OAAO;GACN,QAAQ;GACR,SAAS,gBAAgB,SAAS,OAAO;EAC1C;EAED,IAAI,MAAM,SAAS,aAClB,MAAM,IAAI,yBAAyB,EAAE,IAAI,CAAC;EAE3C,IAAI,SAAS,WAAW,UACvB,OAAO;GACN,QAAQ;GACR,gBAAgB,OAAO,OAAO;IAC7B;IACA;IACA,OAAO,SAAS;IAChB,WAAW,IAAI,KAAK,SAAS,WAAW,CAAC,CAAC,YAAY;GACvD,CAAC;EACF;EAED,OAAO,KAAK,cAAc,KAAK,aAAa,GAAG;CAChD;CAEA,MAAM,SACL,MACA,OACA,SACgB;EAChB,MAAM,MAAM,KAAK,MAAM;EACvB,MAAM,WAAW,KAAK,QAAQ,IAAI,MAAM,GAAG;EAC3C,IAAI,aAAa,QAChB,MAAM,IAAI,uCAAuC,MAAM,GAAG;EAE3D,IACC,SAAS,WAAW,aACpB,SAAS,UAAU,MAAM,SACzB,OAAO,SAAS,aAEhB,MAAM,KAAK,UAAU,KAAK;EAE3B,MAAM,cAAc,MAAM,KAAK;EAC/B,KAAK,MAAM,WAAW;EACtB,KAAK,QAAQ,IAAI,MAAM,KAAK;GAC3B,aAAa,SAAS;GACtB,QAAQ;GACR,OAAO,SAAS;GAChB;GACA,SAAS,gBAAgB,OAAO;EACjC,CAAC;CACF;CAEA,MAAM,MACL,OACwC;EACxC,MAAM,MAAM,KAAK,MAAM;EACvB,MAAM,WAAW,KAAK,QAAQ,IAAI,MAAM,GAAG;EAC3C,IACC,aAAa,UACb,SAAS,WAAW,eACpB,SAAS,UAAU,MAAM,SACzB,OAAO,SAAS,aAEhB,MAAM,KAAK,UAAU,KAAK;EAE3B,MAAM,cAAc,MAAM,KAAK;EAC/B,MAAM,QAAQ,KAAK,MAAM,WAAW;EACpC,KAAK,QAAQ,IAAI,MAAM,KAAK;GAAE,GAAG;GAAU;EAAY,CAAC;EACxD,OAAO;CACR;CAEA,MAAM,QAAQ,OAA8C;EAC3D,MAAM,WAAW,KAAK,QAAQ,IAAI,MAAM,GAAG;EAC3C,IAAI,UAAU,WAAW,YAAY,SAAS,UAAU,MAAM,OAC7D,KAAK,QAAQ,IAAI,MAAM,KAAK;GAC3B,aAAa,SAAS;GACtB,QAAQ;GACR,OAAO,SAAS;GAChB,SAAS,SAAS;EACnB,CAAC;CAEH;CAEA,MAAM,QAAQ,OAA8C;EAC3D,MAAM,WAAW,KAAK,QAAQ,IAAI,MAAM,GAAG;EAC3C,IACC,aAAa,UACb,SAAS,WAAW,eACpB,SAAS,UAAU,MAAM,OAEzB,KAAK,QAAQ,OAAO,MAAM,GAAG;CAE/B;CAEA,MAAM,UACL,gBACA,UACgB;EAChB,IAAI,aAAa,eAAe,aAAa,iBAC5C,MAAM,IAAI,UACT,oGACD;EAED,MAAM,WAAW,KAAK,QAAQ,IAAI,eAAe,GAAG;EACpD,IACC,aAAa,UACb,SAAS,WAAW,YACpB,SAAS,UAAU,eAAe,SAClC,SAAS,gBAAgB,eAAe,eACxC,IAAI,KAAK,SAAS,WAAW,CAAC,CAAC,YAAY,MAC1C,eAAe,aAChB,KAAK,MAAM,IAAI,SAAS,aAExB,MAAM,IAAI,0BAA0B;GACnC,KAAK,eAAe;GACpB,OAAO,eAAe;EACvB,CAAC;EAEF,IAAI,aAAa,aAAa;GAC7B,KAAK,QAAQ,IAAI,eAAe,KAAK;IACpC,aAAa,SAAS;IACtB,QAAQ;IACR,OAAO,SAAS;IAChB,SAAS,SAAS;GACnB,CAAC;GACD;EACD;EACA,KAAK,QAAQ,OAAO,eAAe,GAAG;CACvC;;CAGA,IAAI,OAAe;EAClB,OAAO,KAAK,QAAQ;CACrB;;CAGA,QAAc;EACb,KAAK,QAAQ,MAAM;CACpB;CAEA,AAAQ,cACP,KACA,aACA,KACmB;EACnB,MAAM,YAAY,KAAK,kBAAkB;EACzC,IAAI,OAAO,cAAc,YAAY,UAAU,WAAW,GACzD,MAAM,IAAI,UAAU,kDAAkD;EAEvE,KAAK,mBAAmB;EACxB,IAAI,CAAC,OAAO,cAAc,KAAK,eAAe,GAC7C,MAAM,IAAI,WAAW,8CAA8C;EAEpE,MAAM,QAAQ,GAAG,KAAK,gBAAgB,GAAG;EACzC,MAAM,cAAc,MAAM,KAAK;EAC/B,MAAM,QAAQ,KAAK,MAAM,WAAW;EACpC,KAAK,QAAQ,IAAI,KAAK;GACrB;GACA,QAAQ;GACR;GACA;EACD,CAAC;EACD,OAAO;GACN,QAAQ;GACR,OAAO,OAAO,OAAO;IAAE;IAAK;IAAO;GAAM,CAAC;EAC3C;CACD;CAEA,AAAQ,MAAM,aAAuC;EACpD,OAAO,OAAO,OAAO;GACpB,WAAW,IAAI,KAAK,WAAW,CAAC,CAAC,YAAY;GAC7C,cAAc,KAAK;EACpB,CAAC;CACF;CAEA,AAAQ,QAAgB;EACvB,MAAM,MAAM,KAAK,MAAM;EACvB,MAAM,QAAQ,eAAe,OAAO,IAAI,QAAQ,IAAI;EACpD,IAAI,CAAC,OAAO,SAAS,KAAK,GACzB,MAAM,IAAI,UAAU,4CAA4C;EAEjE,OAAO;CACR;CAEA,AAAQ,UAAU,OAA0D;EAC3E,OAAO,IAAI,0BAA0B;GACpC,KAAK,MAAM;GACX,OAAO,MAAM;EACd,CAAC;CACF;AACD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AChKA,IAAa,WAAb,MAEA;CACC,AAAiB,2BAAW,IAAI,IAAgC;CAChE,AAAiB;CAEjB,YAAY,SAA8B;EACzC,KAAK,mBAAmB,SAAS;CAClC;CAEA,SAGE,WAAc,SAAyC;EACxD,aAAa,KAAK,UAAU,SAAS,YAAY,UAChD,QAAQ,KAAU,CACnB;CACD;CASA,MAAM,QAA4B,OAAiC;EAClE,MAAM,UAAU,eAAe,KAAK,UAAU,SAAS,MAAM,IAAI;EACjE,IAAI;GAEH,OAAO,GAAG,MADY,QAAQ,KAAK,CACnB;EACjB,SAAS,OAAO;GACf,OAAO,kBAAkB,OAAO,KAAK,kBAAkB,OAAO;EAC/D;CACD;CAQA,MAAM,cAAkC,OAAsB;EAI7D,OAAQ,MADQ,eAAe,KAAK,UAAU,SAAS,MAAM,IACzC,CAAC,CAAC,KAAK;CAC5B;AACD;;;;ACnLA,SAAgB,oBAIf,WACA,QACwB;CACxB,MAAM,aAAa,mCAAmC,SAAS;CAC/D,IAAI,CAAC,YACJ,MAAM,IAAI,UACT,mEACD;CAED,MAAM,cACL,OAAO,WAAW,aAAa,eAAe,OAAO,YAAY;CAClE,OAAO,WAAW,QAAQ,OAAO,UAChC,YAAY,OAA2C,KAAK,CAC7D;AACD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACKA,IAAa,cAAb,MAAyB;CACxB,AAAiB,0BAAU,IAAI,IAG7B;CACF,AAAiB,2BAAW,IAAI,IAA0C;CAI1E,AAAQ,yCAAyB,IAAI,QAAwB;;CAG7D,AAAO,IACN,MACA,IACmB;EACnB,OAAO,KAAK,QAAQ,IAAI,IAAI,CAAC,EAAE,IAAI,EAAE;CACtC;;CAGA,AAAO,IAAU,MAA4B,IAAyB;EACrE,OAAO,KAAK,QAAQ,IAAI,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK;CAC3C;;;;;;;;;;;CAYA,AAAO,UAAgB,MAA4B,IAAyB;EAC3E,OAAO,KAAK,SAAS,IAAI,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK;CAC5C;;;;;;;;;;;;;;CAeA,AAAO,IACN,MACA,IACA,WACO;EACP,IAAI,KAAK,SAAS,IAAI,IAAI,CAAC,EAAE,IAAI,EAAE,GAClC,MAAM,IAAI,sBAAsB,OAAO,EAAE,CAAC;EAE3C,IAAI,QAAQ,KAAK,QAAQ,IAAI,IAAI;EACjC,IAAI,UAAU,QAAW;GACxB,wBAAQ,IAAI,IAAqB;GACjC,KAAK,QAAQ,IAAI,MAAM,KAAK;EAC7B;EACA,MAAM,WAAW,MAAM,IAAI,EAAE;EAC7B,IAAI,aAAa,UAAa,aAAa,WAC1C,MAAM,IAAI,MACT,+DACI,KAAK,KAAK,GAAG,OAAO,EAAE,EAAE,kKAG7B;EAED,MAAM,IAAI,IAAI,SAAS;EAOvB,IACC,cAAc,QACd,OAAO,cAAc,YACrB,CAAC,KAAK,uBAAuB,IAAI,SAAmB,GACnD;GACD,MAAM,UAAU,oBAAoB,SAAS;GAC7C,IAAI,YAAY,QACf,KAAK,uBAAuB,IAAI,WAAqB,OAAO;EAE9D;CACD;;;;;;;;;CAUA,AAAO,gCAA2C;EACjD,MAAM,SAAoB,CAAC;EAC3B,KAAK,MAAM,SAAS,KAAK,QAAQ,OAAO,GACvC,KAAK,MAAM,YAAY,MAAM,OAAO,GAAG;GACtC,MAAM,UAAU,oBAAoB,QAAQ;GAC5C,IAAI,YAAY,QAAW;GAG3B,IAAI,WADH,KAAK,uBAAuB,IAAI,QAAkB,KAAK,IAEvD,OAAO,KAAK,QAAQ;EAEtB;EAED,OAAO;CACR;;;;;;;;;;CAWA,AAAO,QACN,MACA,IACA,WACO;EACP,MAAM,QAAQ,KAAK,QAAQ,IAAI,IAAI;EACnC,IAAI,OAAO,IAAI,EAAE,MAAM,WACtB,MAAM,OAAO,EAAE;CAEjB;;;;;;;;;CAUA,AAAO,OAAa,MAA4B,IAAsB;EACrE,KAAK,QAAQ,IAAI,IAAI,CAAC,EAAE,OAAO,EAAE;EACjC,IAAI,aAAa,KAAK,SAAS,IAAI,IAAI;EACvC,IAAI,eAAe,QAAW;GAC7B,6BAAa,IAAI,IAAY;GAC7B,KAAK,SAAS,IAAI,MAAM,UAAU;EACnC;EACA,WAAW,IAAI,EAAE;CAClB;;CAGA,AAAO,QAAc;EACpB,KAAK,QAAQ,MAAM;EACnB,KAAK,SAAS,MAAM;EAKpB,KAAK,yCAAyB,IAAI,QAAwB;CAC3D;AACD;;;;;;;;;;AAWA,SAAS,oBAAoB,OAAoC;CAChE,IAAI,UAAU,QAAQ,OAAO,UAAU,UAAU,OAAO;CACxD,MAAM,aAAa,mCAAmC,KAAK;CAC3D,IAAI,YAAY,mBAAmB,OAAO,WAAW,kBAAkB;CACvE,MAAM,UAAW,MAAsC;CACvD,OAAO,MAAM,QAAQ,OAAO,IAAI,QAAQ,SAAS;AAClD;;;;ACjKA,MAAM,+BAAe,IAAI,QAAoC;;AAG7D,SAAgB,2BACf,OACA,WAC8C;CAC9C,OAAO,oBAAoB,OAAO,MAAM,QAAQ,SAAS,GAAG,QAAQ;AACrE;;AAGA,SAAgB,0BACf,OAC8C;CAC9C,OAAO,oBAAoB,OAAO,QAAW,KAAK;AACnD;;;;;AAMA,SAAgB,6BACf,UACA,WAC8C;CAC9C,MAAM,aAAa,cAAc,QAAQ;CACzC,OAAO,0BAA0B;EAChC,GAAG;EACH,UAAU,WAAW,QAAQ,SAAS;EACtC,WAAW;CACZ,CAAC;AACF;;;;;;;;;;;;;AAcA,SAAgB,6BACf,UACA,WACU;CACV,MAAM,aAAa,cAAc,QAAQ;CACzC,IAAI,WAAW,cAAc,OAAO,OAAO;CAC3C,OAAO,CAAC,WAAW,cAClB,WAAW,UACX,WAAW,QAAQ,SAAS,CAC7B;AACD;;AAGA,SAAgB,yBACf,UACA,WACiC;CACjC,MAAM,aAAa,cAAc,QAAQ;CACzC,MAAM,QAAQ,WAAW,QACxB,WAAW,UACX,WACA,WAAW,SACZ;CACA,OAAO,OAAO,OAAO;EAAE;EAAO,OAAO,WAAW,QAAQ,KAAK;CAAE,CAAC;AACjE;AAEA,SAAS,oBACR,OACA,UACA,WAC8C;CAC9C,OAAO,0BAA0B;EAChC;EACA;EACA,UAAU,cAAc,MAAM,QAAQ,SAAuB;EAC7D,gBAAgB,GAAG,MAClB,MAAM,gBACH,MAAM,cAAc,GAAgB,CAAc,IAClD,UAAU,GAAG,CAAC;EAClB,UAAU,QAAQ,WAAW,qBAC5B,MAAM,QACL,QACA,WACA,gBACD;EACD,UAAU,YAAY,MAAM,QAAQ,OAAqB;CAC1D,CAAC;AACF;AAEA,SAAS,0BACR,YAC8C;CAC9C,MAAM,QAAQ,OAAO,OAAO,OAAO,OAAO,IAAI,CAAC;CAI/C,aAAa,IAAI,OAAiB,UAAU;CAC5C,OAAO;AACR;AAEA,SAAS,cACR,UACqB;CACrB,MAAM,aAAa,aAAa,IAAI,QAAkB;CACtD,IAAI,CAAC,YACJ,MAAM,IAAI,UACT,gEACD;CAED,OAAO;AACR;;;;;;;;;;;;;;;;;;;;;;ACtJA,IAAa,wBAAb,cAA2C,eAAsC;CAChF,cAAc;EACb,MACC,uBACA,oQAID;CACD;AACD;;;;;;;;;;;;;;;;;;AA6CA,IAAa,yBAAb,cAA4C,eAAqC;CACpD;CAA5B,YAAY,AAAgB,WAAmB;EAC9C,MACC,sBACA,2BAA2B,UAAU,2JAGtC;EAN2B;CAO5B;AACD;;AAGA,IAAa,gCAAb,cAAmD,eAA6C;CAE9E;CACA;CAFjB,YACC,AAAgB,YAChB,AAAgB,cACf;EACD,MACC,8BACA,uBAAuB,WAAW,aAAa,aAAa,oCAE7D;EAPgB;EACA;CAOjB;AACD;;AAGA,IAAa,mCAAb,cAAsD,eAAgD;CACzE;CAA5B,YAAY,AAAgB,YAAoB;EAC/C,MACC,iCACA,eAAe,WAAW,qIAG3B;EAN2B;CAO5B;AACD;;AAGA,IAAa,oCAAb,cAAuD,eAAkD;CACxG,AAAS;CACT,AAAS;CACT,AAAS;CAET,YAAY,SAKT;EACF,MACC,mCACA,0CAA0C,QAAQ,OAAO,gBACrD,QAAQ,YAAY,4GAExB,QAAQ,gBACT;EACA,KAAK,cAAc,QAAQ;EAC3B,KAAK,SAAS,QAAQ;EACtB,KAAK,cAAc,QAAQ;CAC5B;AACD;;;;;;;;AAoBA,IAAa,yBAAb,cAA4C,eAAqC;CAE/D;CACA;CACA;CACA;CAJjB,YACC,AAAgB,aAChB,AAAgB,WAChB,AAAgB,QAChB,AAAgB,kBACf;EACD,MACC,sBACA,uBAAuB,aAAa,WAAW,QAAQ,gBAAgB,CACxE;EARgB;EACA;EACA;EACA;CAMjB;AACD;AAEA,SAAS,uBACR,aACA,WACA,QACA,kBACS;CACT,QAAQ,QAAR;EACC,KAAK,cACJ,OACC,aAAa,YAAY,4BAA4B,UAAU;EAIjE,KAAK,iBACJ,OACC,aAAa,YAAY;EAG3B,KAAK,wBACJ,OACC,aAAa,YAAY,4BAA4B,UAAU;EAIjE,KAAK,sBACJ,OACC,aAAa,YAAY,6BACtB,oBAAoB,gBAAgB,IAAI,UAAU;EAIvD,KAAK,8BACJ,OACC,aAAa,YAAY,iBAAiB,oBAAoB,QAAQ;CAIzE;AACD;;;;;;;;;;;;;;;;;;;;;AAsBA,IAAa,cAAb,cAAiC,oBAAqC;CACrE,YAAY,OAAgB;EAC3B,MAAM;GACL,MAAM;GACN,SACC;GAID;EACD,CAAC;CACF;AACD;;;;;;;;;;;;;;AAeA,IAAa,gBAAb,cAAmC,oBAAuC;CAGxD;CAFjB,YACC,OACA,AAAgB,eACf;EACD,MAAM;GACL,MAAM;GACN,SACC;GAGD;EACD,CAAC;EATe;CAUjB;AACD;AAqFA,MAAM,4BAA2C,OAAO,IACvD,2CACD;;;;;;;;;;;;;;AA8IA,SAAS,kCACR,YACO;CACP,KAAK,MAAM,OAAO;EAAC;EAAU;EAAS;CAAU,GAC/C,IAAI,OAAO,WAAW,SAAS,YAC9B,MAAM,IAAI,UACT,sBAAsB,IAAI,gMAI3B;CAGF,IAAI,OAAO,WAAW,cAAc,YACnC,MAAM,IAAI,UACT,oJAGD;CAED,IACC,WAAW,gBAAgB,QAC3B,OAAO,WAAW,gBAAgB,UAElC,MAAM,IAAI,UACT,uJAGD;AAEF;AAEA,SAAgB,mBAKP;CACR,MAAM,WAAW,eAA+B;EAC/C,MAAM,UAAU,EAAE,GAAG,WAAW;EAMhC,kCAAkC,OAAuC;EACzE,OAAO,eAAe,SAAS,2BAA2B;GACzD,cAAc;GACd,YAAY;GACZ,OAAO;GACP,UAAU;EACX,CAAC;EACD,OAAO,OAAO,OAAO,OAAO;CAC7B;CACA,OAAO;AAMR;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAyKA,IAAa,aAAb,MAIE;CAG4B;CAF7B,AAAQ,UAAU;CAElB,YAAY,AAAiB,MAA+C;EAA/C;CAAgD;;;;;;;CAQ7E,MAAa,IACZ,MAGA,SACa;EAOb,IAAI,SAAS,QAAQ,SACpB,MAAM,YACL,QAAQ,QACR,qDACD;EAED,IAAI,KAAK,SACR,MAAM,IAAI,sBAAsB;EAEjC,KAAK,UAAU;EAEf,IAAI;EACJ,IAAI,gBAAgB;EACpB,IAAI,YAAY;EAChB,IAAI;EAEJ,IAAI;GACH,OAAO,MAAM,WACZ;IACC,QAAQ,KAAK,KAAK;IAClB,KAAK,KAAK,KAAK;IACf,OAAO,KAAK,KAAK;IACjB,gBAAgB,KAAK,KAAK;IAC1B,aAAa,KAAK,KAAK;IACvB,gBAAgB,KAAK,KAAK;IAC1B,qBAAqB,KAAK,KAAK;IAC/B,QAAQ,SAAS;GAClB,GACA,OAAO,IAAI,eAAe;IAOzB,SAAS,MAAM;IACf,MAAM,IAAI,IAAI,QAAa,UAAU;IACrC,UAAU;IACV,gBAAgB;IAChB,YAAY;IACZ,YAAY;IAGZ,MAAM,UAAU,YADK,KAAK,kBAAkB,IAAI,CACT,GAAG,GAAG,SAAS,MAAM;IAC5D,IAAI;KACH,MAAM,SAAS,MAAM,KAAK,OAAO;KAKjC,EAAE,oBAAoB;KACtB,MAAM,EAAE,MAAM,EAAE;KAIhB,EAAE,oBAAoB;KACtB,gBAAgB;KAMhB,MAAM,UAAU,EAAE;KAClB,EAAE,MAAM;KACR,OAAO;MAAE;MAAQ;KAAQ;IAC1B,SAAS,OAAO;KACf,YAAY;KACZ,YAAY;KACZ,MAAM;IACP;GACD,CACD;EACD,SAAS,OAAO;GACf,MAAM,iBAAiB,OAAO;IAC7B;IACA;IACA;IACA,QAAQ,SAAS;GAClB,CAAC;EACF,UAAU;GACT,SAAS,MAAM;GACf,KAAK,UAAU;EAChB;CACD;CAEA,AAAQ,kBACP,IACA,SAC+B;EAC/B,MAAM,eAAe,CAAC;EACtB,KAAK,MAAM,OAAO,OAAO,KAAK,KAAK,KAAK,YAAY,GAEjD;GACF,MAAM,YAAY,KAAK,KAAK,aAAa;GACzC,IAAI,CAAC,uBAAuB,SAAS,GACpC,MAAM,IAAI,iCAAiC,OAAO,GAAG,CAAC;GAEvD,MAAM,aAAa;GAEnB,aAAa,OAAO,qBADJ,WAAW,OAAO,IAAI,QAAQ,YAAY,UAAU,CAE7D,GACN,SACA,YACA,OAAO,GAAG,CACX;EACD;EACA,OAAO;CACR;AACD;AAEA,SAAS,uBAAuB,OAAiC;CAChE,IAAI,UAAU,QAAQ,OAAO,UAAU,UAAU,OAAO;CACxD,IAAI;EACH,MAAM,SAAS,QAAQ,yBACtB,OACA,yBACD;EACA,OACC,QAAQ,UAAU,QAClB,OAAO,iBAAiB,SACxB,OAAO,eAAe,SACtB,OAAO,aAAa,SACpB,OAAO,SAAS,KAAK;CAEvB,QAAQ;EACP,OAAO;CACR;AACD;;;;;;;AAQA,SAAS,qBACR,SACA,SACA,YACA,YACc;CACd,IAAI,YAAY,QAAQ,OAAO,YAAY,UAC1C,MAAM,IAAI,8BACT,YACA,YAAY,OAAO,SAAS,OAAO,OACpC;CAGD,MAAM,QAAQ,4BACb,SACA,SACA,UACD;CACA,qCAAqC,KAAK;CAC1C,4BAA4B,KAAK;CACjC,OAAO,IAAI,MACV,MAAM,QACN,8BAA8B,KAAK,CACpC;AACD;AAEA,MAAM,kCAAkC;CAAC;CAAO;CAAU;AAAQ;AAmBlE,SAAS,4BACR,QACA,SACA,YAC6B;CAC7B,OAAO;EACN;EACA,QAAQ,OAAO,OAAO,QAAQ,eAAe,MAAM,CAAC;EACpD;EACA;EACA,6BAAa,IAAI,IAAI;EACrB,wCAAwB,IAAI,IAAI;EAChC,wBAAQ,IAAI,IAAI;CACjB;AACD;AAEA,SAAS,wBAAwB,UAA+B;CAK/D,OAAO,cAHN,OAAO,aAAa,WAChB,SAAS,eAAe,SAAS,SAAS,IAC3C;AAEL;AAEA,SAAS,+BAA+B,UAAgC;CACvE,OAAO,gCAAgC,SACtC,QACD;AACD;;;;;;;AAQA,SAAS,8BACR,QACA,UACU;CACV,IAAI,UAAyB;CAC7B,OAAO,YAAY,QAAQ,YAAY,OAAO,WAAW;EACxD,IAAI,QAAQ,yBAAyB,SAAS,QAAQ,GAAG,OAAO;EAChE,UAAU,QAAQ,eAAe,OAAO;CACzC;CACA,OAAO;AACR;AAEA,SAAS,qBACR,OACA,UACU;CACV,MAAM,QAAQ,WAAW,wBAAwB,QAAQ,CAAC;CAC1D,MAAM,QAAQ,QAAQ,IAAI,MAAM,QAAQ,UAAU,MAAM,MAAM;CAC9D,IAAI,OAAO,UAAU,YAAY,OAAO;CAMxC,MAAM,SAAS,MAAM,YAAY,IAAI,QAAQ;CAC7C,IAAI,UAAU,OAAO,iBAAiB,OAAO,OAAO,OAAO;CAC3D,MAAM,eAAe;CACrB,MAAM,WAAW,GAAG,SAA6B;EAChD,MAAM,QAAQ,WAAW,wBAAwB,QAAQ,CAAC;EAC1D,OAAO,QAAQ,MAAM,cAAc,MAAM,QAAQ,IAAI;CACtD;CACA,MAAM,YAAY,IAAI,UAAU;EAAE;EAAc;CAAQ,CAAC;CACzD,OAAO;AACR;AAEA,SAAS,kCACR,OACA,UACA,YACO;CACP,OAAO,eAAe,MAAM,QAAQ,UAAU;EAC7C,cAAc;EACd,YAAY,WAAW,cAAc;EACrC,WAAW,qBAAqB,OAAO,QAAQ;EAC/C,KACE,WAAW,cAAc,WAAW,YAAa,WAAW,OACzD,UAAmB;GACpB,MAAM,QAAQ,WAAW,wBAAwB,QAAQ,CAAC;GAC1D,IAAI,CAAC,QAAQ,IAAI,MAAM,QAAQ,UAAU,OAAO,MAAM,MAAM,GAC3D,MAAM,IAAI,UACT,wCAAwC,OAAO,QAAQ,GACxD;EAEF,IACC;CACL,CAAC;CACD,MAAM,uBAAuB,IAAI,QAAQ;AAC1C;AAEA,SAAS,qCACR,OACO;CACP,MAAM,aAAa,MAAM,WAAW,kBACjC,kCACA,gCAAgC,MAAM,GAAG,CAAC;CAC7C,KAAK,MAAM,aAAa,YAAY;EACnC,MAAM,OAAO,IAAI,SAAS;EAC1B,OAAO,eAAe,MAAM,QAAQ,WAAW;GAC9C,cAAc;GACd,YAAY;GACZ,UAAU;GACV,QAAQ,cAAuB;IAC9B,MAAM,QAAQ,WAAW,wBAAwB,SAAS,CAAC;IAC3D,MAAM,QAAQ,UAAU,CACvB,WACA,MAAM,UACP;GACD;EACD,CAAC;CACF;AACD;AAEA,SAAS,4BACR,OACO;CACP,KAAK,MAAM,YAAY,QAAQ,QAAQ,MAAM,MAAM,GAAG;EACrD,IAAI,+BAA+B,QAAQ,GAAG;EAC9C,MAAM,aAAa,QAAQ,yBAAyB,MAAM,QAAQ,QAAQ;EAC1E,IAAI,YACH,kCAAkC,OAAO,UAAU,UAAU;CAE/D;AACD;AAEA,SAAS,8BACR,OACuB;CACvB,OAAO;EACN,MAAM,QAAQ,UAAU,aAAa;GAYpC,IACC,CAAC,8BAA8B,QAAQ,QAAQ,KAC/C,CAAC,8BAA8B,MAAM,QAAQ,QAAQ,GAErD,OAAO,QAAQ,IAAI,QAAQ,UAAU,QAAQ;GAE9C,MAAM,QAAQ,WAAW,wBAAwB,QAAQ,CAAC;GAE1D,IADY,QAAQ,yBAAyB,QAAQ,QAC/C,GAAG,OAAO,QAAQ,IAAI,QAAQ,UAAU,QAAQ;GACtD,IAAI,aAAa,UAAU,OAAO;GAClC,OAAO,qBAAqB,OAAO,QAAQ;EAC5C;EACA,MAAM,QAAQ,UAAU,OAAO,aAC9B,4BAA4B,OAAO,QAAQ,UAAU,OAAO,QAAQ;EACrE,MAAM,QAAQ,aAAa;GAC1B,MAAM,QAAQ,WAAW,wBAAwB,QAAQ,CAAC;GAC1D,OACC,MAAM,OAAO,IAAI,QAAQ,KACxB,aAAa,aACZ,QAAQ,IAAI,QAAQ,QAAQ,KAC5B,QAAQ,IAAI,MAAM,QAAQ,QAAQ;EAEtC;EACA,iBAAiB,QAAQ,UAAU,eAClC,+BAA+B,OAAO,QAAQ,UAAU,UAAU;EACnE,iBAAiB,QAAQ,aACxB,+BAA+B,OAAO,QAAQ,QAAQ;CACxD;AACD;AAEA,SAAS,4BACR,OACA,QACA,UACA,OACA,UACU;CACV,MAAM,QAAQ,WAAW,wBAAwB,QAAQ,CAAC;CAC1D,IAAI,+BAA+B,QAAQ,GAAG,OAAO;CACrD,IAAI,QAAQ,yBAAyB,QAAQ,QAAQ,GAAG;EACvD,MAAM,MAAM,QAAQ,IAAI,QAAQ,UAAU,OAAO,QAAQ;EACzD,IAAI,KAAK,MAAM,YAAY,OAAO,QAAQ;EAC1C,OAAO;CACR;CACA,IAAI,CAAC,QAAQ,aAAa,MAAM,GAAG,OAAO;CAC1C,MAAM,MAAM,QAAQ,IAAI,MAAM,QAAQ,UAAU,OAAO,MAAM,MAAM;CACnE,MAAM,aAAa,QAAQ,yBAAyB,MAAM,QAAQ,QAAQ;CAC1E,IAAI,OAAO,YACV,kCAAkC,OAAO,UAAU,UAAU;CAM9D,IAAI,KAAK,MAAM,YAAY,OAAO,QAAQ;CAC1C,OAAO;AACR;AAEA,SAAS,+BACR,OACA,QACA,UACA,YACU;CACV,MAAM,QAAQ,WAAW,wBAAwB,QAAQ,CAAC;CAC1D,IACC,+BAA+B,QAAQ,KACvC,CAAC,QAAQ,yBAAyB,QAAQ,QAAQ,GAElD,OAAO;CAER,MAAM,UAAU,QAAQ,yBAAyB,QAAQ,QAAQ;CACjE,IAAI,CAAC,QAAQ,eAAe,QAAQ,UAAU,UAAU,GAAG,OAAO;CAClE,MAAM,OAAO,QAAQ,yBAAyB,QAAQ,QAAQ;CAC9D,IACC,MAAM,uBAAuB,IAAI,QAAQ,MACxC,SAAS,QAAQ,MAAM,OAAO,SAAS,QAAQ,MAAM,MAEtD,MAAM,uBAAuB,OAAO,QAAQ;CAE7C,OAAO;AACR;AAEA,SAAS,+BACR,OACA,QACA,UACU;CACV,MAAM,QAAQ,WAAW,wBAAwB,QAAQ,CAAC;CAC1D,IAAI,+BAA+B,QAAQ,GAAG,OAAO;CACrD,MAAM,mBAAmB,QAAQ,yBAAyB,QAAQ,QAAQ;CAC1E,IAAI,oBAAoB,CAAC,MAAM,uBAAuB,IAAI,QAAQ,GACjE,OAAO,QAAQ,eAAe,QAAQ,QAAQ;CAE/C,MAAM,mBAAmB,QAAQ,yBAChC,MAAM,QACN,QACD;CACA,IACC,kBAAkB,iBAAiB,SACnC,kBAAkB,iBAAiB,OAEnC,OAAO;CAER,IAAI,CAAC,QAAQ,eAAe,MAAM,QAAQ,QAAQ,GAAG,OAAO;CAC5D,IAAI,oBAAoB,CAAC,QAAQ,eAAe,QAAQ,QAAQ,GAC/D,OAAO;CACR,MAAM,uBAAuB,OAAO,QAAQ;CAC5C,MAAM,YAAY,OAAO,QAAQ;CACjC,OAAO;AACR;;AAmCA,IAAM,UAAN,MAA0C;CAyBZ;CAnB7B,AAAiB,oBAA6C,CAAC;CAC/D,AAAiB,gCAAgB,IAAI,IAA+B;CACpE,AAAiB,eAAe,IAAI,YAAY;CAKhD,AAAiB,mBAAmB,OAAO,OAAO;EACjD,KAAK,KAAK,aAAa,IAAI,KAAK,KAAK,YAAY;EACjD,KAAK,KAAK,aAAa,IAAI,KAAK,KAAK,YAAY;EACjD,WAAW,KAAK,aAAa,UAAU,KAAK,KAAK,YAAY;CAC9D,CAAC;CACD,AAAiB,uCAAuB,IAAI,QAG1C;CACF,AAAiB,qCAAqB,IAAI,IAA2B;CACrE,AAAQ,UAAU;CAElB,YAAY,AAAiB,kBAAyC;EAAzC;CAA0C;CAEvE,IAAW,cAAqC;EAC/C,KAAK,WAAW,sBAAsB;EACtC,OAAO,KAAK;CACb;CAEA,AAAO,YACN,YACsD;EACtD,MAAM,UAAU;EAChB,OAAO,OAAO,OAAO;GACpB,IAAI,cAAc;IACjB,OAAO,QAAQ;GAChB;GACA,cAAc,cACb,QAAQ,YAAY,WAAW,UAAU;EAC3C,CAAC;CACF;;CAGA,AAAQ,eACP,WACqC;EACrC,OAAO,KAAK,qBAAqB,IAChC,SACD,CAAC,EAAE;CACJ;;CAGA,AAAQ,kBAAkB,WAA4B;EACrD,OAAO,KAAK,eAAe,SAAS,CAAC,EAAE,WAAW;CACnD;CAEA,AAAQ,YACP,WACA,YACa;EACb,KAAK,WAAW,sBAAsB;EAItC,MAAM,WAAW,KAAK,qBAAqB,IAAI,SAAS;EACxD,IAAI,YAAY,SAAS,eAAe,YACvC,MAAM,IAAI,uBACT,OAAO,UAAU,EAAE,GACnB,QACA,wBACA,SAAS,cAAc,MACxB;EAED,KAAK,aAAa,IAAI,WAAW,WAAW,UAAU,IAAI,SAAS;EACnE,IAAI,UAAU,OAAO;EAErB,MAAM,QAA+B;GACpC;GACA,WAAW;GACX,iBAAiB,UAAU;GAC3B;GACA,UAAU,2BAA2B,WAAW,aAAa,SAAS;EACvE;EACA,KAAK,qBAAqB,IAAI,WAAW,KAAK;EAC9C,KAAK,mBAAmB,IAAI,KAAK;EACjC,OAAO;CACR;CAEA,AAAO,IACN,WACA,YACO;EACP,KAAK,WAAW,gBAAgB;EAChC,KAAK,iBAAiB,WAAW,UAAU;EAC3C,MAAM,WAAW,KAAK,qBAAqB,IAAI,SAAS;EACxD,IAAI,YAAY,SAAS,eAAe,YACvC,MAAM,IAAI,uBACT,OAAO,UAAU,EAAE,GACnB,OACA,wBACA,SAAS,cAAc,MACxB;EAED,IAAI,UAAU,cAAc,UAC3B,MAAM,IAAI,uBACT,OAAO,UAAU,EAAE,GACnB,OACA,iBACA,SAAS,cAAc,MACxB;EAGD,IAAI,QAAQ;EACZ,MAAM,eAAe,CAAC;EACtB,IAAI,CAAC,OAAO;GACX,KAAK,aAAa,IAAI,WAAW,WAAW,UAAU,IAAI,SAAS;GACnE,QAAQ;IACP;IACA,WAAW;IACX,iBAAiB;IACjB;IACA,UAAU,0BAA0B,WAAW,WAAW;GAC3D;GACA,KAAK,qBAAqB,IAAI,WAAW,KAAK;GAC9C,KAAK,mBAAmB,IAAI,KAAK;EAClC;EAEA,IAAI;GACH,KAAK,cAAc,OAAO,OAAO,UAAU;EAC5C,SAAS,OAAO;GAMf,IAAI,cAAc;IACjB,KAAK,qBAAqB,OAAO,SAAS;IAC1C,KAAK,mBAAmB,OAAO,KAAK;IACpC,KAAK,aAAa,QAAQ,WAAW,WAAW,UAAU,IAAI,SAAS;GACxE;GACA,MAAM;EACP;CACD;CAEA,AAAO,OACN,WACA,YACO;EACP,KAAK,WAAW,mBAAmB;EACnC,MAAM,QAAQ,KAAK,eAAe,WAAW,UAAU,UAAU;EACjE,KAAK,cAAc,OAAO,UAAU,UAAU;CAC/C;CAEA,AAAO,OACN,WACA,YACO;EACP,KAAK,WAAW,mBAAmB;EAQnC,MAAM,QAAQ,KAAK,qBAAqB,IAAI,SAAS;EACrD,IAAI,KAAK,kBAAkB,SAAS,KAAK,OAAO,eAAe,YAC9D;EAED,MAAM,SAAS,KAAK,eAAe,WAAW,UAAU,UAAU;EAClE,KAAK,cAAc,QAAQ,UAAU,UAAU;CAChD;;CAGA,AAAQ,cACP,OACA,QACA,YACO;EACP,MAAM,kBAAkB,KAAK,eAAe,OAAO,MAAM;EACzD,IAAI;GACH,IAAI,WAAW,UACd,KAAK,sBACJ,MAAM,WACN,YACA,MAAM,eACP;QAEA,KAAK,oBACJ,MAAM,WACN,YACA,MAAM,eACP;EAEF,SAAS,OAAO;GACf,IAAI,iBAAiB,KAAK,2BAA2B,KAAK;GAC1D,MAAM;EACP;CACD;CAEA,AAAQ,eACP,WACA,WACA,YACwB;EACxB,KAAK,iBAAiB,WAAW,UAAU;EAC3C,MAAM,QAAQ,KAAK,qBAAqB,IAAI,SAAS;EAKrD,IAAI,SAAS,MAAM,eAAe,YACjC,MAAM,IAAI,uBACT,OAAO,UAAU,EAAE,GACnB,WACA,wBACA,MAAM,cAAc,MACrB;EAMD,IACC,SACA,MAAM,cAAc,SACpB,MAAM,eAAe,YAErB,MAAM,IAAI,uBACT,OAAO,UAAU,EAAE,GACnB,WACA,sBACA,MAAM,cAAc,MACrB;EAED,IACC,CAAC,SACD,MAAM,cAAc,YACpB,MAAM,eAAe,YAErB,MAAM,IAAI,uBACT,OAAO,UAAU,EAAE,GACnB,WACA,cACA,OAAO,cAAc,MACtB;EAED,OAAO;CACR;CAEA,AAAQ,iBACP,WACA,YACO;EACP,IAAI,KAAK,aAAa,UAAU,WAAW,WAAW,UAAU,EAAE,GACjE,MAAM,IAAI,sBAAsB,OAAO,UAAU,EAAE,CAAC;CAEtD;CAEA,AAAQ,eACP,OACA,QACU;EACV,IAAI,MAAM,iBAAiB,QAAW;GACrC,IAAI,MAAM,aAAa,WAAW,QACjC,MAAM,IAAI,uBACT,OAAO,MAAM,UAAU,EAAE,GACzB,QACA,sBACA,MAAM,aAAa,MACpB;GAED,KAAK,iCAAiC,KAAK;GAC3C,OAAO;EACR;EAEA,MAAM,eAAe,OAAO,OAAO;GAClC;GACA,SAAS,MAAM,UAAU;GAEzB,QAAQ,MAAM,UAAU;GACxB,UAAU,6BAA6B,MAAM,UAAU,MAAM,SAAS;GACtE,SAAS,yBAAyB,MAAM,UAAU,MAAM,SAAS;EAClE,CAAC;EACD,KAAK,kBAAkB,KAAK,KAAK;EACjC,OAAO;CACR;;CAGA,AAAQ,2BAA2B,OAAoC;EACtE,MAAM,QAAQ,KAAK,kBAAkB,YAAY,KAAK;EACtD,IAAI,SAAS,GAAG,KAAK,kBAAkB,OAAO,OAAO,CAAC;EACtD,OAAO,MAAM;CACd;CAEA,AAAQ,iCAAiC,OAAoC;EAC5E,MAAM,eAAe,MAAM;EAC3B,IAAI,iBAAiB,QAAW;EAChC,MAAM,gBAAgB,MAAM,UAAU;EAKtC,MAAM,qBAAqB,6BAC1B,aAAa,UACb,MAAM,SACP;EACA,MAAM,aACL,cAAc,WAAW,aAAa,OAAO,UAC7C,cAAc,OACZ,OAAO,UAAU,UAAU,aAAa,OAAO,MACjD;EACD,IACC,aAAa,YAAY,MAAM,UAAU,WACzC,CAAC,cACD,oBAEA,MAAM,IAAI,uBACT,OAAO,MAAM,UAAU,EAAE,GACzB,UACA,8BACA,aAAa,MACd;CAEF;CAEA,AAAQ,oBACP,WACA,YACA,iBAC4B;EAC5B,KAAK,WAAW,uBAAuB;EAMvC,IACC,KAAK,kBAAkB,SAAS,KAChC,KAAK,aAAa,UAAU,WAAW,WAAW,UAAU,EAAE,GAE9D,MAAM,IAAI,sBAAsB,OAAO,UAAU,EAAE,CAAC;EAErD,MAAM,QAAQ,KAAK,iBAAiB,YAAY,WAAW,EAC1D,gBACD,CAAC;EACD,KAAK,cAAc,IAAI,KAAK;EAC5B,OAAO;CACR;CAEA,AAAQ,sBACP,WACA,YACA,iBAC4B;EAC5B,KAAK,WAAW,mBAAmB;EACnC,MAAM,QAAQ,KAAK,iBAAiB,cAAc,WAAW,EAC5D,gBACD,CAAC;EAcD,KAAK,aAAa,OAAO,WAAW,WAAW,UAAU,EAAE;EAC3D,KAAK,cAAc,IAAI,KAAK;EAC5B,OAAO;CACR;;;;;;;;CASA,AAAO,sBAA4B;EAClC,KAAK,MAAM,SAAS,KAAK,oBAAoB;GAC5C,IAAI,MAAM,iBAAiB,QAAW;IACrC,KAAK,iCAAiC,KAAK;IAC3C;GACD;GAIA,IACC,MAAM,cAAc,aACnB,MAAM,UAAU,YAAY,MAAM,mBAClC,6BAA6B,MAAM,UAAU,MAAM,SAAS,IAE7D,MAAM,IAAI,uBAAuB,OAAO,MAAM,UAAU,EAAE,CAAC;EAE7D;EAEA,KAAK,MAAM,YAAY,KAAK,aAAa,8BAA8B,GAAG;GAGzE,IACC,aAAa,QACb,OAAO,aAAa,YACpB,KAAK,eAAe,QAAQ,MAAM,QAElC;GAKD,MAAM,KAAM,SAA8B;GAC1C,MAAM,IAAI,uBAAuB,OAAO,EAAE,CAAC;EAC5C;CACD;;CAGA,MAAa,MAAM,aAAqC;EACvD,KAAK,WAAW,kBAAkB;EAClC,KAAK,MAAM,SAAS,KAAK,mBAAmB;GAC3C,MAAM,eAAe,MAAM;GAC3B,IAAI,iBAAiB,QACpB,MAAM,IAAI,uBACT,OAAO,MAAM,UAAU,EAAE,GACzB,UACA,4BACD;GAED,MAAM,QAAQ,OAAO,OAAO;IAC3B,QAAQ,aAAa;IACrB,aAAa,MAAM,UAAU;IAC7B,iBAAiB,MAAM;IACvB,SAAS,aAAa;IACtB,SAAS,aAAa;IACtB,QAAQ,aAAa;GACtB,CAAC;GACD,IAAI;IACH,MAAM,MAAM,WAAW,MAAM,aAAa,KAAK;GAChD,SAAS,OAAO;IACf,MAAM,8BAA8B,MAAM,YAAY,OAAO,KAAK;GACnE;EACD;CACD;CAEA,IAAW,eAAyD;EACnE,OAAO,CAAC,GAAG,KAAK,aAAa;CAC9B;CAEA,AAAO,QAAc;EACpB,KAAK,UAAU;EAKf,KAAK,aAAa,MAAM;EACxB,KAAK,mBAAmB,MAAM;EAC9B,KAAK,kBAAkB,SAAS;EAChC,KAAK,cAAc,MAAM;CAC1B;CAEA,AAAO,WAAW,WAAyB;EAC1C,IAAI,KAAK,SACR,MAAM,IAAI,uBAAuB,SAAS;CAE5C;AACD;AAEA,SAAS,8BACR,YACA,OACA,OACsB;CACtB,IAAI;CACJ,IAAI;EACH,SAAS,WAAW,SAAS,OAAO,KAAK;CAC1C,SAAS,aAAa;EACrB,MAAM,IAAI,kCAAkC;GAC3C,aAAa,OAAO,MAAM,WAAW;GACrC,QAAQ,MAAM;GACd,kBAAkB;GAClB;EACD,CAAC;CACF;CAKA,IAAI,0BAA0B,MAAM,GAAG,OAAO;CAC9C,MAAM,IAAI,kCAAkC;EAC3C,aAAa,OAAO,MAAM,WAAW;EACrC,QAAQ,MAAM;EACd,kBAAkB;EAClB,6BAAa,IAAI,UAChB,iEACD;CACD,CAAC;AACF;AAEA,SAAS,YACR,cACA,SACA,QAC4B;CAC5B,OAAO;EACN,IAAI,eAAuB;GAC1B,QAAQ,WAAW,sBAAsB;GACzC,OAAO;EACR;EAGA;CACD;AACD;;;;;;;;;;;;;;;;;;;;;;;;;;AA2BA,SAAS,iBACR,OACA,OAMU;CAOV,IACC,MAAM,QAAQ,WACd,MAAM,OAAO,WAAW,WACvB,UAAU,MAAM,OAAO,UACvB,mBAAmB,OAAO,MAAM,OAAO,MAAM,IAE9C,OAAO;CAER,IAAI,MAAM,WAAW;EACpB,IACC,UAAU,MAAM,aAChB,mBAAmB,OAAO,MAAM,SAAS,GAEzC,OAAO;EAER,OAAO,IAAI,cAAc,MAAM,WAAW,KAAK;CAChD;CACA,IAAI,MAAM,eAAe;EACxB,MAAM,eAAe,wBAAwB,KAAK;EAClD,IAAI,cACH,OAAO;EAER,OAAO,IAAI,YAAY,KAAK;CAC7B;CACA,OAAO;AACR;;;;;;;;;AAUA,SAAS,iBACR,OACA,OACgB;CAChB,MAAM,uBAAO,IAAI,IAAa;CAC9B,IAAI,UAAmB;CACvB,OACC,YAAY,QACZ,OAAO,YAAY,YACnB,CAAC,KAAK,IAAI,OAAO,GAChB;EACD,KAAK,IAAI,OAAO;EAChB,IAAI;EACJ,IAAI;GACH,QAAS,QAAgC;EAC1C,QAAQ;GACP;EACD;EACA,MAAM,QAAQ,MAAM,SAAS,KAAK;EAClC,IAAI,UAAU,QAAW,OAAO;EAChC,UAAU;CACX;AAED;;;;;;;;;AAUA,SAAS,wBACR,OACgC;CAChC,OAAO,iBAAiB,QAAQ,SAC/B,gBAAgB,oBAAoB,OAAO,MAC5C;AACD;;;;;;AAOA,SAAS,mBAAmB,OAAgB,QAA0B;CACrE,IAAI,WAAW,UAAa,WAAW,MACtC,OAAO;CAER,OACC,iBAAiB,QAAQ,OAAO,UAC/B,UAAU,SAAS,OAAO,MAC3B,KAAK;AAEP;;;;ACx2DA,MAAM,wBAAQ,IAAI,IAAyB;CAC1C;CACA;CACA;AACD,CAAC;;;;;;;AAQD,SAAgB,wBAAwB,OAAqC;CAC5E,IAAI,UAAU;CACd,IAAI,kBAAkB;CACtB,MAAM,uBAAO,IAAI,IAAY;CAE7B,OACC,YAAY,SACX,OAAO,YAAY,YAAY,OAAO,YAAY,aAClD;EACD,MAAM,OAAO;EACb,IAAI,KAAK,IAAI,IAAI,GAAG;EACpB,KAAK,IAAI,IAAI;EAEb,IAAI;GACH,MAAM,YAAY;GAKlB,IAAI,UAAU,SAAS,gBAAgB,OAAO;GAC9C,IAAI,UAAU,cAAc,MAAM,OAAO;GACzC,IAAI,UAAU,cAAc,OAAO,kBAAkB;GACrD,UAAU,UAAU;EACrB,QAAQ;GACP,OAAO;EACR;CACD;CAEA,OAAO,kBAAkB,cAAc;AACxC;;AAGA,SAAgB,sBACf,OACA,aAAwC,yBACZ;CAC5B,IAAI;EACH,MAAM,OAAO,WAAW,KAAK;EAC7B,IAAI,MAAM,IAAI,IAAI,GAAG,OAAO,OAAO,OAAO,EAAE,KAAK,CAAC;EAClD,OAAO,OAAO,OAAO;GACpB,MAAM;GACN,iCAAiB,IAAI,UACpB,sDAAsD,OAAO,IAAI,GAClE;EACD,CAAC;CACF,SAAS,iBAAiB;EACzB,OAAO,OAAO,OAAO;GAAE,MAAM;GAAW;EAAgB,CAAC;CAC1D;AACD;;;;;;;;;;;;;;;;;;AC5DA,SAAgB,oBACf,SACA,MACS;CACT,MAAM,cAAc,KAAK,cAAc,MAAM,UAAU;CACvD,MAAM,SAAS,KAAK,IAAI,KAAK,YAAY,WAAW;CACpD,MAAM,SAAS,KAAM,KAAK,OAAO,IAAI;CACrC,OAAO,KAAK,IAAI,GAAG,KAAK,IAAI,KAAK,YAAY,KAAK,MAAM,SAAS,MAAM,CAAC,CAAC;AAC1E;;;;;;;AAQA,SAAgB,oBAAoB,QAAoC;CACvE,aAAa;EACZ,IAAI;GACH,MAAM,QAAQ,OAAO;GACrB,OAAO,OAAO,SAAS,KAAK,IAAI,QAAQ;EACzC,QAAQ;GACP,OAAO;EACR;CACD;AACD;;;;;;;;;;;;AC/BA,SAAgB,2BACf,MACA,QACiC;CACjC,IAAI,WAAW,QAAW,OAAO;CACjC,IAAI,OAAO,SAAS,OAAO,QAAQ,QAAQ,SAAS;CACpD,OAAO,IAAI,SAAS,YAAY;EAC/B,MAAM,gBAAsB,QAAQ,SAAS;EAC7C,OAAO,iBAAiB,SAAS,SAAS,EAAE,MAAM,KAAK,CAAC;EACxD,AAAK,KAAK,MAAM,YAAY;GAC3B,OAAO,oBAAoB,SAAS,OAAO;GAC3C,QAAQ,OAAO;EAChB,CAAC;CACF,CAAC;AACF;;;;;;;;;;ACdA,SAAgB,sBACf,IACA,QACgB;CAChB,IAAI,MAAM,KAAK,OAAO,SAAS,OAAO,QAAQ,QAAQ;CACtD,OAAO,IAAI,SAAS,YAAY;EAC/B,MAAM,aAAmB;GACxB,aAAa,KAAK;GAClB,OAAO,oBAAoB,SAAS,IAAI;GACxC,QAAQ;EACT;EACA,MAAM,QAAQ,WAAW,MAAM,EAAE;EACjC,OAAO,iBAAiB,SAAS,MAAM,EAAE,MAAM,KAAK,CAAC;CACtD,CAAC;AACF;;;;;;;AAQA,SAAgB,sBACf,IACA,QACA,cACgB;CAChB,OAAO,IAAI,SAAe,SAAS,WAAW;EAC7C,IAAI,QAAQ,SAAS;GACpB,OAAO,YAAY,QAAQ,YAAY,CAAC;GACxC;EACD;EACA,IAAI;EACJ,MAAM,QAAQ,iBAAiB;GAC9B,IAAI,WAAW,QAAQ,OAAO,oBAAoB,SAAS,OAAO;GAClE,QAAQ;EACT,GAAG,EAAE;EACL,IAAI,QAAQ;GACX,gBAAgB;IACf,aAAa,KAAK;IAClB,OAAO,YAAY,QAAQ,YAAY,CAAC;GACzC;GACA,OAAO,iBAAiB,SAAS,SAAS,EAAE,MAAM,KAAK,CAAC;EACzD;CACD,CAAC;AACF;;;;;;;;;;;;;;;AC5BA,IAAsB,WAAtB,MAA+B;CAC9B,AAAmB;CACnB,AAAiB;CACjB,AAAiB;CACjB,AAAiB;CACjB,AAAiB;;;;;;;CAQjB,AAAU,sBAAsB;;CAGhC,AAAQ;CAER,AAAU,YAAY,SAAiB,SAA0B;EAChE,MAAM,YAAY,QAAQ,aAAa;EACvC,sBAAsB,SAAS,aAAa,SAAS;EACrD,KAAK,YAAY;EACjB,KAAK,iBAAiB,QAAQ,kBAAkB;EAChD,KAAK,cAAc,QAAQ,eAAe;EAC1C,KAAK,aAAa,QAAQ,cAAc;EACxC,wBAAwB,SAAS,kBAAkB,KAAK,cAAc;EACtE,wBAAwB,SAAS,eAAe,KAAK,WAAW;EAChE,wBAAwB,SAAS,cAAc,KAAK,UAAU;EAC9D,KAAK,SAAS,oBAAoB,QAAQ,UAAU,KAAK,MAAM;CAChE;;;;;;CAcA,MAAM,IAAI,QAAoC;EAC7C,OAAO,CAAC,OAAO,SAAS;GACvB,MAAM,UAAU,MAAM,KAAK,UAAU,MAAM;GAC3C,IAAI,OAAO,SAAS;GACpB,IAAI,YAAY,WACf,MAAM,sBAAsB,KAAK,gBAAgB,MAAM;QAEvD,MAAM,sBAAsB,KAAK,eAAe,GAAG,MAAM;EAE3D;CACD;;;;;;;;;;;;;;CAeA,MAAM,UAAU,QAAsD;EACrE,IAAI,KAAK,iBAAiB,QACzB,OAAO,2BAA2B,KAAK,cAAc,MAAM;EAE5D,MAAM,OAAO,KAAK,KAAK,MAAM;EAC7B,KAAK,eAAe;EACpB,IAAI;GACH,OAAO,MAAM;EACd,UAAU;GACT,KAAK,eAAe;EACrB;CACD;;CAGA,AAAQ,iBAAyB;EAChC,OAAO,oBAAoB,KAAK,IAAI,GAAG,KAAK,mBAAmB,GAAG;GACjE,aAAa,KAAK;GAClB,YAAY,KAAK;GACjB,QAAQ,KAAK;EACd,CAAC;CACF;AACD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACwDA,IAAa,oBAAb,cAA2D,SAAS;CACnE,AAAiB;CACjB,AAAiB;CAIjB,AAAiB;CACjB,AAAiB;CACjB,AAAiB;CACjB,AAAiB;CACjB,AAAiB;CAEjB,YAAY,SAA6C;EACxD,MAAM,qBAAqB,OAAO;EAClC,KAAK,YAAY,yBAChB,qBACA,QAAQ,WACR;GAAC;GAAmB;GAAe;EAAc,CAClD;EACA,KAAK,QAAQ,QAAQ;EACrB,KAAK,UAAU,QAAQ;EACvB,KAAK,kBAAkB,QAAQ;EAC/B,KAAK,QAAQ,QAAQ,gCAAgB,IAAI,KAAK;EAC9C,KAAK,oBACJ,QAAQ;EACT,KAAK,mBACJ,QAAQ;EACT,wBACC,qBACA,qBACA,KAAK,iBACN;EACA,wBACC,qBACA,oBACA,KAAK,gBACN;CACD;;;;;;CAOA,MAAgB,KAAK,QAAsD;EAC1E,OAAO,CAAC,QAAQ,SAAS;GACxB,IAAI;GACJ,IAAI;IACH,QAAQ,MAAM,oBACb,yBACA;KAAE;KAAQ,WAAW,KAAK;IAAiB,IAC1C,YAAY,KAAK,MAAM,IAAI,KAAK,IAAI,GAAG,KAAK,WAAW,OAAO,CAChE;GACD,SAAS,OAAO;IACf,IAAI,QAAQ,SAAS,OAAO;IAC5B,KAAK,uBAAuB;IAC5B,uBAAuB,KAAK,UAAU,YAAY,KAAK,CAAC;IACxD,OAAO;GACR;GACA,IAAI,MAAM,WAAW,GAAG;IACvB,KAAK,sBAAsB;IAC3B,OAAO;GACR;GAKA,IAAI,gBAAgB;GACpB,MAAM,YAAqC,CAAC;GAC5C,KAAK,MAAM,YAAY,OAAO;IAC7B,IAAI,QAAQ,SAAS;IACrB,IAAI;IACJ,IAAI;KACH,MAAM,oBACL,6BACA;MAAE;MAAQ,WAAW,KAAK;KAAkB,IAC3C,YAAY;MACZ,iBAAiB;MACjB,OAAO,KAAK,QAAQ,UAAU,OAAO;KACtC,CACD;KACA,UAAU,KAAK,QAAQ;IACxB,SAAS,OAAO;KACf,IAAI,QAAQ,SAAS;KACrB,gBAAgB;KAChB,MAAM,aAAa,sBAAsB,OAAO,KAAK,eAAe;KACpE,uBACC,KAAK,UAAU,gBAAgB,OAAO,UAAU,UAAU,CAC3D;KAOA,MAAM,mBACL,CAAC,QAAQ,WAAW,gBAAgB,OAAO,YAAY;KACxD,IAAI,WAAW,SAAS,eAAe,kBACtC,IAAI;MACH,MAAM,aAAa,MAAM,oBACxB,gCACA;OAAE;OAAQ,WAAW,KAAK;MAAiB,IAC1C,YACA,KAAK,MAAM,WAAW,SAAS,YAAY,OAAO,OAAO,CAC3D;MACA,IAAI,eAAe,QAClB,uBAAuB,KAAK,UAAU,aAAa,UAAU,CAAC;KAEhE,SAAS,WAAW;MACnB,IAAI,CAAC,QAAQ,SACZ,uBACC,KAAK,UAAU,gBAAgB,WAAW,QAAQ,CACnD;KAEF;IAEF;GACD;GAOA,IAAI,QAAQ;GACZ,IAAI,UAAU,SAAS,GACtB,IAAI;IAKH,MAAM,oBACL,mCACA;KACC,QAJ4B,QAAQ,UAAU,SAAY;KAK1D,WAAW,KAAK;IACjB,IACC,YACA,KAAK,MAAM,cACV,UAAU,KAAK,aAAa,SAAS,UAAU,GAC/C,OACD,CACF;GACD,SAAS,OAAO;IACf,QAAQ;IACR,IAAI,CAAC,QAAQ,SACZ,KAAK,MAAM,YAAY,WACtB,uBACC,KAAK,UAAU,gBAAgB,OAAO,QAAQ,CAC/C;GAGH;GAGD,IAAI,iBAAiB,CAAC,OAAO;IAI5B,KAAK,uBAAuB;IAC5B,OAAO;GACR;GACA,KAAK,sBAAsB;GAG3B,IAAI,QAAQ,SAAS,OAAO;EAC7B;EACA,OAAO;CACR;;;;;CAMA,AAAQ,MAAY;EACnB,MAAM,QAAQ,KAAK,MAAM;EACzB,IAAI,EAAE,iBAAiB,SAAS,OAAO,MAAM,MAAM,QAAQ,CAAC,GAC3D,MAAM,IAAI,UAAU,mDAAmD;EAExE,OAAO;CACR;AACD;;;;;;;;;;;;;;;;;;;;AC5SA,IAAa,wBAAb,MAEA;CACC,AAAiB,0BAAU,IAAI,IAAsC;;CAErE,AAAiB,uBAAO,IAAI,IAAsC;CAClE,AAAiB;CACjB,AAAiB;CACjB,AAAQ,eAAe;CAEvB,YAAY,UAAwC,CAAC,GAAG;EACvD,MAAM,MAAM,QAAQ,uBAAuB;EAC3C,sBAAsB,yBAAyB,uBAAuB,GAAG;EACzE,KAAK,sBAAsB;EAC3B,IAAI,QAAQ,eAAe,QAC1B,0BACC,yBACA,cACA,QAAQ,UACT;EAED,KAAK,aAAa,QAAQ;CAC3B;CAEA,MAAM,SAAS,UAKG;EACjB,MAAM,kBAAkB,QAAQ,SAAS,OAAO,SAAS,GAAG;EAC5D,IACC,CAAC,KAAK,QAAQ,IAAI,eAAe,KACjC,KAAK,eAAe,UACpB,KAAK,QAAQ,OAAO,KAAK,KAAK,QAAQ,KAAK,YAE3C,MAAM,IAAI,8BAA8B;GACvC,OAAO;GACP,UAAU;GACV,OAAO,KAAK;GACZ,SAAS,KAAK,QAAQ,OAAO,KAAK,KAAK;GACvC,WAAW;EACZ,CAAC;EAEF,MAAM,WAAW,KAAK;EAItB,KAAK,QAAQ,IAAI,iBAAiB;GACjC,YAAY,YAAY;GACxB,OAAO,SAAS;GAChB,KAAK,SAAS;GACd,OAAO,IAAI,KAAK,SAAS,KAAK;GAC9B,SAAS,gBAAgB,SAAS,OAAO;GACzC,UAAU;GACV;EACD,CAAC;CACF;CAEA,MAAM,OAAO,OAAe,KAA4B;EACvD,KAAK,QAAQ,OAAO,QAAQ,OAAO,GAAG,CAAC;CACxC;CAEA,MAAM,IACL,KACA,OACgD;EAChD,IAAI,CAAC,OAAO,UAAU,KAAK,KAAK,QAAQ,GACvC,MAAM,IAAI,MACT,6DAA6D,OAC9D;EAID,IAAI,UAAU,GAAG,OAAO,CAAC;EACzB,OAAO,CAAC,GAAG,KAAK,QAAQ,OAAO,CAAC,CAAC,CAC/B,QAAQ,aAAa,SAAS,MAAM,QAAQ,KAAK,IAAI,QAAQ,CAAC,CAAC,CAC/D,MACC,GAAG,MACH,EAAE,MAAM,QAAQ,IAAI,EAAE,MAAM,QAAQ,KAAK,EAAE,WAAW,EAAE,QAC1D,CAAC,CACA,MAAM,GAAG,KAAK,CAAC,CACf,KAAK,aAAa,SAAS,QAAQ,CAAC;CACvC;CAEA,MAAM,cAAc,aAAmD;EACtE,KAAK,MAAM,cAAc,aAAa;GACrC,KAAK,KAAK,OAAO,UAAU;GAC3B,KAAK,MAAM,CAAC,KAAK,aAAa,KAAK,SAClC,IAAI,SAAS,eAAe,YAAY;IACvC,KAAK,QAAQ,OAAO,GAAG;IACvB;GACD;EAEF;CACD;CAEA,MAAM,WACL,YACA,OACoD;EACpD,KAAK,MAAM,CAAC,KAAK,aAAa,KAAK,SAAS;GAC3C,IAAI,SAAS,eAAe,YAAY;GACxC,SAAS,YAAY;GAErB,IAAI,UAAU,QAAW,SAAS,YAAY,OAAO,KAAK;GAC1D,IAAI,SAAS,YAAY,KAAK,qBAAqB;IAClD,KAAK,QAAQ,OAAO,GAAG;IACvB,KAAK,KAAK,IAAI,SAAS,YAAY,QAAQ;IAC3C,OAAO,aAAa,QAAQ;GAC7B;GACA;EACD;CAID;CAEA,MAAM,cAAoE;EACzE,OAAO,CAAC,GAAG,KAAK,KAAK,OAAO,CAAC,CAAC,CAC5B,MAAM,GAAG,MAAM,EAAE,WAAW,EAAE,QAAQ,CAAC,CACvC,IAAI,YAAY;CACnB;AACD;AAEA,SAAS,aACR,UAC+B;CAC/B,OAAO;EACN,GAAG,SAAS,QAAQ;EACpB,GAAI,SAAS,cAAc,SACxB,CAAC,IACD,EAAE,WAAW,SAAS,UAAU;CACpC;AACD;AAEA,SAAS,SACR,UACwB;CACxB,OAAO;EACN,YAAY,SAAS;EACrB,OAAO,SAAS;EAChB,KAAK,SAAS;EACd,OAAO,IAAI,KAAK,SAAS,KAAK;EAC9B,SAAS,gBAAgB,SAAS,OAAO;EACzC,UAAU,SAAS;CACpB;AACD;;AAGA,SAAS,QAAQ,OAAe,KAAqB;CACpD,OAAO,GAAG,MAAM,QAAQ;AACzB;;;;;ACxMA,IAAa,+BAAb,cAAkD,YAAyC;CAEzE;CACA;CAFjB,YACC,AAAgB,OAChB,AAAgB,WACf;EACD,MAAM;GACL,MAAM;GACN,SAAS,8BAA8B,MAAM,QAAQ,UAAU;EAChE,CAAC;EANe;EACA;CAMjB;AACD;;AAGA,IAAa,qCAAb,cAAwD,YAAgD;CAEtF;CACA;CAFjB,YACC,AAAgB,OAChB,AAAgB,WACf;EACD,MAAM;GACL,MAAM;GACN,SAAS,qCAAqC,UAAU,UAAU,MAAM;EACzE,CAAC;EANe;EACA;CAMjB;AACD;;AAGA,IAAa,sCAAb,cAAyD,eAAoD;CAC5G,YAAY,SAAiB,OAAiB;EAC7C,MAAM,qCAAqC,SAAS,KAAK;CAC1D;AACD;;AAGA,IAAa,mCAAb,cAAsD,eAAiD;CACtG,YAAY,SAAiB,OAAiB;EAC7C,MAAM,kCAAkC,SAAS,KAAK;CACvD;AACD;;AAGA,IAAa,oCAAb,cAAuD,eAAkD;CACxG,YAAY,SAAiB,OAAiB;EAC7C,MAAM,mCAAmC,SAAS,KAAK;CACxD;AACD;;AAGA,IAAa,iCAAb,cAAoD,eAA+C;CAClG,YAAY,SAAiB,OAAiB;EAC7C,MAAM,gCAAgC,SAAS,KAAK;CACrD;AACD;;AAGA,IAAa,0CAAb,cAA6D,eAAyD;CACrH,YAAY,SAAiB,OAAiB;EAC7C,MAAM,0CAA0C,SAAS,KAAK;CAC/D;AACD;;AAGA,IAAa,qCAAb,cAAwD,eAAmD;CAC1G,YAAY,SAAiB,OAAiB;EAC7C,MAAM,oCAAoC,SAAS,KAAK;CACzD;AACD;;AAGA,IAAa,6CAAb,cAAgE,eAA4D;CAC3H,cAAc;EACb,MACC,6CACA,kEACD;CACD;AACD;;;;ACzDA,MAAM,gCAAgC;AACtC,MAAM,gCAAgC;AACtC,MAAM,qCAAqC;AAO3C,SAAgB,yBACf,SAC4C;CAC5C,IAAI;EAKH,OAAO,WAJe,4BACrB,WAAW,CAAC,GACZ,iCAGY,CACb;CACD,SAAS,OAAO;EACf,IAAI,iBAAiB,oCACpB,MAAM;EAEP,MAAM,IAAI,mCACT,mFACA,KACD;CACD;AACD;AAEA,SAAgB,uBACf,OACgC;CAChC,IAAI;EACH,OAAO,WACN,4BAA4B,OAAO,6BAA6B,CACjE;CACD,SAAS,OAAO;EACf,IAAI,iBAAiB,gCACpB,MAAM;EAEP,MAAM,IAAI,+BACT,uEACA,KACD;CACD;AACD;AAEA,SAAgB,yBACf,SACkC;CAClC,IAAI;EACH,OAAO,WACN,4BAA4B,SAAS,+BAA+B,CACrE;CACD,SAAS,OAAO;EACf,IAAI,iBAAiB,kCACpB,MAAM;EAEP,MAAM,IAAI,iCACT,yEACA,KACD;CACD;AACD;AAEA,SAAS,gCACR,SACA,OACmC;CACnC,OAAO,IAAI,iCAAiC,SAAS,KAAK;AAC3D;AAEA,SAAS,8BACR,SACA,OACiC;CACjC,OAAO,IAAI,+BAA+B,SAAS,KAAK;AACzD;AAEA,SAAS,kCACR,SACA,OACqC;CACrC,OAAO,IAAI,mCAAmC,SAAS,KAAK;AAC7D;AAEA,SAAS,4BACR,OACA,cACA,uBAAO,IAAI,QAAyB,GACpC,YAAwC;CAAE,OAAO;CAAG,YAAY;AAAE,GAClE,QAAQ,GACC;CACT,IAAI,OAAO,UAAU,YACpB,MAAM,aAAa,qDAAqD;CAEzE,IAAI,UAAU,QAAQ,OAAO,UAAU,UAAU,OAAO;CAExD,MAAM,SAAS;CACf,IAAI,QAAQ,+BACX,MAAM,aACL,oDAAoD,8BAA8B,EACnF;CAED,MAAM,WAAW,KAAK,IAAI,MAAM;CAChC,IAAI,aAAa,QAAW,OAAO;CACnC,UAAU,SAAS;CACnB,IAAI,UAAU,QAAQ,+BACrB,MAAM,aACL,0CAA0C,8BAA8B,eAAe,OAAO,EAAE,eACjG;CAED,MAAM,wBAAwB,uBAC7B,QACA,OAAO,WACR;CACA,IACC,0BAA0B,UAC1B,EAAE,WAAW,wBAEb,MAAM,aACL,yDACD;CAGD,IAAI,MAAM,QAAQ,KAAK,GAAG;EACzB,IAAI,CAAC,0BAA0B,OAAO,eAAe,KAAK,CAAC,GAC1D,MAAM,aACL,4DACD;EAED,MAAM,SAAoB,IAAI,MAAM,MAAM,MAAM;EAChD,KAAK,IAAI,QAAQ,MAAM;EAEvB,KAAK,MAAM,OAAO,0BACjB,QACA,cACA,SACD,GAAG;GACF,MAAM,aAAa,OAAO,yBAAyB,QAAQ,GAAG;GAC9D,IAAI,CAAC,YAAY;GAEjB,IAAI,EAAE,WAAW,aAChB,MAAM,aACL,yDACD;GAGD,IAAI,QAAQ,UAAU;GAEtB,WAAW,QAAQ,4BAClB,WAAW,OACX,cACA,MACA,WACA,QAAQ,CACT;GACA,OAAO,eAAe,QAAQ,KAAK,UAAU;EAC9C;EACA,OAAO;CACR;CAEA,MAAM,YAAY,OAAO,eAAe,MAAM;CAC9C,IAAI,cAAc,QAAQ,CAAC,2BAA2B,SAAS,GAC9D,MAAM,aACL,4DACD;CAGD,MAAM,MAAM,OAAO,UAAU,SAAS,KAAK,MAAM;CACjD,IAAI,gBAAgB,QAAQ,GAAG,KAAK,YAAY,OAAO,MAAM,GAC5D,MAAM,aACL,sCAAsC,IAAI,MAAM,GAAG,EAAE,EAAE,gBACxD;CAGD,MAAM,SAAS,OAAO,OAAO,cAAc,OAAO,OAAO,OAAO,SAAS;CACzE,KAAK,IAAI,QAAQ,MAAM;CAEvB,KAAK,MAAM,OAAO,0BACjB,QACA,cACA,SACD,GAAG;EACF,MAAM,aAAa,OAAO,yBAAyB,QAAQ,GAAG;EAC9D,IAAI,CAAC,YAAY;EAEjB,IAAI,EAAE,WAAW,aAChB,MAAM,aACL,yDACD;EAGD,WAAW,QAAQ,4BAClB,WAAW,OACX,cACA,MACA,WACA,QAAQ,CACT;EACA,OAAO,eAAe,QAAQ,KAAK,UAAU;CAC9C;CAEA,OAAO;AACR;AAEA,SAAS,0BACR,OACA,cACA,WACyB;CACzB,MAAM,OAAO,QAAQ,QAAQ,KAAK;CAClC,UAAU,cAAc,KAAK;CAC7B,IAAI,UAAU,aAAa,oCAC1B,MAAM,aACL,0CAA0C,mCAAmC,eAAe,OAAO,EAAE,iBACtG;CAED,OAAO;AACR;AAEA,SAAgB,SACf,OACwC;CACxC,OAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAC3E;AAEA,SAAgB,cACf,OACwC;CACxC,IAAI,CAAC,SAAS,KAAK,GAAG,OAAO;CAE7B,MAAM,YAAY,OAAO,eAAe,KAAK;CAC7C,OAAO,cAAc,QAAQ,2BAA2B,SAAS;AAClE;AAEA,SAAS,0BAA0B,WAAmC;CACrE,IAAI,cAAc,QAAQ,CAAC,MAAM,QAAQ,SAAS,GAAG,OAAO;CAC5D,IAAI,CAAC,gCAAgC,WAAW,OAAO,GAAG,OAAO;CAEjE,MAAM,kBAAkB,OAAO,eAAe,SAAS;CACvD,OACC,oBAAoB,QAAQ,2BAA2B,eAAe;AAExE;AAEA,SAAS,2BAA2B,WAA4B;CAC/D,OACC,OAAO,eAAe,SAAS,MAAM,QACrC,gCAAgC,WAAW,QAAQ;AAErD;AAEA,SAAgB,OACf,OACA,KACiB;CACjB,OAAO,OAAO,OAAO,OAAO,GAAG;AAChC;;;;AC/QA,MAAM,iDAA2D,IAAI,IAAI;CACxE;CACA;CACA;CACA;AACD,CAAC;AACD,MAAM,iDAA2D,IAAI,IAAI;CACxE;CACA;CACA;AACD,CAAC;AACD,MAAM,iDAA2D,IAAI,IAAI;CACxE;CACA;CACA;AACD,CAAC;AAED,SAAgB,4BAMf,YAC6D;CAC7D,MAAM,SAAS,oCACd,YACA,QACD;CACA,MAAM,eAAe,OAAO,OAAO,IAAI;CAIvC,KAAK,MAAM,SAAS,OAAO,KAAK,MAAM,GAAe;EACpD,MAAM,OAAO,oCACZ,QACA,KACD;EACA,MAAM,cAAc,4CACnB,MACA,IACD;EACA,MAAM,oBAAoB,OAAO,OAAO,IAAI;EAS5C,KAAK,MAAM,aAAa,OAAO,KAC9B,eAAe,CAAC,CACjB,GAAuB;GACtB,MAAM,aAAa,oCAClB,aACA,SACD;GAQA,IAAI,YAAY;IACf,MAAM,mBAAmB,OAAO,OAAO;KACtC,QAAQ,oCAAoC,YAAY,QAAQ;KAChE,OAAO,4CACN,YACA,OACD;KACA,QAAQ,4CACP,YACA,QACD;IACD,CAAC;IAMD,OAAO,eAAe,mBAAmB,WAAW;KACnD,OAAO;KACP,YAAY;IACb,CAAC;GACF;EACD;EAEA,OAAO,eAAe,cAAc,OAAO;GAC1C,OAAO,OAAO,OAAO;IACpB,UAAU,4CAA4C,MAAM,UAAU;IACtE,iBAAiB,4CAChB,MACA,iBACD;IACA,IAAI,OAAO,OAAO,iBAAiB;GACpC,CAAC;GACD,YAAY;EACb,CAAC;CACF;CAEA,OAAO,OAAO,OAAO;EACpB,SAAS,oCACR,YACA,SACD;EACA,gBAAgB,oCACf,YACA,gBACD;EACA,kBAAkB,4CACjB,YACA,kBACD;EAGA,QAAQ,OAAO,OAAO,YAAY;CACnC,CAAC;AACF;;;;;;;;;;;AAYA,MAAM,sCAAsB,IAAI,QAAgB;;;;;;;AA4BhD,SAAgB,oCAMf,YAC6D;CAC7D,IAAI,oBAAoB,IAAI,UAAU,GAAG,OAAO;CAChD,gCAAgC,UAAU;CAC1C,MAAM,SAAS,4BAA4B,UAAU;CAMrD,gCAAgC,MAAM;CACtC,OAAO;AACR;;;;;;;;;;;;;;;;;;;;;AAsBA,SAAgB,+BAMf,YACqE;CACrE,MAAM,SAAS,oCAAoC,UAAU;CAC7D,oBAAoB,IAAI,MAAM;CAC9B,OAAO;AAMR;AAEA,SAAgB,cAMf,YACA,OACA,OACkE;CAClE,MAAM,cAAc,WAAW,OAAO,MAAM,CAAC;CAC7C,IAAI,CAAC,eAAe,CAAC,OAAO,aAAa,MAAM,IAAI,GAAG,OAAO;CAE7D,OAAO,YAAY,MAAM;AAG1B;AAEA,SAAgB,gCAMf,YACO;CACP,MAAM,YAAY;CAClB,IAAI,CAAC,cAAc,SAAS,GAC3B,MAAM,IAAI,oCACT,mDACD;CAED,4CACC,WACA,8BACD;CAEA,MAAM,UAAU,oCAAoC,WAAW,SAAS;CACxE,IAAI,OAAO,YAAY,UACtB,MAAM,IAAI,oCACT,8DACD;CAGD,IACC,OAAO,oCAAoC,WAAW,gBAAgB,MACtE,YAEA,MAAM,IAAI,oCACT,iEACD;CAGD,MAAM,mBAAmB,4CACxB,WACA,kBACD;CACA,IACC,qBAAqB,UACrB,OAAO,qBAAqB,YAE5B,MAAM,IAAI,oCACT,mEACD;CAGD,MAAM,kBAAkB,oCACvB,WACA,QACD;CACA,IAAI,CAAC,cAAc,eAAe,GACjC,MAAM,IAAI,oCACT,6DACD;CAED,MAAM,SAAuC;CAC7C,sCAAsC,QAAQ,OAAO;CAErD,IAAI,CAAC,OAAO,QAAQ,OAAO,GAC1B,MAAM,IAAI,oCACT,iCAAiC,QAAQ,kBAC1C;CAGD,KAAK,MAAM,SAAS,OAAO,KAAK,MAAM,GAAG;EACxC,MAAM,OAAgB,oCAAoC,QAAQ,KAAK;EACvE,IAAI,CAAC,cAAc,IAAI,GACtB,MAAM,IAAI,oCACT,yBAAyB,MAAM,wCAChC;EAED,4CACC,MACA,8BACD;EAEA,MAAM,WAAoB,4CACzB,MACA,UACD;EACA,IAAI,aAAa,UAAa,OAAO,aAAa,WACjD,MAAM,IAAI,oCACT,yBAAyB,MAAM,mCAChC;EAGD,MAAM,kBACL,4CAA4C,MAAM,iBAAiB;EACpE,IACC,oBAAoB,UACpB,OAAO,oBAAoB,YAE3B,MAAM,IAAI,oCACT,yBAAyB,MAAM,sCAChC;EAGD,MAAM,cAAuB,4CAC5B,MACA,IACD;EACA,IAAI,gBAAgB,UAAa,CAAC,cAAc,WAAW,GAC1D,MAAM,IAAI,oCACT,yBAAyB,MAAM,sCAChC;EAED,IAAI,cAAc,WAAW,GAC5B,sCAAsC,aAAa,OAAO;EAG3D,MAAM,aAAa,OAAO,KAAK,eAAe,CAAC,CAAC;EAChD,IAAI,aAAa,QAAQ,WAAW,SAAS,GAC5C,MAAM,IAAI,oCACT,kCAAkC,MAAM,8BACzC;EAGD,KAAK,MAAM,aAAa,YAAY;GACnC,MAAM,aAAsB,oCAC3B,aACA,SACD;GACA,IAAI,CAAC,cAAc,UAAU,GAC5B,MAAM,IAAI,oCACT,2BAA2B,MAAM,QAAQ,UAAU,0BACpD;GAED,4CACC,YACA,8BACD;GAEA,MAAM,SAAkB,oCACvB,YACA,QACD;GACA,IAAI,OAAO,WAAW,UACrB,MAAM,IAAI,oCACT,2BAA2B,MAAM,QAAQ,UAAU,8BACpD;GAGD,IAAI,CAAC,OAAO,QAAQ,MAAM,GACzB,MAAM,IAAI,oCACT,2BAA2B,MAAM,QAAQ,UAAU,2BAA2B,OAAO,GACtF;GAGD,MAAM,QAAiB,4CACtB,YACA,OACD;GACA,IAAI,UAAU,UAAa,OAAO,UAAU,YAC3C,MAAM,IAAI,oCACT,2BAA2B,MAAM,QAAQ,UAAU,4BACpD;GAGD,MAAM,SAAkB,4CACvB,YACA,QACD;GACA,IAAI,WAAW,UAAa,OAAO,WAAW,YAC7C,MAAM,IAAI,oCACT,2BAA2B,MAAM,QAAQ,UAAU,6BACpD;EAEF;CACD;AACD;AAEA,SAAS,4CACR,OACA,aACO;CACP,KAAK,MAAM,OAAO,QAAQ,QAAQ,KAAK,GAAG;EACzC,MAAM,aAAa,OAAO,yBAAyB,OAAO,GAAG;EAC7D,IAAI,eAAe,UAAa,EAAE,WAAW,aAC5C,MAAM,IAAI,oCACT,8DACD;EAED,IAAI,gBAAgB,UAAa,CAAC,YAAY,IAAI,GAAG,GACpD,MAAM,IAAI,oCACT,wDAAwD,OAAO,GAAG,EAAE,GACrE;CAEF;AACD;AAEA,SAAS,sCACR,OACA,WACO;CACP,4CAA4C,KAAK;CAEjD,KAAK,MAAM,OAAO,QAAQ,QAAQ,KAAK,GAAG;EACzC,MAAM,aAAa,OAAO,yBAAyB,OAAO,GAAG;EAC7D,IAAI,OAAO,QAAQ,YAAY,YAAY,eAAe,MACzD,MAAM,IAAI,oCACT,kBAAkB,UAAU,6CAC7B;CAEF;AACD;AAEA,SAAS,oCACR,OACA,KACU;CACV,MAAM,aAAa,OAAO,yBAAyB,OAAO,GAAG;CAC7D,IAAI,eAAe,UAAa,EAAE,WAAW,aAC5C,MAAM,IAAI,oCACT,8DACD;CAGD,OAAO,WAAW;AACnB;AAEA,SAAS,4CACR,OACA,KACU;CACV,MAAM,aAAa,OAAO,yBAAyB,OAAO,GAAG;CAC7D,IAAI,eAAe,QAAW,OAAO;CACrC,IAAI,EAAE,WAAW,aAChB,MAAM,IAAI,oCACT,8DACD;CAGD,OAAO,WAAW;AACnB;;;;AC1cA,MAAM,gDAA0D,IAAI,IAAI,CACvE,WACA,SACD,CAAC;AAED,SAAgB,6BAMf,YACA,UAC0C;CAC1C,8BAA8B,YAAY,QAAQ;CAClD,MAAM,mBAAmB,4BACxB,QACD;CAGA,8BAA8B,YAAY,gBAAgB;CAC1D,uCAAuC,YAAY,gBAAgB;CACnE,OAAO;AACR;AAEA,SAAgB,+CAIf,OACA,SAC0C;CAC1C,OAAO,OAAO,OAAO;EAAE;EAAO;CAAQ,CAAC;AACxC;AAEA,SAAgB,4BAGd,UAG0C;CAC3C,OAAO,OAAO,OAAO;EACpB,OAAO,+BAA+B,QAAQ;EAC9C,SAAS,yBACR,iCAAiC,QAAQ,CAC1C;CACD,CAAC;AACF;AAEA,SAAgB,8BAMf,YACA,UACO;CACP,IAAI,CAAC,SAAS,QAAQ,GACrB,MAAM,IAAI,kCACT,4CACD;CAGD,MAAM,QAAQ,+BAA+B,QAAQ;CACrD,iCAAiC,QAAQ;CAEzC,IAAI,CAAC,OAAO,WAAW,QAAQ,KAAK,GACnC,MAAM,IAAI,kCACT,kCAAkC,MAAM,kBACzC;AAEF;AAEA,SAAgB,uCAMf,YACA,UACO;CACP,MAAM,YAAY,WAAW,OAAO,SAAS;CAC7C,IAAI,UAAU,oBAAoB,QAAW;EAC5C,MAAM,eAAe,UAAU,gBAAgB;GAC9C,OAAO,SAAS;GAChB,SAAS,SAAS;EACnB,CAAC;EACD,IAAI,OAAO,iBAAiB,WAC3B,MAAM,IAAI,oCACT,yBAAyB,SAAS,MAAM,yCACzC;EAED,IAAI,CAAC,cACJ,MAAM,IAAI,kCACT,qEAAqE,SAAS,MAAM,GACrF;CAEF;CAEA,IAAI,WAAW,qBAAqB,QAAW;CAE/C,MAAM,QAAQ,WAAW,iBAAiB,QAAQ;CAClD,IAAI,OAAO,UAAU,WACpB,MAAM,IAAI,oCACT,wDACD;CAGD,IAAI,CAAC,OACJ,MAAM,IAAI,kCACT,0DAA0D,SAAS,MAAM,GAC1E;AAEF;AAEA,SAAS,+BAAsD,UAEpD;CACV,MAAM,kBAAkB,OAAO,yBAAyB,UAAU,OAAO;CACzE,IACC,oBAAoB,UACpB,EAAE,WAAW,oBACb,OAAO,gBAAgB,UAAU,UAEjC,MAAM,IAAI,kCACT,+DACD;CAGD,OAAO,gBAAgB;AACxB;AAEA,SAAS,iCAA2C,UAEvC;CACZ,MAAM,oBAAoB,OAAO,yBAChC,UACA,SACD;CACA,IAAI,sBAAsB,UAAa,EAAE,WAAW,oBACnD,MAAM,IAAI,kCACT,qEACD;CAGD,OAAO,kBAAkB;AAC1B;AAEA,SAAgB,2BACf,OACsC;CACtC,IAAI,CAAC,qBAAqB,KAAK,GAC9B,MAAM,IAAI,+BACT,4DACD;AAEF;AAEA,SAAgB,qBACf,OAC8B;CAC9B,IAAI,CAAC,SAAS,KAAK,GAAG,OAAO;CAE7B,MAAM,iBAAiB,OAAO,yBAAyB,OAAO,MAAM;CACpE,OACC,mBAAmB,UACnB,WAAW,kBACX,OAAO,eAAe,UAAU;AAElC;AAEA,SAAgB,mCACf,QAGgE;CAChE,IAAI,OAAO,WAAW,WAAW,OAAO,EAAE,SAAS,OAAO;CAC1D,IAAI,kBAAkB,aACrB,OAAO;EAAE,SAAS;EAAO,WAAW;CAAO;CAG5C,MAAM,IAAI,wCACT,+DACD;AACD;AAEA,SAAgB,+BACf,QACO;CACP,IAAI,WAAW,QAAW;CAE1B,IAAI,CAAC,cAAc,MAAM,GACxB,MAAM,IAAI,mCACT,gEACD;CAGD,KAAK,MAAM,OAAO,QAAQ,QAAQ,MAAM,GAAG;EAC1C,IAAI,CAAC,8BAA8B,IAAI,GAAG,GACzC,MAAM,IAAI,mCACT,uDAAuD,OAAO,GAAG,EAAE,GACpE;EAED,MAAM,aAAa,OAAO,yBAAyB,QAAQ,GAAG;EAC9D,IAAI,eAAe,UAAa,EAAE,WAAW,aAC5C,MAAM,IAAI,mCACT,6DACD;CAEF;CAEA,MAAM,UAAU,kCAAkC,MAAM;CACxD,IAAI,YAAY,UAAa,CAAC,MAAM,QAAQ,OAAO,GAClD,MAAM,IAAI,mCACT,kEACD;AAEF;AAEA,SAAgB,kCACf,QAG4D;CAC5D,IAAI,WAAW,QAAW,OAAO,EAAE,YAAY,MAAM;CAErD,MAAM,oBAAoB,OAAO,yBAAyB,QAAQ,SAAS;CAC3E,IAAI,sBAAsB,QAAW,OAAO,EAAE,YAAY,MAAM;CAChE,IAAI,EAAE,WAAW,oBAChB,MAAM,IAAI,mCACT,yEACD;CAGD,OAAO;EAAE,YAAY;EAAM,SAAS,kBAAkB;CAAkB;AACzE;AAEA,SAAgB,kCACf,QACiC;CACjC,IAAI,WAAW,QAAW,OAAO;CAEjC,MAAM,oBAAoB,OAAO,yBAAyB,QAAQ,SAAS;CAC3E,IAAI,sBAAsB,QAAW,OAAO;CAC5C,IAAI,EAAE,WAAW,oBAChB,MAAM,IAAI,mCACT,yEACD;CAGD,OAAO,kBAAkB;AAC1B;;;;;ACpPA,SAAgB,mCAMf,YAC0C;CAE1C,OAAO,+CADkB,oCAAoC,UACQ,CAAC;AACvE;AAEA,SAAgB,+CAMf,YAC0C;CAC1C,MAAM,WAAW,4BAA8C;EAC9D,OAAO,WAAW;EAClB,SAAS,WAAW,eAAe;CACpC,CAAC;CACD,uCAAuC,YAAY,QAAQ;CAC3D,OAAO;AACR;;;;;;;;AASA,SAAgB,yBAMf,YACA,UACA,OACU;CACV,MAAM,mBAAmB,oCAAoC,UAAU;CAKvE,OAAO,iCACN,kBALuB,6BACvB,kBACA,QAIc,GACd,KACD;AACD;AAEA,SAAgB,iCAMf,YACA,UACA,OACU;CACV,IAAI,CAAC,qBAAqB,KAAK,GAAG,OAAO;CAGzC,IADkB,WAAW,OAAO,SAAS,MAChC,CAAC,aAAa,MAAM,OAAO;CAExC,MAAM,aAAa,cAAc,YAAY,SAAS,OAAO,KAAK;CAClE,IAAI,CAAC,YAAY,OAAO;CAExB,MAAM,eAAe,uBAAuB,KAAK;CACjD,IAAI,CAAC,WAAW,OAAO,OAAO;CAQ9B,OAAO,mCANa,WAAW,MAAM;EACpC,OAAO,SAAS;EAChB,SAAS,SAAS;EAClB,OAAO;CACR,CAEoD,CAAC,CAAC,CAAC;AACxD;;;;;;;;AASA,SAAgB,sBAMf,YACA,UACA,OACqD;CACrD,MAAM,mBAAmB,oCAAoC,UAAU;CAKvE,OAAO,8BACN,kBALuB,6BACvB,kBACA,QAIc,GACd,KACD;AACD;AAEA,SAAgB,8BAMf,YACA,UACA,OACqD;CACrD,2BAA2B,KAAK;CAEhC,MAAM,OAAO,SAAS;CAEtB,MAAM,aADY,WAAW,OAAO,KAE1B,CAAC,aAAa,OACpB,SACA,cAAc,YAAY,MAAM,KAAK;CAEzC,IAAI,CAAC,YACJ,MAAM,IAAI,6BAA6B,MAAM,MAAM,IAAI;CAGxD,MAAM,eAAe,uBAAuB,KAAK;CASjD,MAAM,gBAAgB,mCAPrB,WAAW,UAAU,SAClB,OACA,WAAW,MAAM;EACjB,OAAO;EACP,SAAS,SAAS;EAClB,OAAO;CACR,CAAC,CACgE;CAEpE,IAAI,CAAC,cAAc,SAAS;EAC3B,IAAI,cAAc,cAAc,QAC/B,MAAM,cAAc;EAErB,MAAM,IAAI,mCAAmC,MAAM,aAAa,IAAI;CACrE;CAEA,MAAM,SAAS,WAAW,SAAS;EAClC,OAAO;EACP,SAAS,SAAS;EAClB,OAAO;CACR,CAAC;CACD,+BAA+B,MAAM;CACrC,MAAM,gBAAgB,kCAAkC,MAAM;CAC9D,MAAM,cAAc,cAAc,aAC/B,cAAc,UACd,SAAS;CACZ,MAAM,eACL,gBAAgB,SAAS,UACtB,+CACA,WAAW,QACX,SAAS,OACV,IACC,4BAA8C;EAC9C,OAAO,WAAW;EAClB,SAAS;CACV,CAAC;CACJ,uCAAuC,YAAY,YAAY;CAK/D,OAAO,OAAO,OAAO;EACpB;EACA,IAAI,WAAW;EACf,UAAU;EACV,SAAS,yBACR,kCAAkC,MAAM,CACzC;CACD,CAAC;AACF;;;;;;;;;AC/KA,SAAgB,+BAMf,YAC0D;CAI1D,MAAM,mBAAmB,oCAAoC,UAAU;CACvE,MAAM,SAAU,OAAO,KAAK,iBAAiB,MAAM,CAAC,CAAc,KACjE,cACD;CACA,MAAM,2BAAW,IAAI,IAAsB;CAC3C,MAAM,2BAAW,IAAI,IAAsB;CAC3C,MAAM,cAGA,CAAC;CAEP,KAAK,MAAM,SAAS,QAAQ;EAC3B,SAAS,IAAI,OAAO,CAAC,CAAC;EACtB,SAAS,IAAI,OAAO,CAAC,CAAC;CACvB;CAEA,KAAK,MAAM,SAAS,QAAQ;EAC3B,MAAM,mBAAmB,iBAAiB,OAAO,MAAM,CAAC;EACxD,MAAM,aACL,OAAO,KAAK,oBAAoB,CAAC,CAAC,CAAC,CAClC,KAAK,cAAc;EAErB,KAAK,MAAM,aAAa,YAAY;GACnC,MAAM,aAAa,mBAAmB;GACtC,IAAI,eAAe,QAAW;GAE9B,SAAS,IAAI,KAAK,CAAC,EAAE,KAAK,WAAW,MAAM;GAC3C,SAAS,IAAI,WAAW,MAAM,CAAC,EAAE,KAAK,KAAK;GAC3C,YAAY,KACX,OAAO,OAAO;IACb;IACA;IACA,QAAQ,WAAW;IACnB,SAAS,WAAW,UAAU;GAC/B,CAAC,CACF;EACD;CACD;CAEA,MAAM,wBAAwB,WAC7B,CAAC,iBAAiB,OAAO,GACzB,QACD;CAIA,MAAM,yBAAyB,WAHR,OAAO,QAC5B,UAAU,iBAAiB,OAAO,MAAM,CAAC,aAAa,IAED,GAAG,QAAQ;CAClE,MAAM,cAA2D,CAAC;CAElE,KAAK,MAAM,SAAS,QACnB,IAAI,CAAC,sBAAsB,IAAI,KAAK,GACnC,YAAY,KAAK,OAAO,OAAO;EAAE,MAAM;EAAqB;CAAM,CAAC,CAAC;CAGtE,KAAK,MAAM,SAAS,QACnB,IACC,iBAAiB,OAAO,MAAM,CAAC,aAAa,QAC5C,SAAS,IAAI,KAAK,CAAC,EAAE,WAAW,GAEhC,YAAY,KAAK,OAAO,OAAO;EAAE,MAAM;EAAuB;CAAM,CAAC,CAAC;CAGxE,KAAK,MAAM,SAAS,QACnB,IAAI,CAAC,uBAAuB,IAAI,KAAK,GACpC,YAAY,KAAK,OAAO,OAAO;EAAE,MAAM;EAAoB;CAAM,CAAC,CAAC;CAIrE,OAAO,OAAO,OAAO;EACpB,aAAa,OAAO,OAAO,WAAW;EACtC,aAAa,OAAO,OAAO,WAAW;EACtC,6BAA6B,OAAO,OACnC,OAAO,QAAQ,UAAU,sBAAsB,IAAI,KAAK,CAAC,CAC1D;EACA,wBAAwB,OAAO,OAC9B,OAAO,QAAQ,UAAU,uBAAuB,IAAI,KAAK,CAAC,CAC3D;CACD,CAAC;AACF;AAEA,SAAS,WACR,aACA,OACsB;CACtB,MAAM,0BAAU,IAAI,IAAY;CAChC,MAAM,UAAU,CAAC,GAAG,WAAW;CAE/B,OAAO,QAAQ,SAAS,GAAG;EAC1B,MAAM,QAAQ,QAAQ,IAAI;EAC1B,IAAI,UAAU,UAAa,QAAQ,IAAI,KAAK,GAAG;EAE/C,QAAQ,IAAI,KAAK;EACjB,KAAK,MAAM,QAAQ,MAAM,IAAI,KAAK,KAAK,CAAC,GACvC,IAAI,CAAC,QAAQ,IAAI,IAAI,GAAG,QAAQ,KAAK,IAAI;CAE3C;CAEA,OAAO;AACR;AAEA,SAAS,eAAe,MAAc,OAAuB;CAC5D,OAAO,OAAO,QAAQ,KAAK,OAAO,QAAQ,IAAI;AAC/C;;;;;;;;;;ACjGA,IAAa,qBAAb,MAKE;CACD,AAAiB;CAOjB;CACA,cAAc;CASd,YACC,YACA,GAAG,eACF;EAGD,KAAK,aAAa,oCAAoC,UAAU;EAMhE,MAAM,CAAC,oBAAoB;EAC3B,IAAI,qBAAqB,QAIxB,KAAKC,YAAY,6BAChB,KAAK,YACL,gBACD;OAEA,KAAKA,YAAY,+CAChB,KAAK,UACN;CAEF;;CAGA,IAAI,WAAoD;EACvD,OAAO,4BAA8C,KAAKA,SAAS;CACpE;;CAGA,IAAI,QAAgB;EACnB,OAAO,KAAKA,UAAU;CACvB;;CAGA,IAAI,UAA2C;EAC9C,OAAO,KAAKA,UAAU;CACvB;;CAGA,aAAsB;EACrB,OAAO,KAAK,WAAW,OAAO,KAAK,MAAM,CAAC,aAAa;CACxD;;CAGA,IAAI,OAAwB;EAC3B,OAAO,KAAK,eACX,iCAAiC,KAAK,YAAY,KAAKA,WAAW,KAAK,CACxE;CACD;;CAGA,SAAS,OAAmE;EAC3E,OAAO,KAAK,eAAe;GAC1B,MAAM,SAAS,8BACd,KAAK,YACL,KAAKA,WACL,KACD;GACA,KAAKA,YAAY,OAAO;GACxB,OAAO;EACR,CAAC;CACF;CAEA,AAAQ,SAAkB,WAAmC;EAC5D,IAAI,KAAKC,aACR,MAAM,IAAI,2CAA2C;EAGtD,KAAKA,cAAc;EACnB,IAAI;GACH,OAAO,UAAU;EAClB,UAAU;GACT,KAAKA,cAAc;EACpB;CACD;AACD;;;;;;;;;;;;;;;;;;;;;;;;;;AClIA,IAAa,eAAb,MAA+E;CAC9E,AAAiB,2BAAW,IAAI,IAAiC;CACjE,AAAiB,mBAAwC,CAAC;CAE1D,UACC,WACA,SACa;EACb,MAAM,OAAO;EACb,IAAI,CAAC,KAAK,SAAS,IAAI,IAAI,GAC1B,KAAK,SAAS,IAAI,MAAM,CAAC,CAAC;EAE3B,MAAM,kBAAkB,KAAK,SAAS,IAAI,IAAI;EAC9C,MAAM,SAAS;EACf,gBAAgB,KAAK,MAAM;EAK3B,IAAI,UAAU;EACd,aAAa;GACZ,IAAI,SAAS;GACb,MAAM,MAAM,gBAAgB,QAAQ,MAAM;GAC1C,IAAI,QAAQ,IAAI;IACf,gBAAgB,OAAO,KAAK,CAAC;IAC7B,UAAU;GACX;GACA,IAAI,gBAAgB,WAAW,GAC9B,KAAK,SAAS,OAAO,IAAI;EAE3B;CACD;;;;;CAMA,aAAa,SAAwC;EACpD,KAAK,iBAAiB,KAAK,OAAO;EAKlC,IAAI,UAAU;EACd,aAAa;GACZ,IAAI,SAAS;GACb,MAAM,MAAM,KAAK,iBAAiB,QAAQ,OAAO;GACjD,IAAI,QAAQ,IAAI;IACf,KAAK,iBAAiB,OAAO,KAAK,CAAC;IACnC,UAAU;GACX;EACD;CACD;CAEA,KACC,WACA,SACqC;EACrC,OAAO,IAAI,SAAoC,SAAS,WAAW;GAGlE,IAAI,SAAS,QAAQ,SAAS;IAC7B,OAAO,YAAY,QAAQ,QAAQ,uBAAuB,CAAC;IAC3D;GACD;GAEA,IAAI;GACJ,IAAI,UAAU;GACd,IAAI;GAEJ,MAAM,gBAAgB;IACrB,IAAI,SAAS;IACb,UAAU;IACV,YAAY;IACZ,IAAI,UAAU,QAAW,aAAa,KAAK;IAC3C,IAAI,iBAAiB,SAAS,QAC7B,QAAQ,OAAO,oBAAoB,SAAS,aAAa;GAE3D;GAEA,MAAM,cAAc,KAAK,UAAU,YAAY,UAAU;IACxD,QAAQ;IACR,QAAQ,KAAK;GACd,CAAC;GAED,IAAI,SAAS,QAAQ;IACpB,sBAAsB;KACrB,QAAQ;KACR,OAAO,YAAY,QAAQ,QAAS,uBAAuB,CAAC;IAC7D;IACA,QAAQ,OAAO,iBAAiB,SAAS,aAAa;GACvD;GAEA,IAAI,OAAO,SAAS,cAAc,UACjC,QAAQ,iBAAiB;IACxB,QAAQ;IACR,uBACC,IAAI,MACH,iCAAiC,QAAQ,UAAU,kBAAkB,UAAU,EAChF,CACD;GACD,GAAG,QAAQ,SAAS;EAEtB,CAAC;CACF;;;;;;;;;CAUA,MAAM,QACL,QACA,UAA0B,CAAC,GACX;EAMhB,MAAM,SAAkB,CAAC;EACzB,IAAI;GACH,MAAM,oBACL,oBACA;IACC,QAAQ,QAAQ;IAChB,WAAW,QAAQ;GACpB,IACC,YAAY,KAAK,qBAAqB,QAAQ,SAAS,MAAM,CAC/D;EACD,SAAS,cAAc;GACtB,IAAI,OAAO,WAAW,GAAG,MAAM;GAC/B,MAAM,IAAI,eACT,CACC,wBAAwB,QACrB,eACA,IAAI,MAAM,OAAO,YAAY,GAAG,EAAE,OAAO,aAAa,CAAC,GAC1D,GAAG,MACJ,GACA,iDACD;EACD;EACA,IAAI,OAAO,WAAW,GACrB,MAAM,OAAO;EAEd,IAAI,OAAO,SAAS,GACnB,MAAM,IAAI,eAAe,QAAQ,gCAAgC;CAEnE;CAEA,MAAc,qBACb,QACA,SACA,QACgB;EAChB,KAAK,MAAM,SAAS,QAAQ;GAC3B,IAAI,QAAQ,OAAO,SAClB,MAAM,YAAY,QAAQ,QAAQ,0BAA0B;GAU7D,MAAM,QAAQ,CACb,GAAI,KAAK,SAAS,IAAI,MAAM,IAAI,KAAK,CAAC,GACtC,GAAG,KAAK,gBACT;GACA,IAAI,MAAM,SAAS,GAAG;IAKrB,MAAM,aAAa,OAAO;IAC1B,MAAM,gBAA0B,CAAC;IACjC,MAAM,QAAQ,WACb,MAAM,IAAI,OAAO,SAAS,UAAU;KACnC,IAAI;MACH,MAAM,QAAQ,OAAO,OAAO;KAC7B,SAAS,QAAQ;MAChB,cAAc,KAAK,KAAK;MACxB,OAAO,KACN,kBAAkB,QACf,SAID,IAAI,MAAM,OAAO,MAAM,GAAG,EAAE,OAAO,OAAO,CAAC,CAC9C;KACD;IACD,CAAC,CACF;IAIA,MAAM,UAAU,OAAO,OAAO,UAAU;IACxC,OAAO,KACN,GAAG,cACD,KAAK,OAAO,OAAO;KAAE;KAAO,OAAO,QAAQ;IAAY,EAAE,CAAC,CAC1D,MAAM,GAAG,MAAM,EAAE,QAAQ,EAAE,KAAK,CAAC,CACjC,KAAK,UAAU,MAAM,KAAK,CAC7B;GACD;GACA,IAAI,QAAQ,OAAO,SAClB,MAAM,YAAY,QAAQ,QAAQ,0BAA0B;EAE9D;CACD;AACD;;;;;;;;;;ACjLA,SAAgB,yBAMf,QACA,QACiD;CACjD,MAAM,UAAU,OAAO,OAAO,KAAK;CACnC,OAAO,4BAA4B;EAClC,WAAW,OAAO,MAAM;EACxB,MAAM,QAAQ;EACd,SAAS,QAAQ;EACjB,YAAY,OAAO,MAAM,WAAW,YAAY;EAChD,GAAG,oBAAoB,OAAO;EAC9B,SAAS,QAAQ;EACjB,GAAI,QAAQ,aAAa,SAAY,CAAC,IAAI,EAAE,UAAU,QAAQ,SAAS;EACvE,QAAQ,OAAO;EACf,UAAU,OAAO;CAClB,CAAC;AACF;;AAGA,SAAgB,yBAAyB,SAAqC;CAC7E,yBAAyB,OAAO;CAChC,OAAO,KAAK,UAAU,OAAO;AAC9B;;;;;AAMA,SAAgB,yBACf,YACqB;CACrB,IAAI;EACH,OAAO,4BAA4B,KAAK,MAAM,UAAU,GAAG,MAAM;CAClE,SAAS,OAAO;EACf,IAAI,iBAAiB,gCAAgC,MAAM;EAC3D,MAAM,IAAI,+BACT,KACA,0BACA,KACD;CACD;AACD;;;;;;AAOA,SAAgB,mCAKf,SACqD;CACrD,MAAM,gBAAgB,4BAA4B,OAAO;CACzD,MAAM,WAAW,mBAAmB,aAAa;CACjD,OAAO;EACN,OAAO,kBAAkB,cAAc,MAAM,cAAc,SAAS;GACnE,SAAS,cAAc;GACvB,aAAa,cAAc,OAAO;GAClC,eAAe,cAAc,OAAO;GACpC,YAAY,IAAI,KAAK,cAAc,UAAU;GAC7C,SAAS,cAAc;GACvB;EACD,CAAC;EACD,QAAQ,cAAc;EACtB,UAAU,cAAc;CACzB;AACD;AAEA,SAAS,4BACR,OACA,kBAAwC,aACpC;CACJ,yBAAyB,OAAO,eAAe;CAC/C,MAAM,OAAO,KAAK,MAAM,KAAK,UAAU,KAAK,CAAC;CAC7C,IAAI,oBAAoB,QACvB,KAAK,aAAa,uBAAuB,KAAK,UAAU;CAEzD,OAAO,WAAW,IAAI;AACvB;AAEA,SAAS,yBACR,OACA,kBAAwC,aACF;CACtC,gBAAgB,OAAO,KAAK,OAAO;CACnC,IAAI,CAAC,aAAa,KAAK,GACtB,QAAQ,KAAK,sCAAsC;CAEpD,IAAI,OAAO,MAAM,cAAc,YAAY,MAAM,UAAU,WAAW,GACrE,QAAQ,eAAe,4BAA4B;CAEpD,KAAK,MAAM,SAAS,qBAAqB;EACxC,IAAI,CAAC,OAAO,OAAO,OAAO,KAAK,GAAG;EAClC,MAAM,iBAAiB,MAAM;EAC7B,IAAI,OAAO,mBAAmB,YAAY,eAAe,WAAW,GACnE,QAAQ,KAAK,SAAS,yCAAyC;CAEjE;CACA,IAAI,OAAO,MAAM,SAAS,YAAY,MAAM,KAAK,WAAW,GAC3D,QAAQ,UAAU,4BAA4B;CAE/C,MAAM,UAAU,MAAM;CACtB,IACC,OAAO,YAAY,YACnB,CAAC,OAAO,UAAU,OAAO,KACzB,UAAU,GAEV,QAAQ,aAAa,yBAAyB;CAE/C,IACC,OAAO,MAAM,eAAe,aAC3B,oBAAoB,cAClB,CAAC,wBAAwB,MAAM,UAAU,IACzC,uBAAuB,MAAM,UAAU,MAAM,SAEhD,QACC,gBACA,oBAAoB,cACjB,+CACA,yFACJ;CAED,IAAI,CAAC,OAAO,OAAO,OAAO,SAAS,GAClC,QAAQ,aAAa,kDAAkD;CAExE,IACC,OAAO,OAAO,OAAO,UAAU,KAC/B,MAAM,aAAa,UACnB,CAAC,aAAa,MAAM,QAAQ,GAE5B,QAAQ,cAAc,0CAA0C;CAEjE,IAAI,aAAa,MAAM,QAAQ,GAC9B;OAAK,MAAM,SAAS,qBACnB,IAAI,OAAO,OAAO,MAAM,UAAU,KAAK,GACtC,QACC,cAAc,SACd,sDACD;CAEF;CAED,IAAI,CAAC,aAAa,MAAM,MAAM,GAC7B,QAAQ,YAAY,6BAA6B;CAElD,IACC,OAAO,MAAM,OAAO,kBAAkB,YACtC,MAAM,OAAO,cAAc,WAAW,GAEtC,QAAQ,0BAA0B,4BAA4B;CAE/D,IACC,OAAO,MAAM,OAAO,gBAAgB,YACpC,MAAM,OAAO,YAAY,WAAW,GAEpC,QAAQ,wBAAwB,4BAA4B;CAE7D,IAAI,CAAC,aAAa,MAAM,QAAQ,GAC/B,QAAQ,cAAc,6BAA6B;CAEpD,MAAM,EAAE,aAAa;CACrB,MAAM,mBAAmB,SAAS;CAClC,IACC,OAAO,qBAAqB,YAC5B,CAAC,OAAO,UAAU,gBAAgB,KAClC,mBAAmB,GAEnB,QAAQ,+BAA+B,yBAAyB;CAEjE,MAAM,iBAAiB,SAAS;CAChC,IACC,OAAO,mBAAmB,YAC1B,CAAC,OAAO,UAAU,cAAc,KAChC,iBAAiB,GAEjB,QAAQ,6BAA6B,yBAAyB;CAE/D,MAAM,aAAa,SAAS;CAC5B,IACC,OAAO,eAAe,YACtB,CAAC,OAAO,UAAU,UAAU,KAC5B,cAAc,gBAEd,QACC,yBACA,wDACD;CAED,IAAI,CAAC,OAAO,OAAO,UAAU,kCAAkC,GAC9D,QACC,+CACA,mCACD;CAED,MAAM,WAAW,SAAS;CAC1B,IACC,aAAa,SACZ,OAAO,aAAa,YACpB,CAAC,OAAO,UAAU,QAAQ,KAC1B,WAAW,KACX,YAAY,mBAEb,QACC,+CACA,sEACD;AAEF;AAEA,MAAM,sBAAsB;CAC3B;CACA;CACA;AACD;AAEA,SAAS,oBACR,SACkC;CAClC,MAAM,EAAE,eAAe,gBAAgB,gBAAgB;CACvD,OAAO;EACN,GAAI,kBAAkB,SAAY,CAAC,IAAI,EAAE,cAAc;EACvD,GAAI,mBAAmB,SAAY,CAAC,IAAI,EAAE,eAAe;EACzD,GAAI,gBAAgB,SAAY,CAAC,IAAI,EAAE,YAAY;CACpD;AACD;AAEA,SAAS,mBACR,SAC4B;CAC5B,MAAM,gBAAgB,oBAAoB,OAAO;CACjD,IACC,QAAQ,aAAa,UACrB,OAAO,KAAK,aAAa,CAAC,CAAC,WAAW,GAEtC;CAED,OAAO;EAAE,GAAG,QAAQ;EAAU,GAAG;CAAc;AAChD;AAEA,SAAS,wBAAwB,OAAwB;CACxD,MAAM,YAAY,IAAI,KAAK,KAAK;CAChC,OACC,CAAC,OAAO,MAAM,UAAU,QAAQ,CAAC,KAAK,UAAU,YAAY,MAAM;AAEpE;AAEA,MAAM,iBACL;AAED,SAAS,uBAAuB,OAAmC;CAClE,MAAM,QAAQ,eAAe,KAAK,KAAK;CACvC,IAAI,UAAU,MAAM,OAAO;CAE3B,MAAM,GAEL,MACA,OACA,KACA,MACA,QACA,YAGA,YACA,gBACG;CACJ,MAAM,cAAc,OAAO,IAAI;CAC/B,MAAM,eAAe,OAAO,KAAK;CACjC,MAAM,aAAa,OAAO,GAAG;CAC7B,IACC,eAAe,KACf,eAAe,MACf,aAAa,KACb,aAAa,YAAY,aAAa,YAAY,KAClD,OAAO,IAAI,IAAI,MACf,OAAO,MAAM,IAAI,MACjB,OAAO,MAAM,IAAI,MAChB,eAAe,UAAa,OAAO,UAAU,IAAI,MACjD,iBAAiB,UAAa,OAAO,YAAY,IAAI,IAEtD;CAGD,MAAM,YAAY,IAAI,KAAK,KAAK;CAChC,OAAO,OAAO,MAAM,UAAU,QAAQ,CAAC,IACpC,SACA,UAAU,YAAY;AAC1B;AAEA,SAAS,YAAY,MAAc,OAAuB;CACzD,IAAI,UAAU,GACb,OAAO,OAAO,MAAM,MAAM,OAAO,QAAQ,KAAK,OAAO,QAAQ,KAAK,KAAK;CAExE,OAAO,UAAU,KAAK,UAAU,KAAK,UAAU,KAAK,UAAU,KAAK,KAAK;AACzE;AAEA,SAAS,QAAQ,MAAc,QAAuB;CACrD,MAAM,IAAI,+BAA+B,MAAM,MAAM;AACtD;;;;;;;;ACnWA,SAAgB,uBAAuB,SAAmC;CACzE,OAAO,KAAK,UAAU,CAAC,QAAQ,eAAe,QAAQ,WAAW,CAAC;AACnE;;;;;;;;;;;;;;;;;;;;;;;;;;;ACmBA,SAAgB,iCAEO;CACtB,OAAO,EACN,KAAK,YAAY,CAAC,EACnB;AACD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmHA,IAAa,iBAAb,MAEA;CACC,AAAiB,0BAAU,IAAI,IAAgC;CAC/D,AAAiB,uBAAO,IAAI,IAAmC;;CAE/D,AAAiB,gCAAgB,IAAI,IAA+B;;CAEpE,AAAiB,qCAAqB,IAAI,IAGxC;CACF,AAAiB;CACjB,AAAiB;CACjB,AAAiB;CACjB,AAAiB;CAEjB,YAAY,SAAiC;EAC5C,MAAM,MAAM,SAAS,uBAAuB;EAC5C,sBAAsB,kBAAkB,uBAAuB,GAAG;EAClE,KAAK,sBAAsB;EAC3B,MAAM,WAAW,SAAS,iCAAiC;EAC3D,sBACC,kBACA,iCACA,QACD;EACA,KAAK,gCAAgC;EACrC,IAAI,SAAS,eAAe,QAC3B,0BACC,kBACA,cACA,QAAQ,UACT;EAED,IAAI,SAAS,eAAe,QAC3B,0BACC,kBACA,cACA,QAAQ,UACT;EAED,KAAK,aAAa,SAAS;EAC3B,KAAK,aAAa,SAAS;CAC5B;CAEA,MAAM,IAAI,QAAiE;EAI1E,KAAK,iCAAiC,MAAM;EAC5C,KAAK,6BAA6B,MAAM;EACxC,KAAK,eAAe,MAAM;EAC1B,KAAK,MAAM,WAAW,QAAQ;GAC7B,MAAM,EAAE,OAAO,QAAQ,aAAa;GACpC,MAAM,oBAAoB,KAAK,mBAAmB,IAAI,MAAM,OAAO;GACnE,IAAI,sBAAsB,QAAW;IACpC,sBAAsB,OAAO,QAAQ,kBAAkB,MAAM;IAC7D,2BACC,OACA,UACA,kBAAkB,QACnB;IAGA,KAAK,mBACJ,MAAM,SACN,kBAAkB,QAClB,kBAAkB,QACnB;IACA;GACD;GACA,MAAM,WAAW,KAAK,QAAQ,IAAI,MAAM,OAAO;GAC/C,MAAM,aAAa,KAAK,KAAK,IAAI,MAAM,OAAO;GAC9C,IAAI,aAAa,QAAW;IAC3B,sBAAsB,OAAO,QAAQ,SAAS,MAAM;IAIpD,iDACC,OACA,UACA,SAAS,QACV;GACD;GACA,IAAI,YAAY;IACf,sBAAsB,OAAO,QAAQ,WAAW,MAAM;IACtD,2BAA2B,OAAO,UAAU,WAAW,QAAQ;IAG/D,KAAK,KAAK,OAAO,MAAM,OAAO;IAC9B,KAAK,QAAQ,IAAI,MAAM,SAAS;KAC/B,YAAY,WAAW;KACvB,OAAO,WAAW;KAClB,QAAQ,WAAW;KACnB,UAAU,WAAW;KACrB,UAAU;IACX,CAAC;IACD;GACD;GACA,MAAM,cAAc,OAAO,OAAO,EAAE,GAAG,OAAO,CAAC;GAC/C,MAAM,YAAY,uBAAuB,MAAM;GAC/C,MAAM,eAAe,KAAK,cAAc,IAAI,SAAS;GACrD,IAAI;GACJ,IACC,aAAa,UACb,SAAS,mBAAmB,SAAS,SAAS,kBAE9C,mBAAmB,SAAS,SAAS;QAC/B,IACN,aAAa,UACb,iBAAiB,UACjB,SAAS,mBAAmB,aAAa,kBAEzC,mBAAmB,aAAa;GAEjC,IAAI,qBAAqB,QACxB,MAAM,eAAe,OAAO,QAAQ,UAAU,gBAAgB;GAE/D,IAAI,cAAc,qBAAqB,SAAS,kBAAkB;IACjE,IAAI,aAAa,eAAe,SAAS,YACxC,MAAM,IAAI,kBACT,kCAAkC,MAAM,QAAQ,QAC5C,OAAO,cAAc,GAAG,OAAO,YAAY,sBAC3C,SAAS,iBAAiB,wCAC1B,aAAa,WAAW,QAAQ,SAAS,WAAW,IACxD,MAAM,IACP;IAED,MAAM,gBAAgB,aAAa,mBAAmB,IACrD,SAAS,cACV;IACA,IAAI,kBAAkB,UAAa,kBAAkB,MAAM,SAC1D,MAAM,IAAI,kBACT,kCAAkC,MAAM,QAAQ,QAC5C,OAAO,cAAc,GAAG,OAAO,YAAY,qBAC1C,SAAS,iBAAiB,IAAI,SAAS,eAAe,+BAC/B,cAAc,8EAE1C,MAAM,IACP;GAEF;GACA,IAAI;GAIJ,IAFC,aAAa,UACb,SAAS,SAAS,qBAAqB,SAAS,kBACtB;IAK1B,mCACC,SAAS,SAAS;IACnB,IACC,cAAc,qBAAqB,SAAS,SAAS,kBAErD,KAAK,cAAc,IAAI,WAAW;KACjC,kBAAkB,SAAS;KAC3B;KACA,YAAY,SAAS;KACrB,oCAAoB,IAAI,IAAI,CAC3B,CAAC,SAAS,gBAAgB,MAAM,OAAO,CACxC,CAAC;IACF,CAAC;SACK,IACN,cAAc,qBAAqB,SAAS,oBAC5C,CAAC,aAAa,mBAAmB,IAAI,SAAS,cAAc,GAE5D,KAAK,cAAc,IAClB,WACA,gBACC,cACA,SAAS,gBACT,MAAM,OACP,CACD;GAEF,OAAO,IAAI,aAAa,QACvB,mCACC,SAAS,SAAS;QACb,IAAI,cAAc,qBAAqB,SAAS,kBAAkB;IACxE,mCACC,aAAa;IACd,IAAI,CAAC,aAAa,mBAAmB,IAAI,SAAS,cAAc,GAC/D,KAAK,cAAc,IAClB,WACA,gBACC,cACA,SAAS,gBACT,MAAM,OACP,CACD;GAEF,OAAO;IACN,mCACC,cAAc,oBAAoB;IACnC,KAAK,cAAc,IAAI,WAAW;KACjC,kBAAkB,SAAS;KAC3B;KACA,YAAY,SAAS;KACrB,oCAAoB,IAAI,IAAI,CAC3B,CAAC,SAAS,gBAAgB,MAAM,OAAO,CACxC,CAAC;IACF,CAAC;GACF;GACA,MAAM,gBAAgB,OAAO,OAAO;IACnC,GAAG;IACH;GACD,CAAC;GACD,IAAI,UAAU;IAMb,SAAS,QAAQ;IACjB,SAAS,SAAS;IAClB,SAAS,WAAW;IACpB;GACD;GACA,KAAK,QAAQ,IAAI,MAAM,SAAS;IAC/B,YAAY,MAAM;IAClB;IACA,QAAQ;IACR,UAAU;IACV,UAAU;GACX,CAAC;EACF;CACD;CAEA,AAAQ,eACP,QACO;EACP,MAAM,+BAAe,IAAI,IAAY;EACrC,MAAM,gCAAgB,IAAI,IAAY;EACtC,KAAK,MAAM,EAAE,OAAO,YAAY,QAAQ;GACvC,IACC,KAAK,QAAQ,IAAI,MAAM,OAAO,KAC9B,KAAK,KAAK,IAAI,MAAM,OAAO,KAC3B,KAAK,mBAAmB,IAAI,MAAM,OAAO,GAEzC;GAED,aAAa,IAAI,MAAM,OAAO;GAC9B,MAAM,YAAY,uBAAuB,MAAM;GAC/C,IAAI,CAAC,KAAK,cAAc,IAAI,SAAS,GAAG,cAAc,IAAI,SAAS;EACpE;EAEA,MAAM,iBAAiB,KAAK,QAAQ,OAAO,KAAK,KAAK;EACrD,IACC,KAAK,eAAe,UACpB,iBAAiB,aAAa,OAAO,KAAK,YAE1C,MAAM,IAAI,8BAA8B;GACvC,OAAO;GACP,UAAU;GACV,OAAO,KAAK;GACZ,SAAS;GACT,WAAW,aAAa;EACzB,CAAC;EAEF,IACC,KAAK,eAAe,UACpB,KAAK,cAAc,OAAO,cAAc,OAAO,KAAK,YAEpD,MAAM,IAAI,8BAA8B;GACvC,OAAO;GACP,UAAU;GACV,OAAO,KAAK;GACZ,SAAS,KAAK,cAAc;GAC5B,WAAW,cAAc;EAC1B,CAAC;CAEH;CAEA,AAAQ,iCACP,QACO;EACP,MAAM,kCAAkB,IAAI,IAM1B;EACF,KAAK,MAAM,EAAE,OAAO,QAAQ,cAAc,QAAQ;GACjD,MAAM,eAAe,gBAAgB,IAAI,MAAM,OAAO;GACtD,IAAI,iBAAiB,QAAW;IAC/B,sBAAsB,OAAO,QAAQ,aAAa,MAAM;IACxD,2BACC,OACA,UACA,aAAa,QACd;GACD,OACC,gBAAgB,IAAI,MAAM,SAAS;IAAE;IAAQ;GAAS,CAAC;GAExD,MAAM,oBAAoB,KAAK,mBAAmB,IAAI,MAAM,OAAO;GACnE,IAAI,sBAAsB,QAAW;IACpC,sBAAsB,OAAO,QAAQ,kBAAkB,MAAM;IAC7D,2BACC,OACA,UACA,kBAAkB,QACnB;IACA;GACD;GACA,MAAM,WAAW,KAAK,QAAQ,IAAI,MAAM,OAAO;GAC/C,IAAI,aAAa,QAAW;IAC3B,sBAAsB,OAAO,QAAQ,SAAS,MAAM;IACpD,iDACC,OACA,UACA,SAAS,QACV;GACD;GACA,MAAM,aAAa,KAAK,KAAK,IAAI,MAAM,OAAO;GAC9C,IAAI,eAAe,QAAW;IAC7B,sBAAsB,OAAO,QAAQ,WAAW,MAAM;IACtD,2BAA2B,OAAO,UAAU,WAAW,QAAQ;GAChE;EACD;CACD;CAEA,AAAQ,6BACP,QACO;EACP,MAAM,mCAAmB,IAAI,IAA+B;EAC5D,KAAK,MAAM,EAAE,OAAO,QAAQ,cAAc,QAAQ;GACjD,MAAM,YAAY,uBAAuB,MAAM;GAC/C,MAAM,SACL,iBAAiB,IAAI,SAAS,KAAK,KAAK,cAAc,IAAI,SAAS;GACpE,IACC,WAAW,UACX,SAAS,mBAAmB,OAAO,kBAClC;IACD,iBAAiB,IAAI,WAAW;KAC/B,kBAAkB,SAAS;KAC3B,kCAAkC,QAAQ,oBAAoB;KAC9D,YAAY,SAAS;KACrB,oCAAoB,IAAI,IAAI,CAC3B,CAAC,SAAS,gBAAgB,MAAM,OAAO,CACxC,CAAC;IACF,CAAC;IACD;GACD;GACA,IAAI,SAAS,mBAAmB,OAAO,kBAAkB;IAQxD,MAAM,UACL,KAAK,mBAAmB,IAAI,MAAM,OAAO,KACzC,KAAK,KAAK,IAAI,MAAM,OAAO;IAC5B,MAAM,gBAAgB,KAAK,QAAQ,IAAI,MAAM,OAAO;IAKpD,IAHC,kBAAkB,UAClB,SAAS,mBAAmB,cAAc,SAAS,oBAC3B,kBAAkB,UAAa,CAAC,SAExD,MAAM,eACL,OACA,QACA,UACA,eAAe,SAAS,oBACvB,OAAO,gBACT;IAED;GACD;GACA,IAAI,OAAO,eAAe,SAAS,YAClC,MAAM,IAAI,kBACT,kCAAkC,MAAM,QAAQ,QAC5C,OAAO,cAAc,GAAG,OAAO,YAAY,sBAC3C,SAAS,iBAAiB,wCAC1B,OAAO,WAAW,QAAQ,SAAS,WAAW,IAClD,MAAM,IACP;GAED,MAAM,gBAAgB,OAAO,mBAAmB,IAC/C,SAAS,cACV;GACA,IAAI,kBAAkB,UAAa,kBAAkB,MAAM,SAC1D,MAAM,IAAI,kBACT,kCAAkC,MAAM,QAAQ,QAC5C,OAAO,cAAc,GAAG,OAAO,YAAY,qBAC1C,SAAS,iBAAiB,IAAI,SAAS,eAAe,+BAC/B,cAAc,8EAE1C,MAAM,IACP;GAED,IAAI,kBAAkB,QACrB,iBAAiB,IAChB,WACA,gBAAgB,QAAQ,SAAS,gBAAgB,MAAM,OAAO,CAC/D;EAEF;CACD;CAEA,MAAM,WAAW,OAA2D;EAW3E,MAAM,MACL,OAAO,UAAU,WACd,KAAK,IAAI,GAAG,OAAO,MAAM,KAAK,IAAI,IAAI,KAAK,IAC3C,OAAO;EACX,MAAM,QAAkC,CAAC;EACzC,KAAK,MAAM,UAAU,KAAK,QAAQ,OAAO,GAAG;GAC3C,IAAI,MAAM,UAAU,KAAK;GACzB,MAAM,KAAK;IACV,YAAY,OAAO;IACnB,OAAO,OAAO;IACd,QAAQ,OAAO;IACf,UAAU,OAAO;IACjB,UAAU,OAAO;GAClB,CAAC;EACF;EACA,OAAO;CACR;CAEA,MAAM,eAAe,aAAmD;EACvE,KAAK,MAAM,MAAM,aAAa;GAC7B,MAAM,SAAS,KAAK,QAAQ,IAAI,EAAE,KAAK,KAAK,KAAK,IAAI,EAAE;GACvD,IAAI,WAAW,QACd,KAAK,mBAAmB,IAAI,OAAO,QAAQ,OAAO,QAAQ;GAE3D,KAAK,QAAQ,OAAO,EAAE;GAGtB,KAAK,KAAK,OAAO,EAAE;EACpB;CACD;CAEA,AAAQ,mBACP,SACA,QACA,UACO;EACP,KAAK,mBAAmB,OAAO,OAAO;EACtC,KAAK,mBAAmB,IAAI,SAAS;GACpC,QAAQ,OAAO,OAAO,EAAE,GAAG,OAAO,CAAC;GACnC,UAAU,OAAO,OAAO;IACvB,kBAAkB,SAAS;IAC3B,gBAAgB,SAAS;IACzB,YAAY,SAAS;GACtB,CAAC;EACF,CAAC;EACD,OAAO,KAAK,mBAAmB,OAAO,KAAK,+BAA+B;GACzE,MAAM,SAAS,KAAK,mBAAmB,KAAK,CAAC,CAAC,KAAK;GACnD,IAAI,OAAO,MAAM;GACjB,KAAK,mBAAmB,OAAO,OAAO,KAAK;EAC5C;CACD;CAEA,MAAM,WACL,YACA,OAC6C;EAC7C,MAAM,SAAS,KAAK,QAAQ,IAAI,UAAU;EAG1C,IAAI,CAAC,QAAQ,OAAO;EACpB,OAAO,YAAY;EACnB,OAAO,YACN,iBAAiB,QAAQ,MAAM,UAAU,OAAO,SAAS,SAAS;EACnE,IAAI,OAAO,YAAY,KAAK,qBAAqB;GAChD,KAAK,QAAQ,OAAO,UAAU;GAC9B,MAAM,aAAoC;IACzC,YAAY,OAAO;IACnB,OAAO,OAAO;IACd,QAAQ,OAAO;IACf,UAAU,OAAO;IACjB,UAAU,OAAO;IACjB,WAAW,OAAO;GACnB;GACA,KAAK,KAAK,IAAI,YAAY,UAAU;GACpC,OAAO,EAAE,GAAG,WAAW;EACxB;CAED;CAEA,MAAM,cAA6D;EAClE,OAAO,CAAC,GAAG,KAAK,KAAK,OAAO,CAAC,CAAC,CAAC,KAAK,YAAY,EAAE,GAAG,OAAO,EAAE;CAC/D;AACD;AAEA,SAAS,gBACR,QACA,gBACA,SACoB;CACpB,OAAO;EACN,GAAG;EACH,oBAAoB,IAAI,IAAI,OAAO,kBAAkB,CAAC,CAAC,IACtD,gBACA,OACD;CACD;AACD;AAEA,SAAS,2BACR,OACA,UACA,UACO;CACP,mBAAmB,OAAO,UAAU,UAAU,KAAK;AACpD;;;;;;AAOA,SAAS,iDACR,OACA,UACA,UACO;CACP,mBAAmB,OAAO,UAAU,UAAU,IAAI;AACnD;AAEA,SAAS,mBACR,OACA,UACA,UACA,8BACO;CAIP,KAFC,gCACA,SAAS,qBAAqB,SAAS,qBAGvC,SAAS,mBAAmB,SAAS,kBACrC,SAAS,eAAe,SAAS,YAEjC;CAED,MAAM,IAAI,kBACT,kCAAkC,MAAM,QAAQ,wCAC9B,SAAS,iBAAiB,IAAI,SAAS,eAAe,eACzD,SAAS,WAAW,QAAQ,SAAS,iBAAiB,IACjE,SAAS,eAAe,eAAe,SAAS,WAAW,kEAE/D,MAAM,IACP;AACD;AAEA,SAAS,eACR,OACA,QACA,UACA,kBACoB;CACpB,OAAO,IAAI,kBACV,wCAAwC,MAAM,QAAQ,QAClD,OAAO,cAAc,GAAG,OAAO,YAAY,wBAC3C,SAAS,iBAAiB,qCAC1B,iBAAiB,wIAGrB,MAAM,IACP;AACD;AAEA,SAAS,sBACR,OACA,UACA,UACO;CACP,IACC,SAAS,kBAAkB,SAAS,iBACpC,SAAS,gBAAgB,SAAS,aAElC;CAED,MAAM,IAAI,kBACT,kDAAkD,MAAM,QAAQ,2BACtC,SAAS,cAAc,GAAG,SAAS,YAAY,yBAChD,SAAS,cAAc,GAAG,SAAS,YAAY,+EAExE,MAAM,IACP;AACD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACtnBA,SAAgB,aACf,KACkB;CAClB,OAAO,EACN,UAAU,QAAQ,YACjB,IAAI,QAAQ,CAAC,OAAO,KAAK,GAAG;EAC3B,QAAQ,QAAQ;EAChB,WAAW,KAAK,IAAI,GAAG,QAAQ,aAAa,KAAK,IAAI,CAAC;CACvD,CAAC,EACH;AACD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwJA,IAAa,mBAAb,cAAkE,SAAS;CAC1E,AAAiB;CACjB,AAAiB;CACjB,AAAiB;CACjB,AAAiB;CACjB,AAAiB;CACjB,AAAiB;;;;;;;;;;CAWjB,AAAS;;CAGT,AAAiB;CAEjB,YAAY,SAAuC;EAClD,MAAM,oBAAoB,OAAO;EACjC,KAAK,YAAY,yBAChB,oBACA,QAAQ,WACR;GAAC;GAAmB;GAAe;EAAc,CAClD;EACA,KAAK,SAAS,QAAQ;EACtB,KAAK,iBAAiB,yBAAyB,QAAQ,MAAM,IAC1D,QAAQ,SACR;EACH,KAAK,uBAAuB,KAAK,mBAAmB;EACpD,KAAK,OAAO,QAAQ;EACpB,KAAK,kBAAkB,QAAQ;EAC/B,KAAK,oBACJ,QAAQ;EACT,KAAK,mBACJ,QAAQ;EACT,wBACC,oBACA,qBACA,KAAK,iBACN;EACA,wBACC,oBACA,oBACA,KAAK,gBACN;CACD;;;;;;;;CASA,MAAgB,KAAK,QAAsD;EAC1E,OAAO,CAAC,QAAQ,SAAS;GACxB,IAAI;GACJ,IAAI;IACH,QAAQ,MAAM,oBACb,+BACA;KAAE;KAAQ,WAAW,KAAK;IAAiB,IAC1C,YAAY,KAAK,OAAO,WAAW,KAAK,WAAW,OAAO,CAC5D;GACD,SAAS,OAAO;IACf,IAAI,QAAQ,SAAS,OAAO;IAC5B,KAAK,uBAAuB;IAC5B,uBAAuB,KAAK,UAAU,YAAY,KAAK,CAAC;IACxD,OAAO;GACR;GACA,IAAI,MAAM,WAAW,GAAG;IAKvB,KAAK,sBAAsB;IAC3B,OAAO;GACR;GAEA,IAAI,CAAC,MADmB,KAAK,cAAc,OAAO,MAAM,GACxC,OAAO;EACxB;EACA,OAAO;CACR;;;;;;;CAQA,MAAc,cACb,OACA,QACmB;EACnB,MAAM,YAAsB,CAAC;EAC7B,IAAI;EACJ,IAAI;EACJ,KAAK,MAAM,UAAU,OAAO;GAC3B,IAAI,QAAQ,SAAS;GACrB,IAAI;IACH,MAAM,oBACL,4BACA;KAAE;KAAQ,WAAW,KAAK;IAAkB,IAC3C,YAAY,KAAK,KAAK,QAAQ,QAAQ,OAAO,CAC/C;IACA,UAAU,KAAK,OAAO,UAAU;GACjC,SAAS,OAAO;IACf,IAAI,QAAQ,SACX;IAED,eAAe;IACf,UAAU;IACV;GACD;EACD;EAIA,IAAI,QAAQ;EACZ,IAAI,UAAU,SAAS,GACtB,IAAI;GAMH,MAAM,oBACL,mCACA;IACC,QAJ4B,QAAQ,UAAU,SAAY;IAK1D,WAAW,KAAK;GACjB,IACC,YAAY,KAAK,OAAO,eAAe,WAAW,OAAO,CAC3D;GACA,KAAK,sBAAsB;EAC5B,SAAS,OAAO;GAQf,QAAQ;GACR,IAAI,CAAC,QAAQ,SACZ,KAAK,MAAM,WAAW,MAAM,MAAM,GAAG,UAAU,MAAM,GACpD,uBACC,KAAK,UAAU,gBAAgB,OAAO,OAAO,CAC9C;EAGH;EAGD,IAAI,iBAAiB,QAAW;GAC/B,MAAM,SAAS;GACf,MAAM,QAAQ;GACd,MAAM,aAAa,sBAAsB,OAAO,KAAK,eAAe;GACpE,uBACC,KAAK,UAAU,gBAAgB,OAAO,QAAQ,UAAU,CACzD;GACA,MAAM,WAAW,KAAK;GACtB,IAAI,aAAa,UAAa,WAAW,SAAS,aACjD,IAAI;IACH,MAAM,aAAa,MAAM,oBACxB,+BACA;KAAE;KAAQ,WAAW,KAAK;IAAiB,IAC1C,YAAY,SAAS,WAAW,OAAO,YAAY,OAAO,OAAO,CACnE;IACA,IAAI,eAAe,QAClB,uBAAuB,KAAK,UAAU,aAAa,UAAU,CAAC;GAEhE,SAAS,WAAW;IACnB,IAAI,CAAC,QAAQ,SACZ,uBACC,KAAK,UAAU,gBAAgB,WAAW,MAAM,CACjD;GAEF;EAEF;EAKA,IAAI,iBAAiB,UAAa,CAAC,OAClC,KAAK,sBAAsB,KAAK,IAC/B,KAAK,sBAAsB,IAC1B,cAAc,YAAY,KAAK,CACjC;EAED,IAAI,iBAAiB,QAAW,OAAO;EACvC,IAAI,CAAC,OAAO,OAAO;EAGnB,IAAI,QAAQ,WAAW,UAAU,SAAS,MAAM,QAAQ,OAAO;EAC/D,OAAO;CACR;AACD;;;;;;;;;;ACxcA,SAAgB,gBACf,WACA,WACU;CACV,IAAI,UAAU,qBAAqB,UAAU,kBAC5C,OAAO,UAAU,mBAAmB,UAAU;CAE/C,OAAO,UAAU,iBAAiB,UAAU;AAC7C;;;;;;;;;;;;;;;;;;;;;;;;;;;ACPA,IAAa,oCAAb,MAEA;;CAEC,AAAiB,8BAAc,IAAI,IAGjC;;CAEF,AAAiB,4BAAY,IAAI,IAA2B;CAC5D,AAAiB;CACjB,AAAQ,kBAAkB;CAE1B,YAAY,UAAoD,CAAC,GAAG;EACnE,IAAI,QAAQ,mBAAmB,QAC9B,0BACC,qCACA,kBACA,QAAQ,cACT;EAED,KAAK,iBAAiB,QAAQ;CAC/B;CAEA,MAAM,oBACL,MACA,YACA,WACA,MACa;EACb,MAAM,OAAO,CACZ,GAAG,IAAI,IACN,UAAU,KAAK,YACd,KAAK,UAAU;GACd;GACA,QAAQ;GACR,QAAQ;EACT,CAAC,CACF,CACD,CACD,CAAC,CAAC,KAAK;EACP,MAAM,WAA8B,CAAC;EAErC,KAAK,MAAM,OAAO,MAAM;GACvB,MAAM,WAAW,KAAK,UAAU,IAAI,GAAG,KAAK,QAAQ,QAAQ;GAC5D,IAAI;GACJ,MAAM,UAAU,IAAI,SAAe,YAAY;IAC9C,iBAAiB;GAClB,CAAC;GACD,MAAM,OAAO,SAAS,WAAW,OAAO;GACxC,KAAK,UAAU,IAAI,KAAK,IAAI;GAC5B,MAAM;GACN,SAAS,WAAW;IACnB,eAAe;IACf,IAAI,KAAK,UAAU,IAAI,GAAG,MAAM,MAAM,KAAK,UAAU,OAAO,GAAG;GAChE,CAAC;EACF;EAEA,IAAI;GACH,OAAO,MAAM,KAAK;EACnB,UAAU;GACT,KAAK,IAAI,QAAQ,SAAS,SAAS,GAAG,SAAS,GAAG,SAAS,GAC1D,SAAS,MAAM,GAAG;EAEpB;CACD;CAEA,MAAM,KACL,MACA,YACA,SAC4C;EAC5C,MAAM,SAAS,KAAK,YAClB,IAAI,UAAU,CAAC,EACd,IAAI,uBAAuB,OAAO,CAAC;EAGtC,OAAO,WAAW,SACf,SACA;GAAE,GAAG;GAAQ,UAAU,EAAE,GAAG,OAAO,SAAS;EAAE;CAClD;CAEA,MAAM,KACL,MACA,YACA,SACA,YACgB;EAChB,MAAM,aAAa,uBAAuB,OAAO;EACjD,IAAI,eAAe,KAAK,YAAY,IAAI,UAAU;EAClD,MAAM,kBAAkB,cAAc,IAAI,UAAU,MAAM;EAC1D,IACC,mBACA,KAAK,mBAAmB,UACxB,KAAK,mBAAmB,KAAK,gBAE7B,MAAM,IAAI,8BAA8B;GACvC,OAAO;GACP,UAAU;GACV,OAAO,KAAK;GACZ,SAAS,KAAK;GACd,WAAW;EACZ,CAAC;EAEF,IAAI,iBAAiB,QAAW;GAC/B,+BAAe,IAAI,IAAI;GACvB,KAAK,YAAY,IAAI,YAAY,YAAY;EAC9C;EACA,aAAa,IAAI,YAAY;GAC5B,GAAG;GACH,UAAU,EAAE,GAAG,WAAW,SAAS;EACpC,CAAC;EACD,IAAI,iBAAiB,KAAK,mBAAmB;CAC9C;CAEA,MAAM,WACL,YACA,SACA,UACmB;EACnB,MAAM,SAAS,KAAK,YAClB,IAAI,UAAU,CAAC,EACd,IAAI,uBAAuB,OAAO,CAAC;EACtC,IAAI,WAAW,QAAW,OAAO;EACjC,OAAO,CAAC,gBAAgB,UAAU,OAAO,QAAQ;CAClD;CAEA,MAAM,MAAM,MAAe,YAAmC;EAC7D,KAAK,mBAAmB,KAAK,YAAY,IAAI,UAAU,CAAC,EAAE,QAAQ;EAClE,KAAK,YAAY,OAAO,UAAU;CACnC;AACD;;;;;;;;ACpKA,MAAa,wBAAwB,OAAO,uBAAuB;;;;;;;;;;;;;;;;;;;;;;;;;AA6DnE,SAAgB,uBACf,SACwB;CACxB,OAAO;EACN,MAAM,QAAQ;EACd,UAAU,QAAQ;EAClB,OAAO,OAAO,KAAK,UAAU;GAC5B,MAAM,QAAQ,OAAO,OAAO,QAAQ,UAAU,MAAM,IAAI,IACpD,QAAQ,SAAS,MAAM,QAGxB;GACH,IAAI,UAAU,QACb,MAAM,IAAI,oBAAoB,MAAM,IAAI;GAEzC,IAAI,UAAU,uBAAuB;GACrC,MAAM,MAAM,KAAK,KAAK;EACvB;CACD;AACD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC6BA,IAAa,YAAb,MAAmE;CAClE,AAAiB;CACjB,AAAiB;CACjB,AAAiB;CAEjB,YAAY,SAAsC;EACjD,KAAK,QAAQ,QAAQ;EACrB,KAAK,cAAc,QAAQ;EAC3B,KAAK,aAAa,QAAQ;CAC3B;;;;;;;;;;;;;CAcA,MAAM,QACL,QACA,UAA0B,CAAC,GACM;EACjC,IAAI,QAAQ,QAAQ,SACnB,MAAM,YACL,QAAQ,QACR,wDACD;EAID,MAAM,WAAW,OAAO,KAAK,EAAE,OAAO,QAAQ,eAAe;GAC5D,IAAI,OAAO,MAAM,YAAY,YAAY,MAAM,QAAQ,WAAW,GACjE,MAAM,IAAI,wBACT,KAAK,WAAW,MAChB,OAAO,MAAM,YAAY,WAAW,MAAM,UAAU,aACpD,8JAGD;GAED,IAAI,aAAa,QAChB,MAAM,IAAI,wBACT,KAAK,WAAW,MAChB,MAAM,SACN,oKAGD;GAED,IAAI,CAAC,gBAAgB,QAAQ,GAC5B,MAAM,IAAI,wBACT,KAAK,WAAW,MAChB,MAAM,SACN,8QAKD;GAED,IAAI,WAAW,QACd,MAAM,IAAI,wBACT,KAAK,WAAW,MAChB,MAAM,SACN,qEACD;GAED,MAAM,EAAE,aAAa,kBAAkB;GACvC,IAAI,CAAC,eAAe,CAAC,eACpB,MAAM,IAAI,wBACT,KAAK,WAAW,MAChB,MAAM,SACN,wLAGD;GAED,MAAM,sBACL,MAAM,gBAAgB,UAAa,MAAM,gBAAgB;GAC1D,MAAM,wBACL,MAAM,kBAAkB,UACxB,MAAM,kBAAkB;GACzB,IAAI,uBAAuB,uBAC1B,MAAM,IAAI,kBACT,aACA,eACA,MAAM,MACN,MAAM,aACN,MAAM,aACP;GAGD,OAAO;IAAE;IAAO;IAAU;KADU;KAAe;IACnB;GAAE;EACnC,CAAC;EACD,MAAM,gBAAgB,CACrB,GAAG,IAAI,IACN,SAAS,KACP,EAAE,cAAc,CAAC,uBAAuB,OAAO,GAAG,OAAO,CAC3D,CACD,CAAC,CAAC,QAAQ,CACX,CAAC,CACC,MAAM,CAAC,OAAO,CAAC,WAAY,OAAO,QAAQ,KAAK,OAAO,QAAQ,IAAI,CAAE,CAAC,CACrE,KAAK,GAAG,aAAa,OAAO;EAK9B,MAAM,mBAAmB,OACxB,QACoC;GACpC,IAAI,UAAU;GACd,IAAI,UAAU;GAId,MAAM,0CAA0B,IAAI,IAGlC;GACF,MAAM,6BAAa,IAAI,IAA4C;GACnE,KAAK,MAAM,EAAE,OAAO,aAAa,UAAU;IAC1C,MAAM,MAAM,uBAAuB,OAAO;IAC1C,IAAI,WAAW,IAAI,GAAG,GAAG;IACzB,MAAM,SAAS,MAAM,KAAK,YAAY,KACrC,KACA,KAAK,WAAW,MAChB,OACD;IACA,IAAI,WAAW,UAAa,CAAC,kBAAkB,MAAM,GACpD,MAAM,IAAI,wBACT,KAAK,WAAW,MAChB,MAAM,SACN,sLAID;IAED,wBAAwB,IAAI,KAAK,MAAM;IACvC,WAAW,IAAI,KAAK,QAAQ,QAAQ;GACrC;GAQA,KAAK,MAAM,EAAE,OAAO,UAAU,aAAa,UAAU;IACpD,MAAM,SAAS,wBAAwB,IACtC,uBAAuB,OAAO,CAC/B;IACA,IACC,WAAW,UACX,sBAAsB,UAAU,OAAO,QAAQ,GAC9C;KACD,IAAI,MAAM,YAAY,OAAO,oBAC5B,MAAM,IAAI,iCACT,KAAK,WAAW,MAChB,MAAM,SACN,OAAO,oBACP,eAAe,QAAQ,CACxB;KAED,IAAI,CAAC,sBAAsB,UAAU,OAAO,QAAQ,GACnD,MAAM,IAAI,gCACT,KAAK,WAAW,MAChB,MAAM,SACN,cAAc,OAAO,QAAQ,GAC7B,cAAc,QAAQ,CACvB;IAEF;GACD;GAEA,MAAM,0CAA0B,IAAI,IAGlC;GACF,KAAK,MAAM,EAAE,OAAO,UAAU,aAAa,UAAU;IACpD,MAAM,MAAM,qBAAqB,SAAS,QAAQ;IAClD,MAAM,WAAW,wBAAwB,IAAI,GAAG;IAChD,IAAI,aAAa,UAAa,SAAS,YAAY,MAAM,SACxD,MAAM,IAAI,iCACT,KAAK,WAAW,MAChB,MAAM,SACN,SAAS,SACT,eAAe,QAAQ,CACxB;IAED,IACC,aAAa,UACb,CAAC,sBAAsB,UAAU,SAAS,QAAQ,GAElD,MAAM,IAAI,gCACT,KAAK,WAAW,MAChB,MAAM,SACN,cAAc,SAAS,QAAQ,GAC/B,cAAc,QAAQ,CACvB;IAED,wBAAwB,IAAI,KAAK;KAChC,SAAS,MAAM;KACf;IACD,CAAC;GACF;GAQA,MAAM,oCAAoB,IAAI,IAAgC;GAC9D,MAAM,uCAAuB,IAAI,IAAY;GAC7C,KAAK,MAAM,EAAE,OAAO,UAAU,aAAa,UAAU;IACpD,MAAM,MAAM,uBAAuB,OAAO;IAC1C,MAAM,SAAS,WAAW,IAAI,GAAG;IACjC,IAAI,WAAW,UAAa,CAAC,gBAAgB,UAAU,MAAM,GAC5D;IACD,MAAM,cAAc,qBAAqB,SAAS,QAAQ;IAC1D,IAAI,qBAAqB,IAAI,WAAW,GAAG;IAC3C,qBAAqB,IAAI,WAAW;IACpC,MAAM,SAAS,kBAAkB,IAAI,GAAG;IACxC,IAAI,WAAW,UAAa,gBAAgB,QAAQ,QAAQ,GAC3D,MAAM,IAAI,8BACT,KAAK,WAAW,MAChB,MAAM,SACN,eAAe,MAAM,GACrB,eAAe,QAAQ,CACxB;IAED,IAAI,WAAW,UAAa,gBAAgB,UAAU,MAAM,GAC3D,kBAAkB,IAAI,KAAK,QAAQ;GAErC;GAKA,MAAM,2BAAW,IAAI,IAGnB;GACF,MAAM,UAAiC,CAAC;GACxC,KAAK,MAAM,EAAE,OAAO,UAAU,aAAa,UAAU;IACpD,MAAM,MAAM,uBAAuB,OAAO;IAC1C,MAAM,YAAY,WAAW,IAAI,GAAG;IACpC,IAAI,cAAc,UAAa,CAAC,gBAAgB,UAAU,SAAS,GAAG;KACrE,WAAW;KACX;IACD;IACA,IAAI,CAAC,qBAAqB,UAAU,SAAS,GAC5C,MAAM,IAAI,mBACT,KAAK,WAAW,MAChB,MAAM,SACN,eAAe,SAAS,GACxB,eAAe,QAAQ,CACxB;IAED,WAAW,IAAI,KAAK,QAAQ;IAC5B,SAAS,IAAI,KAAK;KACjB;KACA,YAAY;MACX;MACA,oBAAoB,MAAM;KAC3B;IACD,CAAC;IACD,QAAQ,KAAK,EAAE,MAAM,CAAC;IACtB,WAAW;GACZ;GACA,KAAK,MAAM,EAAE,WAAW,SACvB,MAAM,KAAK,WAAW,MAAM,KAAK,KAAK;GAEvC,KAAK,MAAM,EAAE,SAAS,gBAAgB,SAAS,OAAO,GACrD,MAAM,KAAK,YAAY,KACtB,KACA,KAAK,WAAW,MAChB,SACA,UACD;GAED,OAAO;IAAE;IAAS;GAAQ;EAC3B;EACA,OAAO,KAAK,MAAM,eAChB,QACA,KAAK,YAAY,oBAChB,KACA,KAAK,WAAW,MAChB,qBACM,iBAAiB,GAAG,CAC3B,GACD,EAAE,QAAQ,QAAQ,OAAO,CAC1B;CACD;;;;;;;;CASA,aACC,SACA,UACmB;EACnB,OAAO,KAAK,YAAY,WAAW,KAAK,WAAW,MAAM,SAAS,QAAQ;CAC3E;;;;;;;;;CAUA,MAAM,QAAuB;EAC5B,MAAM,KAAK,MAAM,cAAc,OAAO,QAAQ;GAC7C,MAAM,KAAK,WAAW,WAAW,GAAG;GACpC,MAAM,KAAK,YAAY,MAAM,KAAK,KAAK,WAAW,IAAI;EACvD,CAAC;CACF;;;;;;;;;;;;;;CAeA,eAAgC;EAC/B,OAAO,EACN,SAAS,OAAO,QAAQ,YAAY;GACnC,MAAM,KAAK,QAAQ,CAAC,MAAM,GAAG,EAAE,QAAQ,QAAQ,OAAO,CAAC;EACxD,EACD;CACD;AACD;AAOA,SAAS,mBACR,UACyC;CACzC,OACC,OAAO,UAAU,SAAS,UAAU,KACpC,OAAO,OAAO,UAAU,kCAAkC;AAE5D;AAEA,SAAS,gBACR,UACyC;CACzC,IAAI,CAAC,mBAAmB,QAAQ,GAAG,OAAO;CAC1C,MAAM,WAAW,SAAS;CAC1B,OACC,OAAO,UAAU,SAAS,gBAAgB,KAC1C,SAAS,oBAAoB,KAC7B,OAAO,UAAU,SAAS,cAAc,KACxC,SAAS,kBAAkB,KAC3B,SAAS,aAAa,SAAS,mBAC9B,aAAa,QACZ,OAAO,UAAU,QAAQ,KACzB,YAAY,KACZ,WAAW,SAAS;AAExB;AAEA,SAAS,kBACR,YACqC;CACrC,IAAI,OAAO,eAAe,YAAY,eAAe,MAAM,OAAO;CAClE,MAAM,YAAY;CAClB,OACC,OAAO,UAAU,uBAAuB,YACxC,UAAU,mBAAmB,SAAS,KACtC,UAAU,aAAa,UACvB,gBAAgB,UAAU,QAAQ;AAEpC;AAEA,SAAS,sBACR,MACA,OACU;CACV,OACC,KAAK,qBAAqB,MAAM,oBAChC,KAAK,mBAAmB,MAAM;AAEhC;AAEA,SAAS,sBACR,MACA,OACU;CACV,OACC,sBAAsB,MAAM,KAAK,KACjC,KAAK,eAAe,MAAM,cAC1B,KAAK,qCACJ,MAAM;AAET;AAEA,SAAS,qBACR,SACA,UACS;CACT,OAAO,KAAK,UAAU;EACrB,QAAQ;EACR,QAAQ;EACR,SAAS;EACT,SAAS;CACV,CAAC;AACF;AAEA,SAAS,qBACR,WACA,WACU;CACV,IACC,UAAU,aAAa,KACvB,UAAU,iBAAiB,KAC3B,UAAU,kBAAkB,UAAU,YAEtC,OAAO;CAER,IAAI,cAAc,QACjB,OACC,UAAU,mBAAmB,KAC7B,UAAU,qCAAqC;CAGjD,IAAI,CAAC,mBAAmB,SAAS,GAAG,OAAO;CAC3C,IAAI,UAAU,qBAAqB,UAAU,kBAC5C,OACC,UAAU,qCACT,UAAU,oCACX,UAAU,eAAe,UAAU,cACnC,UAAU,mBAAmB,UAAU,iBAAiB;CAG1D,OACC,UAAU,mBAAmB,UAAU,aAAa,KACpD,UAAU,mBAAmB,KAC7B,UAAU,qCAAqC,UAAU;AAE3D;AAEA,SAAS,eAAe,UAAkD;CACzE,IAAI,aAAa,QAAW,OAAO;CACnC,OAAO,IAAI,SAAS,iBAAiB,IAAI,SAAS,eAAe;AAClE;AAEA,SAAS,cAAc,UAAsC;CAC5D,OACC,IAAI,SAAS,iBAAiB,IAAI,SAAS,eAAe,eAC5C,SAAS,WAAW,qCACE,OACnC,SAAS,gCACV,EAAE;AAEJ;;;;ACzjBA,SAAS,qBACR,MACA,OACO;CACP,IAAI,UAAU,WAAc,CAAC,OAAO,cAAc,KAAK,KAAK,QAAQ,IACnE,MAAM,IAAI,WACT,uBAAuB,KAAK,4CAA4C,OAAO,KAAK,GACrF;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;AA2BA,IAAa,qBAAb,MAEA;CACC,AAAiB,0BAAU,IAAI,IAAmB;CAClD,AAAiB;CACjB,AAAiB;CACjB,AAAQ,cAAc;CAEtB,YAAY,UAAqC,CAAC,GAAG;EACpD,IAAI,QAAQ,eAAe,QAC1B,0BACC,sBACA,cACA,QAAQ,UACT;EAED,IAAI,QAAQ,cAAc,QACzB,0BACC,sBACA,aACA,QAAQ,SACT;EAED,KAAK,aAAa,QAAQ;EAC1B,KAAK,YAAY,QAAQ;CAC1B;CAEA,MAAM,OACL,QACA,QACA,SACgB;EAChB,IAAI,OAAO,WAAW,GAAG;EACzB,MAAM,MAAM,uBAAuB,MAAM;EACzC,MAAM,WAAW,KAAK,QAAQ,IAAI,GAAG;EACrC,KAAK,UAAU,UAAU,OAAO,QAAQ,iBACvC,MAAM,IAAI,yBAAyB;GAClC,eAAe,OAAO;GACtB,aAAa,OAAO;GACpB,iBAAiB,QAAQ;GACzB,eAAe,UAAU,UAAU;EACpC,CAAC;EAEF,IACC,aAAa,UACb,KAAK,eAAe,UACpB,KAAK,QAAQ,QAAQ,KAAK,YAE1B,MAAM,IAAI,8BAA8B;GACvC,OAAO;GACP,UAAU;GACV,OAAO,KAAK;GACZ,SAAS,KAAK,QAAQ;GACtB,WAAW;EACZ,CAAC;EAEF,IACC,KAAK,cAAc,UACnB,KAAK,cAAc,OAAO,SAAS,KAAK,WAExC,MAAM,IAAI,8BAA8B;GACvC,OAAO;GACP,UAAU;GACV,OAAO,KAAK;GACZ,SAAS,KAAK;GACd,WAAW,OAAO;EACnB,CAAC;EASF,IAAI,eAAe;EACnB,IAAI,iBAAiB,QAAW;GAC/B,eAAe,CAAC;GAChB,KAAK,QAAQ,IAAI,KAAK,YAAY;EACnC;EACA,KAAK,MAAM,SAAS,QAKnB,aAAa,KAAK,gBAAgB,KAAK,CAAC;EAEzC,KAAK,eAAe,OAAO;CAC5B;CAEA,MAAM,WACL,QACA,SACiC;EACjC,IAAI,CAAC,OAAO,cAAc,SAAS,KAAK,KAAK,QAAQ,QAAQ,GAC5D,MAAM,IAAI,WACT,kEAAkE,OAAO,SAAS,KAAK,GACxF;EAED,qBAAqB,eAAe,QAAQ,WAAW;EACvD,qBAAqB,aAAa,QAAQ,SAAS;EACnD,MAAM,SAAS,KAAK,QAAQ,IAAI,uBAAuB,MAAM,CAAC;EAC9D,IAAI,WAAW,QACd,OAAO;GAAE,QAAQ;GAAO,aAAa;GAAG,QAAQ,CAAC;EAAE;EAEpD,MAAM,cAAc,QAAQ,eAAe;EAC3C,MAAM,YAAY,QAAQ;EAC1B,MAAM,UAAU,KAAK,IACpB,aAAa,OAAO,QACpB,cAAc,QAAQ,KACvB;EAIA,OAAO;GACN,QAAQ;GACR,aAAa,OAAO;GACpB,QAAQ,gBAAgB,OAAO,MAAM,aAAa,OAAO,CAAC;EAC3D;CACD;AACD;;;;;;;;;;;;;;;;;AClJA,IAAa,wBAAb,MAEA;CACC,AAAiB,4BAAY,IAAI,IAAoC;CACrE,AAAiB;CACjB,AAAiB;CACjB,AAAiB;CAEjB,YAAY,UAAwC,CAAC,GAAG;EACvD,IAAI,QAAQ,eAAe,QAC1B,0BACC,yBACA,cACA,QAAQ,UACT;EAED,IAAI,QAAQ,UAAU,QACrB,0BACC,yBACA,SACA,QAAQ,KACT;EAED,KAAK,aAAa,QAAQ;EAC1B,KAAK,QAAQ,QAAQ;EACrB,KAAK,QAAQ,QAAQ,gCAAgB,IAAI,KAAK;CAC/C;CAEA,MAAM,KACL,SACiD;EACjD,MAAM,MAAM,uBAAuB,OAAO;EAC1C,MAAM,SAAS,KAAK,UAAU,IAAI,GAAG;EACrC,IAAI,WAAW,QAAW,OAAO;EACjC,IACC,OAAO,gBAAgB,UACvB,KAAK,UAAU,KAAK,OAAO,aAC1B;GACD,KAAK,UAAU,OAAO,GAAG;GACzB;EACD;EAGA,KAAK,UAAU,OAAO,GAAG;EACzB,KAAK,UAAU,IAAI,KAAK,MAAM;EAC9B,OAAO,gBAAgB,OAAO,QAAQ;CACvC;CAEA,MAAM,KACL,SACA,UACgB;EAGhB,MAAM,gBAAgB,gBAAgB,QAAQ;EAC9C,MAAM,MAAM,uBAAuB,OAAO;EAC1C,IAAI;EACJ,IAAI,KAAK,UAAU,QAAW;GAC7B,MAAM,QAAQ,KAAK,UAAU;GAC7B,KAAK,cAAc,KAAK;GACxB,cAAc,QAAQ,KAAK;EAC5B;EACA,IAAI,KAAK,UAAU,IAAI,GAAG,GACzB,KAAK,UAAU,OAAO,GAAG;OACnB,IACN,KAAK,eAAe,UACpB,KAAK,UAAU,QAAQ,KAAK,YAC3B;GACD,MAAM,SAAS,KAAK,UAAU,KAAK,CAAC,CAAC,KAAK;GAC1C,IAAI,CAAC,OAAO,MAAM,KAAK,UAAU,OAAO,OAAO,KAAK;EACrD;EACA,KAAK,UAAU,IAAI,KAAK;GAAE,UAAU;GAAe;EAAY,CAAC;CACjE;CAEA,MAAM,OAAO,SAA0C;EACtD,KAAK,UAAU,OAAO,uBAAuB,OAAO,CAAC;CACtD;CAEA,AAAQ,YAAoB;EAC3B,MAAM,MAAM,KAAK,MAAM;EACvB,IAAI,EAAE,eAAe,SAAS,CAAC,OAAO,SAAS,IAAI,QAAQ,CAAC,GAC3D,MAAM,IAAI,UACT,uDACD;EAED,OAAO,IAAI,QAAQ;CACpB;CAEA,AAAQ,cAAc,OAAqB;EAC1C,KAAK,MAAM,CAAC,KAAK,WAAW,KAAK,WAChC,IAAI,OAAO,gBAAgB,UAAa,SAAS,OAAO,aACvD,KAAK,UAAU,OAAO,GAAG;CAG5B;AACD;;;;AC7EA,MAAM,uBAAuB;AAC7B,MAAM,wBAAwB;AAC9B,MAAM,uBAAuB;AAE7B,MAAM,gBAAgB;;AAGtB,SAAS,aAAa,IAAY,QAAqC;CACtE,OAAO,sBAAsB,IAAI,QAAQ,aAAa;AACvD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+BA,IAAa,2BAAb,MAA8E;CAY3D;CATlB,AAAiB;CACjB,AAAiB;CACjB,AAAiB;CACjB,AAAiB;CACjB,AAAiB;CACjB,AAAiB;CACjB,AAAiB;CAEjB,YACC,AAAiB,OACjB,SAAsB,CAAC,GACtB;EAFgB;EAGjB,KAAK,cAAc,OAAO,eAAe;EACzC,KAAK,cAAc,OAAO,eAAe;EACzC,KAAK,aAAa,OAAO,cAAc;EACvC,sBACC,4BACA,eACA,KAAK,WACN;EACA,wBACC,4BACA,eACA,KAAK,WACN;EACA,wBACC,4BACA,cACA,KAAK,UACN;EACA,KAAK,cAAc,OAAO,eAAe;EACzC,KAAK,QAAQ,OAAO,SAAS;EAI7B,KAAK,SAAS,oBAAoB,OAAO,UAAU,KAAK,MAAM;EAC9D,KAAK,UAAU,OAAO;CACvB;CAEA,MAAM,cACL,IACA,SACa;EACb,MAAM,EAAE,aAAa,aAAa,UAAU;EAC5C,MAAM,SAAS,SAAS;EACxB,MAAM,mBAAmB,UAA4B;GACpD,IAAI;IACH,OAAO,YAAY,KAAK;GACzB,QAAQ;IACP,OAAO;GACR;EACD;EAEA,KAAK,IAAI,UAAU,GAAG,WAAW,aAAa,WAAW;GACxD,IAAI,QAAQ,SACX,MAAM,YAAY,QAAQ,aAAa;GAExC,IAAI;IACH,OAAO,MAAM,KAAK,MAAM,cAAc,IAAI,OAAO;GAClD,SAAS,OAAO;IAQf,IAAI,YAAY,eAAe,CAAC,gBAAgB,KAAK,GACpD,MAAM;IAEP,MAAM,UAAU,oBAAoB,SAAS;KAC5C,aAAa,KAAK;KAClB,YAAY,KAAK;KACjB,QAAQ,KAAK;IACd,CAAC;IAGD,uBAAuB,KAAK,UAAU;KAAE;KAAS;KAAO;IAAQ,CAAC,CAAC;IAGlE,MAAM,MAAM,SAAS,MAAM;GAC5B;EACD;EAEA,MAAM,IAAI,MAAM,oDAAoD;CACrE;AACD;;;;;ACvHA,SAAgB,oBAIf,OAC4C;CAK5C,MAAM,WAAW,OAAO,OAAO,EAAE,GAAG,MAAM,CAAC;CAC3C,oBAAoB,QAAQ;CAC5B,OAAO;AACR;;;;;;AAOA,SAAgB,yBAIf,OACA,WACA,YACoC;CACpC,oBAAoB,KAAK;CACzB,MAAM,aAAa,eAAe,UAAU;CAC5C,MAAM,QAAQ,oBAAoB,MAAM,QAAQ,SAAS,CAAC;CAC1D,OAAO,OAAO,OAAO;EACpB;EACA,SAAS,UAAU;EACnB,YAAY;EACZ,eAAe,MAAM;CACtB,CAAC;AACF;;;;;;;;;;;;;AAcA,SAAgB,kCAIf,OACA,IACA,UACa;CACb,oBAAoB,KAAK;CACzB,MAAM,sBAAsB,SAAS,iBAAiB;CACtD,IAAI;CACJ,IAAI;EACH,IAAI;EACJ,IAAI,wBAAwB,MAAM,eACjC,QAAQ,oBAAoB,SAAS,KAAK;OACpC,IAAI,MAAM,SAChB,QAAQ,oBACP,MAAM,QAAQ,oBAAoB,SAAS,KAAK,GAAG,mBAAmB,CACvE;OAEA,MAAM,IAAI,4BAA4B;GACrC,eAAe,MAAM;GACrB,aAAa,OAAO,EAAE;GACtB,uBAAuB,MAAM;GAC7B,qBAAqB;EACtB,CAAC;EAEF,YAAY,MAAM,aAAa,IAAI,OAAO,SAAS,OAAO;CAC3D,SAAS,OAAO;EAIf,IAAI,kBAAkB,KAAK,GAC1B,MAAM,IAAI,uBACT,eAAe,MAAM,cAAc,GAAG,OAAO,EAAE,EAAE,WAC7C,oBAAoB,YAAY,OAAO,SAAS,OAAO,EAAE,iGAG7D,KACD;EAED,MAAM;CACP;CAKA,IAAI,UAAU,YAAY,SAAS,SAClC,MAAM,IAAI,UACT,kCAAkC,MAAM,cAAc,GAAG,OAAO,EAAE,EAAE,oCAC/B,OAAO,UAAU,OAAO,EAAE,6BACvC,OAAO,SAAS,OAAO,EAAE,8GAGlD;CAED,OAAO;AACR;AAEA,SAAS,oBAAoB,OAMpB;CACR,IACC,OAAO,MAAM,kBAAkB,YAC/B,MAAM,cAAc,KAAK,CAAC,CAAC,WAAW,GAEtC,MAAM,IAAI,UACT,wDACD;CAED,0BAA0B,iBAAiB,iBAAiB,MAAM,aAAa;CAC/E,KAAK,MAAM,OAAO,CAAC,WAAW,cAAc,GAC3C,IAAI,OAAO,MAAM,SAAS,YACzB,MAAM,IAAI,UACT,iBAAiB,IAAI,0JAGtB;CAGF,IAAI,MAAM,YAAY,UAAa,OAAO,MAAM,YAAY,YAC3D,MAAM,IAAI,UAAU,mDAAmD;AAEzE;AAEA,SAAS,eAAe,YAAwB;CAC/C,IAAI,EAAE,sBAAsB,SAAS,CAAC,OAAO,SAAS,WAAW,QAAQ,CAAC,GACzE,MAAM,IAAI,4BAA4B;CAEvC,OAAO,IAAI,KAAK,WAAW,QAAQ,CAAC;AACrC;AAEA,SAAS,oBAAuB,OAAa;CAC5C,mBAAmB,OAAO,oBAAI,IAAI,QAAQ,CAAC;CAC3C,OAAO,gBAAgB,KAAK;AAC7B;;;;;AAMA,SAAS,mBACR,OACA,MACA,MACO;CACP,IAAI,OAAO,UAAU,YACpB,MAAM,IAAI,UACT,iBAAiB,KAAK,kEACvB;CAID,IAAI,OAAO,UAAU,UACpB,MAAM,IAAI,UACT,iBAAiB,KAAK,gEACvB;CAED,IAAI,UAAU,QAAQ,OAAO,UAAU,UAAU;CACjD,MAAM,SAAS;CACf,IAAI,KAAK,IAAI,MAAM,GAAG;CACtB,KAAK,IAAI,MAAM;CAEf,IAAI,MAAM,QAAQ,MAAM,GAAG;EAC1B,KAAK,IAAI,QAAQ,GAAG,QAAQ,OAAO,QAAQ,SAC1C,mBAAmB,OAAO,QAAQ,GAAG,KAAK,GAAG,MAAM,IAAI,IAAI;EAE5D;CACD;CAEA,MAAM,MAAM,OAAO,UAAU,SAAS,KAAK,MAAM;CACjD,IAAI,gBAAgB,QAAQ,GAAG,GAAG;EACjC,IAAI,QAAQ,gBAAgB;GAC3B,IAAI,QAAQ;GACZ,KAAK,MAAM,CAAC,KAAK,UAAU,QAAiC;IAC3D,mBAAmB,KAAK,GAAG,KAAK,YAAY,MAAM,IAAI,IAAI;IAC1D,mBAAmB,OAAO,GAAG,KAAK,cAAc,MAAM,IAAI,IAAI;IAC9D;GACD;GACA;EACD;EACA,IAAI,QAAQ,gBAAgB;GAC3B,IAAI,QAAQ;GACZ,KAAK,MAAM,UAAU,QAAwB;IAC5C,mBAAmB,QAAQ,GAAG,KAAK,eAAe,MAAM,IAAI,IAAI;IAChE;GACD;GACA;EACD;EACA,IACC,QAAQ,sBACR,QAAQ,sBACR,QAAQ,oBAER,MAAM,IAAI,UACT,iBAAiB,KAAK,QAAQ,IAAI,MAAM,GAAG,EAAE,EAAE,yBAChD;EAED,IAAI,QAAQ,kBACX,MAAM,IAAI,UACT,iBAAiB,KAAK,yDACvB;EAED;CACD;CAEA,MAAM,YAAY,OAAO,eAAe,MAAM;CAC9C,IAAI,cAAc,OAAO,aAAa,cAAc,MAAM;EACzD,KAAK,MAAM,OAAO,QAAQ,QAAQ,MAAM,GAAG;GAE1C,IAAI,CADe,OAAO,yBAAyB,QAAQ,GAC7C,CAAC,EAAE,YAAY;GAC7B,IAAI,OAAO,QAAQ,UAClB,MAAM,IAAI,UACT,iBAAiB,KAAK,yEACvB;GAED,mBACE,OAAwC,MACzC,GAAG,KAAK,GAAG,OACX,IACD;EACD;EACA;CACD;CAEA,MAAM,OAAe,UAAU,aAAa,QAAQ;CACpD,MAAM,IAAI,UACT,iBAAiB,KAAK,wBAAwB,KAAK,8CACpD;AACD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC3OA,IAAsB,gBAAtB,MAAuC;;;;;CAYtC,AAAS;;CAMT,IAAI,OAA2C;EAC9C,OAAO,IAAI,6BAA6B,OAAO,MAAM,KAAK;CAC3D;;CAGA,GAAG,OAA2C;EAC7C,OAAO,IAAI,6BAA6B,MAAM,MAAM,KAAK;CAC1D;;CAGA,MAAwB;EACvB,OAAO,IAAI,iBAAiB,IAAI;CACjC;;CAGA,WAAmB;EAClB,OAAO,KAAK;CACb;AACD;;;;;;;;;AAUA,SAAgB,cACf,MACA,WACmB;CACnB,IAAI,KAAK,KAAK,CAAC,CAAC,WAAW,KAAK,SAAS,KAAK,KAAK,GAClD,MAAM,IAAI,MACT,iMAGD;CAED,OAAO,IAAI,uBAAuB,MAAM,SAAS;AAClD;AAEA,IAAM,yBAAN,cAAwC,cAAiB;CAE9C;CACQ;CAFlB,YACC,AAAS,MACT,AAAiB,WAChB;EACD,MAAM;EAHG;EACQ;CAGlB;CAEA,cAAc,WAAuB;EACpC,OAAO,KAAK,UAAU,SAAS;CAChC;AACD;AAEA,IAAM,+BAAN,cAA8C,cAAiB;CAC9D,AAAkB;CAKlB,AAAQ;CAER,YACC,UACA,MACA,OACC;EACD,MAAM;EAIN,KAAK,YAAY,OAAO,OAAO;GAAE;GAAU;GAAM;EAAM,CAAC;CACzD;CAIA,IAAI,OAAe;EAClB,KAAK,eAAe,IAAI,KAAK,UAAU,KAAK,KAAK,GAAG,KAAK,UAAU,SAAS,GAAG,KAAK,UAAU,MAAM,KAAK;EACzG,OAAO,KAAK;CACb;CAEA,cAAc,WAAuB;EACpC,MAAM,EAAE,UAAU,MAAM,UAAU,KAAK;EACvC,OAAO,aAAa,QACjB,KAAK,cAAc,SAAS,KAAK,MAAM,cAAc,SAAS,IAC9D,KAAK,cAAc,SAAS,KAAK,MAAM,cAAc,SAAS;CAClE;AACD;AAEA,IAAM,mBAAN,cAAkC,cAAiB;CAClD,AAAkB;CAIlB,AAAQ;CAER,YAAY,OAAyB;EACpC,MAAM;EACN,KAAK,YAAY,OAAO,OAAO;GAAE,UAAU;GAAO;EAAM,CAAC;CAC1D;CAEA,IAAI,OAAe;EAClB,KAAK,eAAe,QAAQ,KAAK,UAAU,MAAM,KAAK;EACtD,OAAO,KAAK;CACb;CAEA,cAAc,WAAuB;EACpC,OAAO,CAAC,KAAK,UAAU,MAAM,cAAc,SAAS;CACrD;AACD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACrKA,SAAgB,YACf,GACA,UACA,UAAU,qBACuB;CACjC,MAAM,SAAS,IAAI,gBAAgB,OAAO;CAC1C,SAAS,QAAQ,CAAC;CAClB,OAAO,OAAO,UAAU,IAAI,IAAI,MAAM,IAAI,GAAG,GAAG,CAAC,CAAC;AACnD"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["invalid","capabilities","require","capabilities","#snapshot","#evaluating"],"sources":["../src/application/cqrs/internal/bus-internals.ts","../src/application/cqrs/command/command-bus.ts","../src/internal/json-value.ts","../src/application/cqrs/command/command-outbox.ts","../src/domain/aggregate/internal/global-capability-registry.ts","../src/domain/aggregate/pending-event-lifecycle.ts","../src/internal/async/abort.ts","../src/internal/validate.ts","../src/internal/async/execution.ts","../src/internal/observer.ts","../src/application/cqrs/handler.ts","../src/application/cqrs/query/query-bus.ts","../src/application/deadlines/adapters/in-memory-deadline-store.ts","../src/internal/async/backoff.ts","../src/internal/async/in-flight.ts","../src/internal/async/sleep.ts","../src/internal/async/poll-loop.ts","../src/internal/delivery-failure.ts","../src/application/deadlines/deadline-processor.ts","../src/application/domain-error-result.ts","../src/application/idempotency/adapters/in-memory-idempotency-store.ts","../src/application/idempotency/idempotency.ts","../src/domain/aggregate/aggregate-address.ts","../src/application/projections/ports.ts","../src/application/projections/adapters/in-memory-checkpoint-store.ts","../src/application/projections/projection-from-handlers.ts","../src/application/projections/projector.ts","../src/application/unit-of-work/errors.ts","../src/domain/aggregate/pending-event-recording.ts","../src/application/unit-of-work/record-pending-events.ts","../src/application/unit-of-work/repository-facade.ts","../src/persistence/repository/identity-map.ts","../src/persistence/repository/persistence-model.ts","../src/application/unit-of-work/unit-of-work-session.ts","../src/application/unit-of-work/unit-of-work.ts","../src/domain/aggregate/aggregate.ts","../src/domain/entity/entity.ts","../src/domain/aggregate/base-aggregate.ts","../src/domain/aggregate/event-sourced-aggregate.ts","../src/domain/aggregate/state-stored-aggregate.ts","../src/domain/specification/specification.ts","../src/domain/state-machine/errors.ts","../src/domain/state-machine/machine-data.ts","../src/domain/state-machine/definition.ts","../src/domain/state-machine/snapshot.ts","../src/domain/state-machine/transition.ts","../src/domain/state-machine/analyzer.ts","../src/domain/state-machine/domain-state-machine.ts","../src/domain/value-object/vo-validated.ts","../src/internal/structural/detach-state.ts","../src/messaging/event-bus/errors.ts","../src/messaging/event-bus/publish-chain.ts","../src/messaging/event-bus/event-bus.ts","../src/messaging/integration-message/integration-message.ts","../src/messaging/outbox/outbox.ts","../src/messaging/outbox/outbox-dispatcher.ts","../src/persistence/event-store/adapters/in-memory-event-store.ts","../src/persistence/repository/retrying-scope.ts","../src/persistence/snapshot-store/adapters/in-memory-snapshot-store.ts","../src/persistence/snapshot-store/snapshot-model.ts"],"sourcesContent":["import { err, type Result } from \"@shirudo/result\";\nimport {\n\tDuplicateHandlerRegistrationError,\n\tErrorMapperFailedError,\n\tUnregisteredHandlerError,\n} from \"../../../errors/kit-errors\";\n\n/**\n * INTERNAL shared pieces of `CommandBus` and `QueryBus`. The two buses are\n * deliberately separate public classes (distinct docs, distinct handler\n * types), but their wiring semantics must not drift: the expected-error\n * decision shape, register-once guard, no-handler gate, and handler-failure\n * classification live here exactly once. Not exported from any package entry.\n */\n\n/**\n * A positive classification decision from a bus's expected-error mapper.\n * The wrapper makes `undefined` a valid error-channel value without making\n * it ambiguous with the mapper declining to classify a thrown value.\n */\nexport interface ExpectedErrorDecision<E> {\n\treadonly error: E;\n}\n\n/**\n * Classifies and maps one handler throw. Returning `undefined` declines the\n * failure, which makes the bus rethrow the exact original value.\n */\nexport type ExpectedErrorMapper<E> = (\n\tthrown: unknown,\n) => ExpectedErrorDecision<E> | undefined;\n\n/**\n * Keeps manual result typing available only for the deliberately untyped\n * default map. Concrete maps, typed or refined index maps, and `any` keep their\n * mapped result contract authoritative.\n */\nexport type UntypedMapDispatch<\n\tTMap extends Record<string, unknown>,\n\tTMessage,\n> = 0 extends 1 & TMap\n\t? never\n\t: string extends keyof TMap\n\t\t? Record<string, unknown> extends TMap\n\t\t\t? TMessage\n\t\t\t: never\n\t\t: never;\n\n/**\n * Registers a handler exactly once. Silent replacement would turn the first\n * handler into dead code with no signal; wiring bugs must surface at\n * registration time.\n */\nexport function registerOnce<THandler>(\n\thandlers: Map<string, THandler>,\n\tbusKind: \"command\" | \"query\",\n\ttype: string,\n\thandler: THandler,\n): void {\n\tif (handlers.has(type)) {\n\t\tthrow new DuplicateHandlerRegistrationError({\n\t\t\tbusKind,\n\t\t\tmessageType: type,\n\t\t});\n\t}\n\thandlers.set(type, handler);\n}\n\n/**\n * Shared no-handler gate for dispatch: a wiring bug throws\n * `UnregisteredHandlerError` (crash-loud, same posture as\n * `MissingHandlerError`), it never rides the error channel. One\n * implementation so the buses and their unsafe paths cannot drift.\n */\nexport function handlerOrThrow<THandler>(\n\thandlers: Map<string, THandler>,\n\tbusKind: \"command\" | \"query\",\n\ttype: string,\n): THandler {\n\tconst handler = handlers.get(type);\n\tif (!handler) {\n\t\tthrow new UnregisteredHandlerError({ busKind, messageType: type });\n\t}\n\treturn handler;\n}\n\n/**\n * Classifies one registered handler failure. Absence of a mapper or an\n * `undefined` decision preserves and rethrows the exact failure: unknown\n * programmer, cancellation, and infrastructure errors cannot silently ride\n * a Result channel. A nested dispatch's wiring error always bypasses the\n * policy. A mapper that throws or returns a malformed decision is itself a\n * wiring bug and is wrapped without losing either cause.\n */\nexport function mapHandlerFailure<E>(\n\terror: unknown,\n\tmapExpectedError: ExpectedErrorMapper<E> | undefined,\n\tbusKind: \"command\" | \"query\",\n): Result<never, E> {\n\tif (\n\t\terror instanceof UnregisteredHandlerError ||\n\t\terror instanceof ErrorMapperFailedError\n\t) {\n\t\tthrow error;\n\t}\n\tif (!mapExpectedError) throw error;\n\n\tlet decision: ExpectedErrorDecision<E> | undefined;\n\ttry {\n\t\tdecision = mapExpectedError(error);\n\t} catch (mapperError) {\n\t\tthrow new ErrorMapperFailedError({\n\t\t\tbusKind,\n\t\t\thandlerError: error,\n\t\t\tmapperError,\n\t\t});\n\t}\n\tif (decision === undefined) throw error;\n\n\tlet mapped: E;\n\ttry {\n\t\tconst candidate: unknown = decision;\n\t\tif (\n\t\t\ttypeof candidate !== \"object\" ||\n\t\t\tcandidate === null ||\n\t\t\t!Object.hasOwn(candidate, \"error\")\n\t\t) {\n\t\t\tthrow new TypeError(\n\t\t\t\t\"mapExpectedError must return undefined or an own { error } decision\",\n\t\t\t);\n\t\t}\n\t\tmapped = (candidate as ExpectedErrorDecision<E>).error;\n\t} catch (mapperError) {\n\t\tthrow new ErrorMapperFailedError({\n\t\t\tbusKind,\n\t\t\thandlerError: error,\n\t\t\tmapperError,\n\t\t});\n\t}\n\treturn err(mapped);\n}\n","import type { Result } from \"@shirudo/result\";\nimport {\n\ttype ExpectedErrorMapper,\n\thandlerOrThrow,\n\tmapHandlerFailure,\n\tregisterOnce,\n\ttype UntypedMapDispatch,\n} from \"../internal/bus-internals\";\nimport type { Command, CommandHandler } from \"./command\";\n\n/**\n * Internal adapter shape for handlers stored in the map.\n *\n * Registered handlers are typed as `CommandHandler<C, TMap[K]>` (narrower\n * input, specific return) and cannot be stored directly in a heterogeneous\n * map (function-parameter contravariance). The closure in `register`\n * downcasts `Command` to the handler's expected `C` based on the\n * dispatch-key invariant (we only call this entry when `cmd.type` matches\n * the key it was registered under). Result is widened to `unknown` here\n * and narrowed back via the public overloads on `execute`.\n */\ntype StoredCommandHandler<E> = (cmd: Command) => Promise<Result<unknown, E>>;\n\n/**\n * Type map for command types to their return types.\n * Used to improve type inference in CommandBus.\n *\n * @example\n * ```typescript\n * type MyCommandMap = {\n * CreateOrder: OrderId;\n * CancelOrder: void;\n * };\n *\n * const bus = new CommandBus<MyCommandMap>();\n * const result = await bus.execute({ type: \"CreateOrder\", ... });\n * // result: Result<OrderId, string> ← automatically inferred\n * ```\n */\ntype CommandTypeMap = Record<string, unknown>;\n\n/**\n * Construction options for {@link CommandBus}.\n *\n * @template E - The error channel type of the bus.\n */\nexport interface CommandBusOptions<E = string> {\n\t/**\n\t * Explicitly recognizes an expected handler failure and maps it into the\n\t * bus's error channel. Return `{ error }` only for failures this boundary\n\t * owns; return `undefined` to rethrow the exact original value. With no\n\t * mapper, every handler throw propagates. Unregistered-handler and nested\n\t * bus wiring errors always propagate.\n\t */\n\tmapExpectedError?: (thrown: unknown) => { readonly error: E } | undefined;\n}\n\n/**\n * Command Bus interface for dispatching commands to their handlers.\n * Provides a centralized way to execute commands with handler registration.\n *\n * Supports an optional type map (`TMap`) for automatic return type inference.\n * Without a type map, the return type must be specified manually or defaults to `unknown`.\n * With a concrete result map, its entry is the only result type for that\n * command; the loose explicit-result overload is unavailable.\n *\n * @template TMap - Optional mapping from command type strings to return types\n *\n * @example\n * ```typescript\n * // With a type map (recommended): the return type is inferred\n * type MyCommands = { CreateOrder: OrderId; CancelOrder: void };\n * const bus = new CommandBus<MyCommands>();\n * const result = await bus.execute({ type: \"CreateOrder\", ... });\n * // result: Result<OrderId, string>\n *\n * // Without a type map: the return type defaults to `unknown`\n * const bus = new CommandBus();\n * bus.register(\"CreateOrder\", createOrderHandler);\n * const result = await bus.execute({ type: \"CreateOrder\", ... });\n * // result: Result<unknown, string>\n * ```\n */\nexport interface ICommandBus<\n\tTMap extends CommandTypeMap = CommandTypeMap,\n\tE = string,\n> {\n\t/**\n\t * Executes a command by dispatching it to the registered handler.\n\t * When a type map is provided, the return type is inferred from the command type.\n\t *\n\t * @param command - The command to execute\n\t * @returns Result containing the success value or an error of type `E`\n\t * @throws UnregisteredHandlerError when no handler is registered for\n\t * `command.type` (a wiring bug; never delivered through the channel)\n\t * @throws The exact handler failure when `mapExpectedError` is absent or\n\t * returns `undefined`\n\t * @throws ErrorMapperFailedError when `mapExpectedError` fails\n\t */\n\texecute<C extends Command & { type: keyof TMap & string }>(\n\t\tcommand: C,\n\t): Promise<Result<TMap[C[\"type\"]], E>>;\n\t// Manual result typing belongs only to the default untyped map shape.\n\texecute<C extends Command, R>(\n\t\tcommand: UntypedMapDispatch<TMap, C>,\n\t): Promise<Result<R, E>>;\n\n\t/**\n\t * Registers a handler for a specific command type.\n\t *\n\t * When `TMap` is supplied, the `commandType` argument is restricted to\n\t * its keys and the handler signature is forced to match `TMap[K]` for the\n\t * return value: typos and wrong-typed handlers are compile errors.\n\t * Without `TMap` the registration is loose (any string key, any return\n\t * type) so the no-config path keeps working.\n\t *\n\t * @param commandType - The command type to register the handler for\n\t * @param handler - The handler function for this command type\n\t */\n\tregister<\n\t\tK extends keyof TMap & string,\n\t\tC extends Command & { type: K } = Command & { type: K },\n\t>(commandType: K, handler: CommandHandler<C, TMap[K], E>): void;\n}\n\n/**\n * Simple in-memory command bus implementation.\n * Handlers are stored in a Map and dispatched based on command type.\n *\n * Supports an optional type map (`TMap`) for automatic return type inference.\n * When `TMap` is concrete, `execute()` infers the result type from the command type.\n * An explicit competing result generic cannot override that map.\n * Without `TMap`, the return type defaults to `unknown` or is specified per call.\n *\n * **Note:** This is a basic implementation suitable for development and simple use cases.\n * For production environments, consider implementing or using a more feature-rich bus that includes:\n * - Middleware/Pipeline support (logging, validation, authorization)\n * - Error handling and retry logic\n * - Timeout handling\n * - Metrics and observability\n * - Transaction management\n * - Dead letter queue support\n *\n * The `CommandHandler` type can still be used with external production-grade buses\n * (e.g., RabbitMQ, AWS SQS) while maintaining type safety.\n *\n * @template TMap - Optional mapping from command type strings to return types\n *\n * @example\n * ```typescript\n * // With a type map: full inference\n * type Commands = { CreateOrder: OrderId; CancelOrder: void };\n * const bus = new CommandBus<Commands>();\n * const result = await bus.execute({ type: \"CreateOrder\", ... });\n * // result: Result<OrderId, string>\n *\n * // Without a type map: specify the return type per call\n * const bus = new CommandBus();\n * bus.register(\"CreateOrder\", async (cmd) => ok(orderId));\n * const result = await bus.execute({ type: \"CreateOrder\", ... });\n * ```\n */\nexport class CommandBus<\n\tTMap extends CommandTypeMap = CommandTypeMap,\n\tE = string,\n> implements ICommandBus<TMap, E>\n{\n\tprivate readonly handlers = new Map<string, StoredCommandHandler<E>>();\n\tprivate readonly mapExpectedError: ExpectedErrorMapper<E> | undefined;\n\n\tconstructor(options?: CommandBusOptions<E>) {\n\t\tthis.mapExpectedError = options?.mapExpectedError;\n\t}\n\n\tregister<\n\t\tK extends keyof TMap & string,\n\t\tC extends Command & { type: K } = Command & { type: K },\n\t>(commandType: K, handler: CommandHandler<C, TMap[K], E>): void {\n\t\tregisterOnce(this.handlers, \"command\", commandType, (cmd: Command) =>\n\t\t\thandler(cmd as C),\n\t\t);\n\t}\n\n\tasync execute<C extends Command & { type: keyof TMap & string }>(\n\t\tcommand: C,\n\t): Promise<Result<TMap[C[\"type\"]], E>>;\n\t// Keep the class surface identical to ICommandBus's untyped fallback.\n\tasync execute<C extends Command, R>(\n\t\tcommand: UntypedMapDispatch<TMap, C>,\n\t): Promise<Result<R, E>>;\n\tasync execute<C extends Command, R>(command: C): Promise<Result<R, E>> {\n\t\t// No-handler dispatch is a wiring bug, not a domain failure: thrown,\n\t\t// never delivered through the error channel (see handlerOrThrow).\n\t\tconst handler = handlerOrThrow(this.handlers, \"command\", command.type);\n\t\ttry {\n\t\t\treturn (await handler(command)) as Result<R, E>;\n\t\t} catch (error) {\n\t\t\treturn mapHandlerFailure(error, this.mapExpectedError, \"command\");\n\t\t}\n\t}\n}\n","/** A primitive value represented without loss by JSON. */\nexport type JsonPrimitive = boolean | null | number | string;\n\n/** A recursively JSON-safe value. Runtime validation rejects lossy shapes. */\nexport type JsonValue =\n\t| JsonPrimitive\n\t| ReadonlyArray<JsonValue>\n\t| { readonly [key: string]: JsonValue };\n\n/** A JSON-safe object. */\nexport type JsonObject = { readonly [key: string]: JsonValue };\n\n/** Non-null, non-array object shape check shared by the message boundaries. */\nexport function isJsonObject(value: unknown): value is JsonObject {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\ntype InvalidJsonValue = (path: string, reason: string) => never;\n\n/**\n * Proves that JSON serialization preserves a value exactly.\n *\n * The caller owns the boundary-specific error type through `invalid`.\n */\nexport function assertJsonValue(\n\tvalue: unknown,\n\tpath: string,\n\tinvalid: InvalidJsonValue,\n\tactive = new WeakSet<object>(),\n): asserts value is JsonValue {\n\tif (value === null) return;\n\tswitch (typeof value) {\n\t\tcase \"string\":\n\t\tcase \"boolean\":\n\t\t\treturn;\n\t\tcase \"number\":\n\t\t\tif (!Number.isFinite(value)) {\n\t\t\t\treturn invalid(path, \"numbers must be finite JSON numbers\");\n\t\t\t}\n\t\t\t// JSON.stringify(-0) produces \"0\", so negative zero does not\n\t\t\t// round-trip; rejecting it keeps the exactness contract honest.\n\t\t\tif (Object.is(value, -0)) {\n\t\t\t\treturn invalid(path, \"negative zero changes to 0 in JSON\");\n\t\t\t}\n\t\t\treturn;\n\t\tcase \"object\":\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tinvalid(path, `value of type ${typeof value} is not JSON-safe`);\n\t}\n\n\tif (active.has(value)) {\n\t\tinvalid(path, \"cyclic references are not JSON-safe\");\n\t}\n\tactive.add(value);\n\tif (Array.isArray(value)) {\n\t\tfor (const key of Reflect.ownKeys(value)) {\n\t\t\tif (key === \"length\") continue;\n\t\t\tif (typeof key === \"symbol\") {\n\t\t\t\tinvalid(path, \"symbol-keyed array properties would be dropped by JSON\");\n\t\t\t}\n\t\t\tconst index = Number(key);\n\t\t\tif (\n\t\t\t\t!Number.isInteger(index) ||\n\t\t\t\tindex < 0 ||\n\t\t\t\tindex >= value.length ||\n\t\t\t\tString(index) !== key\n\t\t\t) {\n\t\t\t\tinvalid(\n\t\t\t\t\t`${path}.${key}`,\n\t\t\t\t\t\"named array properties would be dropped by JSON\",\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\tfor (let index = 0; index < value.length; index += 1) {\n\t\t\tconst descriptor = Object.getOwnPropertyDescriptor(value, index);\n\t\t\tif (descriptor === undefined) {\n\t\t\t\tinvalid(\n\t\t\t\t\t`${path}[${index}]`,\n\t\t\t\t\t\"sparse array holes would change to null in JSON\",\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (!(\"value\" in descriptor) || !descriptor.enumerable) {\n\t\t\t\tinvalid(\n\t\t\t\t\t`${path}[${index}]`,\n\t\t\t\t\t\"accessor and non-enumerable array elements are not JSON-safe\",\n\t\t\t\t);\n\t\t\t}\n\t\t\tassertJsonValue(descriptor.value, `${path}[${index}]`, invalid, active);\n\t\t}\n\t\tactive.delete(value);\n\t\treturn;\n\t}\n\n\tconst prototype = Object.getPrototypeOf(value);\n\tif (prototype !== Object.prototype && prototype !== null) {\n\t\tinvalid(\n\t\t\tpath,\n\t\t\t\"Date, Map, Set, and class instances are not JSON-safe here; map \" +\n\t\t\t\t\"them explicitly to strings, arrays, or plain objects\",\n\t\t);\n\t}\n\tfor (const key of Reflect.ownKeys(value)) {\n\t\tif (typeof key === \"symbol\") {\n\t\t\tinvalid(path, \"symbol-keyed properties would be dropped by JSON\");\n\t\t}\n\t\tconst descriptor = Object.getOwnPropertyDescriptor(value, key);\n\t\tif (descriptor === undefined) continue;\n\t\tconst childPath = `${path}.${key}`;\n\t\tif (key === \"__proto__\") {\n\t\t\tinvalid(\n\t\t\t\tchildPath,\n\t\t\t\t\"hostile __proto__ keys are not accepted at integration boundaries\",\n\t\t\t);\n\t\t}\n\t\tif (!(\"value\" in descriptor) || !descriptor.enumerable) {\n\t\t\tinvalid(\n\t\t\t\tchildPath,\n\t\t\t\t\"accessor and non-enumerable properties are not JSON-safe\",\n\t\t\t);\n\t\t}\n\t\tassertJsonValue(descriptor.value, childPath, invalid, active);\n\t}\n\tactive.delete(value);\n}\n","import type { AggregateAddress } from \"../../../domain/aggregate/aggregate-address\";\nimport type { AnyDomainEvent } from \"../../../domain/event/domain-event\";\nimport { deepFreeze } from \"../../../domain/value-object/value-object\";\nimport { InvalidCommandMessageError } from \"../../../errors/kit-errors\";\nimport {\n\tassertJsonValue,\n\tisJsonObject,\n\ttype JsonObject,\n} from \"../../../internal/json-value\";\nimport type {\n\tEventCommitCandidate,\n\tEventCommitCandidatePosition,\n} from \"../../../messaging/committed-event\";\nimport type { OutboxWriter } from \"../../../messaging/outbox/ports\";\nimport type { PublishedCommand } from \"./command\";\n\n/**\n * Business relationships and technical trace context selected explicitly for\n * an outgoing command. Correlation/conversation explain the business flow;\n * W3C Trace Context connects technical spans.\n */\nexport interface CommandMessageRelationships {\n\t/** Groups messages that belong to one operation or trace. */\n\treadonly correlationId?: string;\n\t/** Groups every message in one long-running business interaction. */\n\treadonly conversationId?: string;\n\t/** W3C Trace Context parent for technical distributed tracing. */\n\treadonly traceparent?: string;\n\t/** Optional vendor trace state associated with `traceparent`. */\n\treadonly tracestate?: string;\n}\n\n/**\n * Application-owned Published Language produced from one private domain or\n * process event. `destination` names one receiver contract; it is deliberately\n * required because a command is an instruction, not a broadcast fact.\n *\n * The command carries a stable schema `version` and JSON-safe `payload`.\n * Domain value objects are translated to wire DTOs by the mapper before this\n * boundary.\n */\nexport interface CommandMessageContent<C extends PublishedCommand>\n\textends CommandMessageRelationships {\n\treadonly destination: string;\n\treadonly command: C;\n}\n\n/**\n * Immutable, JSON-safe command envelope stored for later at-least-once\n * delivery.\n *\n * `causationId` always identifies the private event whose accepted decision\n * requested this command. The mapper cannot replace it with a weaker\n * correlation. Consumer-produced events should in turn use `messageId` as\n * their causation id.\n */\nexport interface DurableCommandMessage<C extends PublishedCommand>\n\textends CommandMessageContent<C> {\n\treadonly messageId: string;\n\treadonly recordedAt: string;\n\treadonly causationId: string;\n}\n\n/**\n * Receipt for the private event that requested one command batch. It retains\n * commit identity and ordering without putting the private event or its\n * payload into the command outbox.\n */\nexport interface CommandCommitOriginCandidate {\n\treadonly eventId: string;\n\treadonly source: AggregateAddress;\n\treadonly position: EventCommitCandidatePosition;\n}\n\n/**\n * One private process-event commit and the exact commands it requested.\n * `messages` may be empty: the receipt still advances the originating source\n * and makes an exact retry distinguishable from a missing commit.\n */\nexport interface CommandOutboxCommitCandidate<C extends PublishedCommand> {\n\treadonly origin: CommandCommitOriginCandidate;\n\treadonly messages: ReadonlyArray<DurableCommandMessage<C>>;\n}\n\n/**\n * Write port for a dedicated transactional command outbox.\n *\n * The adapter is bound to the same ambient transaction as the aggregate or\n * event-stream repository. It must persist the complete input atomically,\n * retain input order, deduplicate exact retries by `origin.eventId`, and reject\n * a reused origin id whose source, position, or messages differ. It also owns\n * the durable source cursor represented by `origin.position`; an empty command\n * batch still advances that cursor.\n *\n * Delivery is out of band and at least once. A consumer therefore uses\n * `message.messageId` as its idempotency key and acknowledges only after the\n * command result has been stored.\n */\nexport interface CommandOutboxWriter<C extends PublishedCommand> {\n\tadd(commits: ReadonlyArray<CommandOutboxCommitCandidate<C>>): Promise<void>;\n}\n\n/** Maps one private accepted event to zero or more addressed commands. */\nexport type CommandOutboxMapper<\n\tEvt extends AnyDomainEvent,\n\tC extends PublishedCommand,\n> = (event: Evt) => ReadonlyArray<CommandMessageContent<C>>;\n\n/**\n * Adapts a dedicated command outbox to the event-candidate write port consumed\n * by `withCommit`.\n *\n * Mapping happens inside the transaction, before the command outbox write.\n * The private event is used only at this boundary and is reduced to an origin\n * receipt. The helper never publishes it or copies its payload implicitly; the\n * application mapper selects and translates the data that belongs in the\n * versioned Published Language. The route rejects values JSON would lose or\n * change before it calls the adapter.\n * Every command gets a stable id derived from the event id and its zero-based\n * order, so an exact transaction retry produces the same rows.\n *\n * Omit `withCommit`'s in-process `bus` for private process events. Participants\n * consume the durable command messages from their explicitly named\n * destinations, while event-stream replay only rebuilds process state.\n */\nexport function routeEventsToCommandOutbox<\n\tC extends PublishedCommand,\n\tEvt extends AnyDomainEvent = AnyDomainEvent,\n>(\n\toutbox: CommandOutboxWriter<C>,\n\tmapper: CommandOutboxMapper<Evt, C>,\n): OutboxWriter<Evt> {\n\treturn {\n\t\tadd: async (events) => {\n\t\t\tconst commits = events.map((candidate) =>\n\t\t\t\ttoCommandCommit(candidate, mapper),\n\t\t\t);\n\t\t\tawait outbox.add(commits);\n\t\t},\n\t};\n}\n\nfunction toCommandCommit<\n\tEvt extends AnyDomainEvent,\n\tC extends PublishedCommand,\n>(\n\tcandidate: EventCommitCandidate<Evt>,\n\tmapper: CommandOutboxMapper<Evt, C>,\n): CommandOutboxCommitCandidate<C> {\n\tconst mapped = mapper(candidate.event);\n\tif (!Array.isArray(mapped)) {\n\t\tthrow new TypeError(\n\t\t\t\"Command outbox mapper must return a readonly array of commands\",\n\t\t);\n\t}\n\tconst messages = Array.from(mapped, (content, index) =>\n\t\ttoDurableCommand<C>(candidate.event, content, index),\n\t);\n\treturn deepFreeze({\n\t\torigin: {\n\t\t\teventId: candidate.event.eventId,\n\t\t\tsource: { ...candidate.source },\n\t\t\tposition: { ...candidate.position },\n\t\t},\n\t\tmessages,\n\t}) as CommandOutboxCommitCandidate<C>;\n}\n\nfunction toDurableCommand<C extends PublishedCommand>(\n\tevent: AnyDomainEvent,\n\tcontent: CommandMessageContent<C>,\n\tindex: number,\n): DurableCommandMessage<C> {\n\tif (\n\t\tcontent === null ||\n\t\ttypeof content !== \"object\" ||\n\t\tArray.isArray(content)\n\t) {\n\t\tthrow new TypeError(\"Command outbox mapper entry must be an object\");\n\t}\n\tconst {\n\t\tdestination,\n\t\tcommand: sourceCommand,\n\t\tcorrelationId,\n\t\tconversationId,\n\t\ttraceparent,\n\t\ttracestate,\n\t} = content;\n\tassertNonBlank(\"destination\", destination);\n\tif (\n\t\tsourceCommand === null ||\n\t\ttypeof sourceCommand !== \"object\" ||\n\t\tArray.isArray(sourceCommand)\n\t) {\n\t\tthrow new TypeError(\"Command outbox command must be an object\");\n\t}\n\tassertPublishedCommand(sourceCommand);\n\tassertOptionalNonBlank(\"correlationId\", correlationId);\n\tassertOptionalNonBlank(\"conversationId\", conversationId);\n\tassertTraceContext(traceparent, tracestate);\n\n\tconst command = JSON.parse(JSON.stringify(sourceCommand)) as C;\n\treturn deepFreeze({\n\t\tmessageId: `${event.eventId}:command:${index}`,\n\t\trecordedAt: event.occurredAt.toISOString(),\n\t\tdestination,\n\t\tcommand,\n\t\t...(correlationId === undefined ? {} : { correlationId }),\n\t\t...(conversationId === undefined ? {} : { conversationId }),\n\t\t...(traceparent === undefined ? {} : { traceparent }),\n\t\t...(tracestate === undefined ? {} : { tracestate }),\n\t\tcausationId: event.eventId,\n\t}) as DurableCommandMessage<C>;\n}\n\nfunction assertNonBlank(\n\tfield: string,\n\tvalue: unknown,\n): asserts value is string {\n\tif (typeof value !== \"string\" || value.trim().length === 0) {\n\t\tinvalid(`$.${field}`, \"must be a non-blank string\");\n\t}\n}\n\nfunction assertOptionalNonBlank(field: string, value: unknown): void {\n\tif (value !== undefined) assertNonBlank(field, value);\n}\n\nfunction assertPublishedCommand(\n\tvalue: unknown,\n): asserts value is PublishedCommand {\n\tassertJsonValue(value, \"$.command\", invalid);\n\tif (!isJsonObject(value)) {\n\t\tinvalid(\"$.command\", \"must be a plain JSON object\");\n\t}\n\tfor (const key of Object.keys(value)) {\n\t\tif (key !== \"type\" && key !== \"version\" && key !== \"payload\") {\n\t\t\tinvalid(\n\t\t\t\t`$.command.${key}`,\n\t\t\t\t\"is not part of the published command schema\",\n\t\t\t);\n\t\t}\n\t}\n\tassertNonBlank(\"command.type\", value.type);\n\tif (\n\t\ttypeof value.version !== \"number\" ||\n\t\t!Number.isInteger(value.version) ||\n\t\tvalue.version < 1\n\t) {\n\t\tinvalid(\"$.command.version\", \"must be an integer >= 1\");\n\t}\n\tif (!Object.hasOwn(value, \"payload\")) {\n\t\tinvalid(\"$.command.payload\", \"is required (use null for an empty payload)\");\n\t}\n}\n\nconst TRACEPARENT =\n\t/^([0-9a-f]{2})-([0-9a-f]{32})-([0-9a-f]{16})-([0-9a-f]{2})([\\x21-\\x7e]*)$/;\nconst TRACESTATE_MEMBER =\n\t/^([a-z0-9][a-z0-9_@*/-]{0,255})=[\\x20-\\x2b\\x2d-\\x3c\\x3e-\\x7e]{1,256}$/;\n\nfunction assertTraceContext(traceparent: unknown, tracestate: unknown): void {\n\tif (traceparent === undefined) {\n\t\tif (tracestate !== undefined) {\n\t\t\tinvalid(\"$.tracestate\", \"requires traceparent\");\n\t\t}\n\t\treturn;\n\t}\n\tif (typeof traceparent !== \"string\") {\n\t\tinvalid(\"$.traceparent\", \"must be a W3C traceparent string\");\n\t}\n\tconst match = TRACEPARENT.exec(traceparent);\n\tconst version = match?.[1];\n\tconst extension = match?.[5] ?? \"\";\n\tif (\n\t\tmatch === null ||\n\t\tversion === \"ff\" ||\n\t\t/^0+$/.test(match[2] ?? \"\") ||\n\t\t/^0+$/.test(match[3] ?? \"\") ||\n\t\t(version === \"00\" && extension.length > 0) ||\n\t\t(version !== \"00\" &&\n\t\t\textension.length > 0 &&\n\t\t\t(!extension.startsWith(\"-\") || extension.length === 1))\n\t) {\n\t\tinvalid(\n\t\t\t\"$.traceparent\",\n\t\t\t\"must be a structurally valid lowercase W3C traceparent\",\n\t\t);\n\t}\n\tif (tracestate === undefined) return;\n\tif (typeof tracestate !== \"string\" || tracestate.length > 512) {\n\t\tinvalid(\"$.tracestate\", \"must stay within the 512-character command limit\");\n\t}\n\t// W3C Trace Context requires receivers to tolerate empty list-members\n\t// (\"vendor1=abc,,vendor2=def\"). They carry no data and are dropped\n\t// before validation; a header with only empty members counts as absent.\n\tconst members = tracestate\n\t\t.split(\",\")\n\t\t.map((member) => member.trim())\n\t\t.filter((member) => member.length > 0);\n\tif (members.length === 0) return;\n\tconst keys = new Set<string>();\n\tif (\n\t\tmembers.length > 32 ||\n\t\tmembers.some((member) => {\n\t\t\tconst memberMatch = TRACESTATE_MEMBER.exec(member);\n\t\t\tconst key = memberMatch?.[1];\n\t\t\tif (key === undefined || keys.has(key)) return true;\n\t\t\tkeys.add(key);\n\t\t\treturn false;\n\t\t})\n\t) {\n\t\tinvalid(\n\t\t\t\"$.tracestate\",\n\t\t\t\"must contain 1 to 32 unique, valid W3C tracestate list-members\",\n\t\t);\n\t}\n}\n\nfunction invalid(path: string, reason: string): never {\n\tthrow new InvalidCommandMessageError(path, reason);\n}\n","import {\n\tCapabilityRegistryConflictError,\n\tUnmanagedInstanceError,\n} from \"../../../errors/kit-errors\";\nimport { isWeakMap } from \"../../../internal/structural/is-built-in\";\n\n/**\n * A capability registry with the outcome of its bootstrap and the one\n * lookup-or-reject every capability module uses.\n */\nexport interface CapabilityRegistry<TCapability extends object> {\n\treadonly registry: WeakMap<object, TCapability>;\n\t/**\n\t * `false` when the host rejected the global registration. The registry\n\t * then belongs to this package copy alone, and an instance constructed by\n\t * another copy cannot be recognized.\n\t */\n\treadonly shared: boolean;\n\t/**\n\t * Resolves the capability of `instance` or throws\n\t * {@link UnmanagedInstanceError} naming the operation, the subject, and\n\t * the instance id. When the registry is private to this package copy,\n\t * the error says so, because that is the one reason an instance from\n\t * another copy cannot be recognized. A nullish instance is rejected the\n\t * same way.\n\t */\n\trequire(instance: object, operation: string, subject: string): TCapability;\n}\n\n/**\n * The sentence a capability lookup appends to its rejection when the\n * registry is private to this copy, so the reader learns why an instance\n * from another package copy was not recognized.\n */\nconst LOCAL_REGISTRY_DETAIL =\n\t\"The capability registry of this package copy is private because the \" +\n\t\"host rejected the global registration, so an instance from another \" +\n\t\"package copy cannot be recognized.\";\n\n/**\n * Shared bootstrap for the kit's cross-copy capability registries.\n *\n * A registry is a WeakMap installed once on the host (`globalThis`) under a\n * versioned `Symbol.for` key, so aggregates constructed by a bundled plugin\n * copy of the kit cooperate with the host package copy. The key version\n * stamps the capability SHAPE: registrations made under another key stay\n * invisible, so an incompatible copy fails the caller's capability check\n * instead of half-working.\n *\n * Two bootstrap failures are loud in different ways. A key that already\n * holds a value which is not a registry belongs to another module; the kit\n * throws {@link CapabilityRegistryConflictError} instead of overwriting it.\n * A host that rejects the registration (a non-extensible `globalThis`)\n * leaves the registry private to this copy, reported through `shared`.\n *\n * A registry is not a security boundary against code already running in the\n * same process; it is an architectural boundary kept out of package exports\n * and public aggregate types.\n */\nexport function createGlobalCapabilityRegistry<TCapability extends object>(\n\tkey: symbol,\n\thost: object = globalThis,\n): CapabilityRegistry<TCapability> {\n\tconst descriptor = Object.getOwnPropertyDescriptor(host, key);\n\tif (descriptor !== undefined) {\n\t\t// Brand-checked, not instanceof: a registry that a kit copy installed\n\t\t// from another realm must not read as a conflict.\n\t\tif (isWeakMap(descriptor.value)) {\n\t\t\treturn withRequire(\n\t\t\t\tdescriptor.value as WeakMap<object, TCapability>,\n\t\t\t\ttrue,\n\t\t\t);\n\t\t}\n\t\tthrow new CapabilityRegistryConflictError(key);\n\t}\n\n\tconst registry = new WeakMap<object, TCapability>();\n\ttry {\n\t\tObject.defineProperty(host, key, {\n\t\t\tvalue: registry,\n\t\t\tenumerable: false,\n\t\t\twritable: false,\n\t\t\tconfigurable: false,\n\t\t});\n\t\treturn withRequire(registry, true);\n\t} catch {\n\t\treturn withRequire(registry, false);\n\t}\n}\n\nfunction withRequire<TCapability extends object>(\n\tregistry: WeakMap<object, TCapability>,\n\tshared: boolean,\n): CapabilityRegistry<TCapability> {\n\treturn {\n\t\tregistry,\n\t\tshared,\n\t\trequire: (instance, operation, subject) => {\n\t\t\tconst capability =\n\t\t\t\tinstance === null || instance === undefined\n\t\t\t\t\t? undefined\n\t\t\t\t\t: registry.get(instance);\n\t\t\tif (capability !== undefined) return capability;\n\t\t\tthrow new UnmanagedInstanceError(\n\t\t\t\toperation,\n\t\t\t\tsubject,\n\t\t\t\t(instance as { id?: unknown } | null | undefined)?.id,\n\t\t\t\tshared ? undefined : LOCAL_REGISTRY_DETAIL,\n\t\t\t);\n\t\t},\n\t};\n}\n","import type { AnyDomainEvent, PendingDomainEvent } from \"../event/domain-event\";\nimport type { Version } from \"./aggregate\";\nimport { createGlobalCapabilityRegistry } from \"./internal/global-capability-registry\";\n\n/**\n * Kit-internal read view of the pending-event lifecycle. Kept out of every\n * package entry point. The type exposes no acknowledge or discard, so a\n * reader such as the repository identity map or the replay path cannot\n * change the batch.\n */\nexport interface PendingEventLifecycleReadView {\n\t/**\n\t * Version the persistence layer last confirmed for the aggregate, or\n\t * `undefined` for a never-persisted instance. Grounds the application\n\t * shell's unique-cursor guard.\n\t */\n\tpersistedVersion(): Version | undefined;\n\t/**\n\t * Count of unflushed pending events. The public `pendingEvents` getter\n\t * allocates and freezes a defensive copy per read, which a count-only\n\t * consumer does not need.\n\t */\n\tpendingEventCount(): number;\n\t/**\n\t * The aggregate's declared type; it is protected on the aggregate and\n\t * absent from `Aggregate`.\n\t */\n\taggregateType(): string;\n}\n\n/**\n * Kit-internal authority for acknowledging one exact pending-event batch.\n *\n * Only application commit orchestration holds it: it acknowledges or\n * discards the batch after the surrounding transaction commits. Every other\n * reader takes the {@link PendingEventLifecycleReadView}.\n */\nexport interface PendingEventLifecycleCapability\n\textends PendingEventLifecycleReadView {\n\t/**\n\t * Acknowledges the committed batch. `committedVersion` is the version the\n\t * commit actually persisted (captured at enrollment); the aggregate syncs\n\t * its persisted-version marker from it rather than from its live version,\n\t * so un-awaited concurrent work mutating the instance in the post-commit\n\t * window cannot desync the marker.\n\t */\n\tacknowledge(\n\t\tevents: ReadonlyArray<PendingDomainEvent<AnyDomainEvent>>,\n\t\tcommittedVersion: Version,\n\t): void;\n\tdiscardPendingEvents(\n\t\tevents: ReadonlyArray<PendingDomainEvent<AnyDomainEvent>>,\n\t): void;\n}\n\n// The key version stamps the capability SHAPE. Bump it whenever the\n// interface above changes: registrations made under another key stay\n// invisible, so an aggregate constructed by an incompatible package copy\n// fails the UnmanagedInstanceError check at enrollment instead of\n// half-working through a shape it does not fully implement.\nconst persistenceCapabilityRegistryKey = Symbol.for(\n\t\"@shirudo/ddd-kit/pending-event-lifecycle-registry/v6\",\n);\n\nconst { registry: capabilities, require } =\n\tcreateGlobalCapabilityRegistry<PendingEventLifecycleCapability>(\n\t\tpersistenceCapabilityRegistryKey,\n\t);\n\n/** Resolves the lifecycle authority or throws `UnmanagedInstanceError`. */\nexport function requirePendingEventLifecycleCapability(\n\taggregate: object,\n\toperation: string,\n): PendingEventLifecycleCapability {\n\treturn require(aggregate, operation, \"aggregate\");\n}\n\nexport function registerPendingEventLifecycleCapability(\n\taggregate: object,\n\tcapability: PendingEventLifecycleCapability,\n): void {\n\tconst frozen = Object.freeze(capability);\n\tcapabilities.set(aggregate, frozen);\n}\n\nexport function pendingEventLifecycleCapabilityFor(\n\taggregate: object,\n): PendingEventLifecycleCapability | undefined {\n\treturn capabilities.get(aggregate);\n}\n\n// The read-view accessors narrow the same registration to the read type.\n// A reader that resolves through them cannot reach acknowledge or discard.\n\n/** Resolves the lifecycle read view or throws `UnmanagedInstanceError`. */\nexport function requirePendingEventLifecycleReadView(\n\taggregate: object,\n\toperation: string,\n): PendingEventLifecycleReadView {\n\treturn requirePendingEventLifecycleCapability(aggregate, operation);\n}\n\nexport function pendingEventLifecycleReadViewFor(\n\taggregate: object,\n): PendingEventLifecycleReadView | undefined {\n\treturn pendingEventLifecycleCapabilityFor(aggregate);\n}\n","/**\n * The value to reject with when an `AbortSignal` has fired.\n *\n * Returns the signal's `reason` (a `DOMException` `AbortError` for\n * `controller.abort()`, `TimeoutError` for `AbortSignal.timeout`), falling\n * back to a plain `Error` with `fallbackMessage` when `reason` is nullish.\n * A spec-compliant signal always populates `reason` when aborted, so the\n * fallback only fires for a non-spec polyfill; without it, a bare\n * `throw undefined` would surface, breaking `instanceof Error` handling.\n *\n * Centralizes the `signal.reason ?? new Error(...)` idiom used at every\n * abort site (event bus, `withCommit`, `UnitOfWork.run`, the retrying\n * scope) so a single fix covers all of them.\n */\nexport function abortReason(\n\tsignal: AbortSignal,\n\tfallbackMessage: string,\n): unknown {\n\treturn signal.reason ?? new Error(fallbackMessage);\n}\n","/**\n * Shared construction-time guards for numeric options. `context` names\n * the throwing component so the error reads like the component's own\n * validation (\"OutboxDispatcher: pollIntervalMs must be...\").\n */\n\n/** Guard for numeric options that must be a non-negative finite number. */\nexport function assertNonNegativeFinite(\n\tcontext: string,\n\tfield: string,\n\tvalue: number,\n): void {\n\tif (!Number.isFinite(value) || value < 0) {\n\t\tthrow new Error(\n\t\t\t`${context}: ${field} must be a non-negative finite number, got ${value}`,\n\t\t);\n\t}\n}\n\n/** Guard for count options that must be a whole number of at least 1. */\nexport function assertPositiveInteger(\n\tcontext: string,\n\tfield: string,\n\tvalue: number,\n): void {\n\tif (!Number.isInteger(value) || value < 1) {\n\t\tthrow new Error(\n\t\t\t`${context}: ${field} must be an integer >= 1, got ${value}`,\n\t\t);\n\t}\n}\n\n/** Guard for retained-record capacities that must fit exact JS integers. */\nexport function assertPositiveSafeInteger(\n\tcontext: string,\n\tfield: string,\n\tvalue: number,\n): void {\n\tif (!Number.isSafeInteger(value) || value < 1) {\n\t\tthrow new RangeError(\n\t\t\t`${context}: ${field} must be a positive safe integer, got ${value}`,\n\t\t);\n\t}\n}\n","import { assertNonNegativeFinite } from \"../validate\";\nimport { abortReason } from \"./abort\";\n\n/** Cancellation and deadline controls for one bounded shell operation. */\nexport interface ExecutionContext {\n\t/** Cooperative cancellation for the in-flight operation. */\n\treadonly signal: AbortSignal;\n\t/** Absolute Unix epoch millisecond at which the shell stops waiting. */\n\treadonly deadlineAt: number;\n}\n\n/** Caller controls for one bounded shell operation. */\ntype ExecutionOptions =\n\t| {\n\t\t\t/** Optional owner/request cancellation signal. */\n\t\t\treadonly signal?: AbortSignal;\n\t\t\t/** Maximum time the shell waits for the operation. */\n\t\t\treadonly timeoutMs: number;\n\t\t\treadonly deadlineAt?: never;\n\t }\n\t| {\n\t\t\t/** Optional owner/request cancellation signal. */\n\t\t\treadonly signal?: AbortSignal;\n\t\t\treadonly timeoutMs?: never;\n\t\t\t/** Shared absolute deadline for a multi-operation budget. */\n\t\t\treadonly deadlineAt: number;\n\t };\n\n/** Default bound for delivery and post-commit operations. */\nexport const DEFAULT_EXECUTION_TIMEOUT_MS = 30_000;\n\n/**\n * Owner signal of each child signal that {@link runBoundedExecution} minted.\n *\n * One bounded operation often wraps another, and every hop derives a fresh\n * signal. A consumer that follows a call chain by signal identity alone loses\n * the link at the first hop. Key and value are both weak: a long chain of\n * nested operations must not hold its whole ancestry alive.\n */\nconst executionOwners = new WeakMap<AbortSignal, WeakRef<AbortSignal>>();\n\n/**\n * The signal that a bounded execution derived this one from, or `undefined`\n * when the signal did not come from {@link runBoundedExecution} or had no\n * owner. Walk it to follow a chain across nested bounded executions.\n */\nexport function ownerSignalOf(signal: AbortSignal): AbortSignal | undefined {\n\treturn executionOwners.get(signal)?.deref();\n}\n\n/**\n * Runs one operation with a child signal that combines owner cancellation and a\n * shell-owned timeout. The returned promise settles on abort even when an\n * adapter ignores the signal; the adapter promise remains observed so a later\n * rejection cannot become an unhandled rejection.\n *\n * This bounds how long the shell waits; JavaScript cannot forcibly terminate\n * an arbitrary promise. An I/O adapter that must prevent zombie work and\n * overlapping retries has to pass `context.signal` to its native operation or\n * enforce a native timeout no later than `context.deadlineAt`.\n */\nexport function runBoundedExecution<T>(\n\tlabel: string,\n\toptions: ExecutionOptions,\n\toperation: (context: ExecutionContext) => Promise<T> | T,\n): Promise<T> {\n\tif (options.deadlineAt === undefined) {\n\t\tassertNonNegativeFinite(label, \"timeoutMs\", options.timeoutMs);\n\t} else {\n\t\tassertNonNegativeFinite(label, \"deadlineAt\", options.deadlineAt);\n\t}\n\tconst startedAt = Date.now();\n\tconst deadlineAt = options.deadlineAt ?? startedAt + options.timeoutMs;\n\tconst timeoutMs = Math.max(0, deadlineAt - startedAt);\n\tconst timeoutError = (): DOMException =>\n\t\tnew DOMException(`${label} timed out after ${timeoutMs}ms`, \"TimeoutError\");\n\tconst controller = new AbortController();\n\tconst context = Object.freeze({\n\t\tsignal: controller.signal,\n\t\tdeadlineAt,\n\t});\n\tconst ownerSignal = options.signal;\n\tif (ownerSignal !== undefined) {\n\t\texecutionOwners.set(controller.signal, new WeakRef(ownerSignal));\n\t}\n\tconst abortFromOwner = (): void => {\n\t\tcontroller.abort(\n\t\t\townerSignal === undefined\n\t\t\t\t? new Error(`${label} aborted`)\n\t\t\t\t: abortReason(ownerSignal, `${label} aborted`),\n\t\t);\n\t};\n\n\tif (ownerSignal?.aborted) abortFromOwner();\n\telse ownerSignal?.addEventListener(\"abort\", abortFromOwner, { once: true });\n\tif (\n\t\t!controller.signal.aborted &&\n\t\toptions.deadlineAt !== undefined &&\n\t\tdeadlineAt <= startedAt\n\t) {\n\t\tcontroller.abort(timeoutError());\n\t}\n\n\tconst timer = setTimeout(() => {\n\t\tcontroller.abort(timeoutError());\n\t}, timeoutMs);\n\n\treturn new Promise<T>((resolve, reject) => {\n\t\tlet settled = false;\n\t\tconst finish = (complete: () => void): void => {\n\t\t\tif (settled) return;\n\t\t\tsettled = true;\n\t\t\tclearTimeout(timer);\n\t\t\townerSignal?.removeEventListener(\"abort\", abortFromOwner);\n\t\t\tcontroller.signal.removeEventListener(\"abort\", onAbort);\n\t\t\tcomplete();\n\t\t};\n\t\tconst onAbort = (): void => {\n\t\t\t// Defer one microtask so a promise that settled immediately before the\n\t\t\t// abort keeps its acknowledgement semantics. If abort happened first,\n\t\t\t// this microtask was queued first and still wins deterministically.\n\t\t\tqueueMicrotask(() =>\n\t\t\t\tfinish(() =>\n\t\t\t\t\treject(abortReason(controller.signal, `${label} aborted`)),\n\t\t\t\t),\n\t\t\t);\n\t\t};\n\n\t\tif (controller.signal.aborted) {\n\t\t\tonAbort();\n\t\t\treturn;\n\t\t}\n\t\tcontroller.signal.addEventListener(\"abort\", onAbort, { once: true });\n\t\tlet outcome: Promise<T>;\n\t\ttry {\n\t\t\toutcome = Promise.resolve(operation(context));\n\t\t} catch (error) {\n\t\t\tfinish(() => reject(error));\n\t\t\treturn;\n\t\t}\n\t\toutcome.then(\n\t\t\t(value) => finish(() => resolve(value)),\n\t\t\t(error) => finish(() => reject(error)),\n\t\t);\n\t});\n}\n","/**\n * Invokes a fire-and-forget observer hook (`onPersistError`,\n * `onPublishError`, `onRetry`) and neutralises BOTH failure shapes it can\n * produce. The observers are typed `(...) => void`, but a `void` return\n * type still admits an `async` function, so an observer can fail in two\n * ways: a synchronous throw, or a rejected promise. Either would replace\n * or mask the operation's real outcome (a committed write made to look\n * failed, a retryable error swapped for the observer's own), and the\n * async rejection additionally becomes an `unhandledRejection` that can\n * crash the process under Node's default policy. Both are swallowed\n * here: observers report, they never affect the operation they observe.\n *\n * Internal utility (not exported from the package barrels).\n */\nexport function reportToObserver(invoke: () => void): void {\n\tlet result: unknown;\n\ttry {\n\t\tresult = invoke() as unknown;\n\t} catch {\n\t\treturn;\n\t}\n\tif (\n\t\tresult !== null &&\n\t\ttypeof result === \"object\" &&\n\t\ttypeof (result as { then?: unknown }).then === \"function\"\n\t) {\n\t\t(result as Promise<unknown>).then(undefined, () => {});\n\t}\n}\n\n/** Runtime-validates and immutably captures a production-observer bundle. */\nexport function captureObserverFunctions<\n\tT extends object,\n\tK extends Extract<keyof T, string>,\n>(context: string, observers: T, required: readonly K[]): Readonly<Pick<T, K>> {\n\tif (observers === null || typeof observers !== \"object\") {\n\t\tthrow new TypeError(\n\t\t\t`${context}.observers must provide ${required.join(\", \")}`,\n\t\t);\n\t}\n\tconst captured: Partial<Record<K, T[K]>> = {};\n\tfor (const name of required) {\n\t\tconst observer = (observers as Record<string, unknown>)[name];\n\t\tif (typeof observer !== \"function\") {\n\t\t\tthrow new TypeError(`${context}.observers.${name} must be a function`);\n\t\t}\n\t\tcaptured[name] = observer as T[K];\n\t}\n\treturn Object.freeze(captured) as Readonly<Pick<T, K>>;\n}\n","import type { Aggregate, Version } from \"../../domain/aggregate/aggregate\";\nimport {\n\ttype PendingEventLifecycleCapability,\n\trequirePendingEventLifecycleCapability,\n} from \"../../domain/aggregate/pending-event-lifecycle\";\nimport {\n\ttype AnyDomainEvent,\n\tisRecordedDomainEvent,\n\ttype PendingDomainEvent,\n} from \"../../domain/event/domain-event\";\nimport type { Id } from \"../../domain/identity/id\";\nimport { EventHarvestError } from \"../../errors/kit-errors\";\nimport { abortReason } from \"../../internal/async/abort\";\nimport {\n\tDEFAULT_EXECUTION_TIMEOUT_MS,\n\ttype ExecutionContext,\n\trunBoundedExecution,\n} from \"../../internal/async/execution\";\nimport { reportToObserver } from \"../../internal/observer\";\nimport { assertNonNegativeFinite } from \"../../internal/validate\";\nimport type { EventCommitCandidate } from \"../../messaging/committed-event\";\nimport type { EventBus } from \"../../messaging/event-bus/ports\";\nimport type { OutboxWriter } from \"../../messaging/outbox/ports\";\nimport type { TransactionScope } from \"../../persistence/repository/scope\";\n\n/** Dependencies for {@link withCommit}. */\nexport interface WithCommitDeps<Evt extends AnyDomainEvent, TCtx> {\n\t/**\n\t * The write half of the outbox: `withCommit` only ever calls `add()`.\n\t * Pass a full `Outbox` for the kit's poll-based dispatch, or a bare\n\t * `OutboxWriter` backed by an external delivery solution.\n\t *\n\t * Required on purpose, while `bus` is optional: the bus is the\n\t * best-effort in-process fast path, the outbox is the delivery\n\t * guarantee. Running without delivery reliability is a decision, not\n\t * a default; make it explicit with\n\t * `outboxWriterAcceptingEventLoss()`.\n\t */\n\toutbox: OutboxWriter<Evt>;\n\tbus?: EventBus<Evt>;\n\tscope: TransactionScope<TCtx>;\n\t/**\n\t * Observer for post-commit `bus.publish` failures. Called with the\n\t * error and the events that were published. Must not be relied on\n\t * for delivery: the outbox dispatcher is the reliable path.\n\t */\n\tonPublishError?: (error: unknown, events: ReadonlyArray<Evt>) => void;\n\t/**\n\t * Application-shell observer invoked for each successfully acknowledged\n\t * saved aggregate, after every commit record has completed its internal\n\t * acknowledgement attempt. Deleted aggregates do not trigger it. `version`\n\t * is the commit-time value captured before any observer runs. Observer\n\t * failures are reported through `onPersistError` and never turn an already\n\t * committed write into an apparent failure. The execution context carries\n\t * owner cancellation and the configured post-commit deadline.\n\t */\n\tonPersisted?: (\n\t\taggregate: Aggregate<Id<string>, Evt>,\n\t\tversion: Version,\n\t\tcontext: ExecutionContext,\n\t) => void | Promise<void>;\n\t/**\n\t * Observer for post-commit persistence failures: either the internal\n\t * acknowledgement/disposal step or the application-shell `onPersisted`\n\t * observer. Called once per failure with the error and affected aggregate.\n\t * Symmetric with {@link onPublishError}: the\n\t * transaction has already committed, so the failure must NOT reject the\n\t * write; without this observer it would otherwise vanish silently. The\n\t * hook is an observer only: if it throws, its error is swallowed so the\n\t * post-commit invariant holds, and the loop continues the remaining\n\t * post-commit work.\n\t */\n\tonPersistError?: (\n\t\terror: unknown,\n\t\taggregate: Aggregate<Id<string>, Evt>,\n\t) => void;\n\t/**\n\t * Total time allotted to the complete post-commit application phase:\n\t * every application observer followed by in-process bus publication shares\n\t * one absolute deadline. Callbacks that have not started when the deadline is\n\t * reached are skipped and reported as timeouts. Defaults to `30000`ms.\n\t * Timing out or aborting these best-effort operations is reported through the\n\t * matching error observer and never rejects an already committed write.\n\t */\n\tpostCommitTimeoutMs?: number;\n\t/**\n\t * Cooperative-cancellation signal. If already aborted, `withCommit`\n\t * rejects with the signal's `reason` BEFORE opening the transaction.\n\t * Otherwise the signal is forwarded to `scope.transactional`, where a\n\t * cancellation-aware scope can abort an in-flight query. The kit does\n\t * not race the work promise: aborting does not kill a running query\n\t * unless the scope honors the signal.\n\t */\n\tsignal?: AbortSignal;\n}\n\ndeclare const aggregateCommitTokenBrand: unique symbol;\n\n/**\n * Opaque receipt that one aggregate was explicitly enrolled in the current\n * {@link withCommit} invocation. Tokens are minted only by the invocation's\n * {@link CommitEnrollment} capability and are bound to that invocation at\n * runtime; a forged token or one retained from an earlier call is rejected\n * inside the transaction.\n */\nexport interface AggregateCommitToken<\n\tEvt extends AnyDomainEvent = AnyDomainEvent,\n> {\n\treadonly [aggregateCommitTokenBrand]: Evt;\n}\n\n/**\n * Invocation-scoped enrollment capability handed to a {@link withCommit}\n * callback. Call `enrollSaved` only for an aggregate participating in the\n * repository write, and return every resulting token in `commits`. Omitting\n * any token rejects the transaction: an enrolled write may not commit without\n * its event harvest and post-commit acknowledgement. Enrollable instances\n * must extend `StateStoredAggregate` or `EventSourcedAggregate`; structural\n * `Aggregate` lookalikes have no internal lifecycle capability and fail\n * before commit.\n */\nexport interface CommitEnrollment<Evt extends AnyDomainEvent> {\n\tenrollSaved(\n\t\taggregate: Aggregate<Id<string>, Evt>,\n\t\toptions?: CommitEnrollmentOptions,\n\t): AggregateCommitToken<Evt>;\n\t/**\n\t * Enroll an aggregate whose row is deleted by the current transaction.\n\t * Its events are harvested and discarded after commit, but the saved-only\n\t * application `onPersisted` observer is not called.\n\t */\n\tenrollDeleted(\n\t\taggregate: Aggregate<Id<string>, Evt>,\n\t\toptions?: CommitEnrollmentOptions,\n\t): AggregateCommitToken<Evt>;\n}\n\n/** OCC baseline associated with one exact commit enrollment. */\nexport interface CommitEnrollmentOptions {\n\t/** Absent for a new aggregate; captured at load for update or removal. */\n\treadonly expectedVersion?: Version;\n}\n\n/** The resolved value of a {@link withCommit} work callback. */\nexport interface WithCommitWorkResult<Evt extends AnyDomainEvent, R> {\n\tresult: R;\n\t/**\n\t * Commit tokens returned by the invocation's enrollment capability.\n\t * Every token minted during the callback must appear at least once.\n\t * Naked aggregates are intentionally not accepted: touching an aggregate\n\t * does not prove that its repository write participated in the transaction.\n\t */\n\tcommits: ReadonlyArray<AggregateCommitToken<Evt>>;\n}\n\ntype CommitDisposition = \"saved\" | \"deleted\";\n\ninterface AggregateCommitRecord<Evt extends AnyDomainEvent> {\n\treadonly aggregate: Aggregate<Id<string>, Evt>;\n\treadonly eventLifecycle: PendingEventLifecycleCapability;\n\treadonly version: Version;\n\treadonly expectedVersion: Version | undefined;\n\t/**\n\t * Version the persistence layer last confirmed for the aggregate at\n\t * enrollment time (kit-maintained). `undefined` means the aggregate was\n\t * never persisted, so any single eventful commit cursor is unique.\n\t */\n\treadonly persistedVersion: Version | undefined;\n\treadonly events: ReadonlyArray<PendingDomainEvent<Evt>>;\n\tdisposition: CommitDisposition;\n}\n\n/**\n * True when the aggregate's live version or pending-event batch no longer\n * matches its enrollment-time snapshot. Shared by the duplicate-enrollment\n * gate and the harvest-time recheck: both must reject the same divergence,\n * or events recorded after enrollment would be silently dropped.\n */\nfunction enrollmentDiverged<Evt extends AnyDomainEvent>(\n\trecord: AggregateCommitRecord<Evt>,\n): boolean {\n\tconst pending = record.aggregate.pendingEvents;\n\treturn (\n\t\trecord.aggregate.version !== record.version ||\n\t\tpending.length !== record.events.length ||\n\t\trecord.events.some((event, index) => event !== pending[index])\n\t);\n}\n\ninterface CommitTokenScope<Evt extends AnyDomainEvent> {\n\treadonly enrollment: CommitEnrollment<Evt>;\n\tclose(): void;\n\tresolve(tokens: unknown): ReadonlyArray<AggregateCommitRecord<Evt>>;\n}\n\n/** One token registry per transactional callback attempt. */\nfunction createCommitTokenScope<\n\tEvt extends AnyDomainEvent,\n>(): CommitTokenScope<Evt> {\n\tconst recordsByToken = new WeakMap<object, AggregateCommitRecord<Evt>>();\n\tconst tokensByAggregate = new WeakMap<\n\t\tAggregate<Id<string>, Evt>,\n\t\tAggregateCommitToken<Evt>\n\t>();\n\tlet mintedTokenCount = 0;\n\tlet open = true;\n\n\tconst enroll = (\n\t\taggregate: Aggregate<Id<string>, Evt>,\n\t\tdisposition: CommitDisposition,\n\t\toptions?: CommitEnrollmentOptions,\n\t): AggregateCommitToken<Evt> => {\n\t\tif (!open) {\n\t\t\tthrow new EventHarvestError(\n\t\t\t\t\"withCommit: commit enrollment was used after its work callback \" +\n\t\t\t\t\t\"settled. Await every repository write and return its token before \" +\n\t\t\t\t\t\"leaving the callback.\",\n\t\t\t);\n\t\t}\n\n\t\tconst existing = tokensByAggregate.get(aggregate);\n\t\tif (existing) {\n\t\t\tconst record = recordsByToken.get(existing);\n\t\t\tif (!record) {\n\t\t\t\tthrow new EventHarvestError(\n\t\t\t\t\t\"withCommit: internal commit-token registry is inconsistent.\",\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (record.disposition === \"deleted\" && disposition === \"saved\") {\n\t\t\t\tthrow new EventHarvestError(\n\t\t\t\t\t`withCommit: aggregate ${String(aggregate.id)} was enrolled as ` +\n\t\t\t\t\t\t\"saved after it was enrolled as deleted in the same transaction.\",\n\t\t\t\t);\n\t\t\t}\n\t\t\t// Duplicate enrollment is idempotent by reference. An omitted\n\t\t\t// expectedVersion is no assertion, not an assertion of \"absent\":\n\t\t\t// only a supplied value is compared against the recorded baseline.\n\t\t\tif (\n\t\t\t\toptions?.expectedVersion !== undefined &&\n\t\t\t\toptions.expectedVersion !== record.expectedVersion\n\t\t\t) {\n\t\t\t\tthrow new EventHarvestError(\n\t\t\t\t\t`withCommit: aggregate ${String(aggregate.id)} was re-enrolled ` +\n\t\t\t\t\t\t`with expectedVersion ${String(options.expectedVersion)}, but its ` +\n\t\t\t\t\t\t`enrollment recorded ${String(record.expectedVersion)}. Duplicate ` +\n\t\t\t\t\t\t\"enrollment must assert the same OCC baseline or none.\",\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (enrollmentDiverged(record)) {\n\t\t\t\tthrow new EventHarvestError(\n\t\t\t\t\t`withCommit: aggregate ${String(aggregate.id)} changed after its ` +\n\t\t\t\t\t\t\"commit batch was enrolled. Register persistence intent last.\",\n\t\t\t\t);\n\t\t\t}\n\t\t\t// The widened disposition is adopted only after every check passed:\n\t\t\t// a rejected enrollDeleted whose error the callback catches must\n\t\t\t// not leave a saved aggregate marked deleted, or the post-commit\n\t\t\t// loop would discard instead of acknowledge.\n\t\t\tif (disposition === \"deleted\") {\n\t\t\t\trecord.disposition = \"deleted\";\n\t\t\t}\n\t\t\treturn existing;\n\t\t}\n\n\t\tconst eventLifecycle = requirePendingEventLifecycleCapability(\n\t\t\taggregate,\n\t\t\t\"withCommit enrollment\",\n\t\t);\n\n\t\tconst token = Object.freeze(\n\t\t\tObject.create(null),\n\t\t) as AggregateCommitToken<Evt>;\n\t\t// The pendingEvents getter already returns a frozen detached copy;\n\t\t// re-copying and re-freezing it here would only duplicate the work.\n\t\tconst events = aggregate.pendingEvents;\n\t\t// Recorded-before-persistence is checked HERE, not only at harvest:\n\t\t// the UnitOfWork enrolls at write registration, so this rejection\n\t\t// lands before any adapter flush. The harvest guard alone fires after\n\t\t// flush, and a non-transactional event store would already have\n\t\t// appended the unstamped batch durably.\n\t\tfor (const event of events) {\n\t\t\tif (!isRecordedDomainEvent(event)) {\n\t\t\t\tthrow new EventHarvestError(\n\t\t\t\t\t`withCommit: event \"${(event as { readonly type: string }).type}\" ` +\n\t\t\t\t\t\t\"has not been recorded. Call recordPendingEvents(aggregate, \" +\n\t\t\t\t\t\t\"createStamp) in the application shell before persistence or \" +\n\t\t\t\t\t\t\"outbox harvest.\",\n\t\t\t\t\t(event as { readonly type: string }).type,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\t// The kit-maintained marker, not the enrollment-supplied\n\t\t// expectedVersion, grounds the unique-cursor guard: it survives\n\t\t// callers who omit enrollment options (the documented\n\t\t// direct-withCommit style), and grounding the guard in data supplied\n\t\t// by the very caller it checks would be circular.\n\t\tconst persistedVersion = eventLifecycle.persistedVersion();\n\t\ttokensByAggregate.set(aggregate, token);\n\t\trecordsByToken.set(token, {\n\t\t\taggregate,\n\t\t\teventLifecycle,\n\t\t\tdisposition,\n\t\t\tversion: aggregate.version,\n\t\t\texpectedVersion: options?.expectedVersion,\n\t\t\tpersistedVersion,\n\t\t\tevents,\n\t\t});\n\t\tmintedTokenCount += 1;\n\t\treturn token;\n\t};\n\n\treturn {\n\t\tenrollment: Object.freeze({\n\t\t\tenrollSaved: (\n\t\t\t\taggregate: Aggregate<Id<string>, Evt>,\n\t\t\t\toptions?: CommitEnrollmentOptions,\n\t\t\t) => enroll(aggregate, \"saved\", options),\n\t\t\tenrollDeleted: (\n\t\t\t\taggregate: Aggregate<Id<string>, Evt>,\n\t\t\t\toptions?: CommitEnrollmentOptions,\n\t\t\t) => enroll(aggregate, \"deleted\", options),\n\t\t}),\n\t\tclose: () => {\n\t\t\topen = false;\n\t\t},\n\t\tresolve: (tokens) => {\n\t\t\tif (!Array.isArray(tokens)) {\n\t\t\t\tthrow new EventHarvestError(\n\t\t\t\t\t\"withCommit: the work callback must return `commits` containing \" +\n\t\t\t\t\t\t\"tokens from the current enrollment capability. Naked aggregate \" +\n\t\t\t\t\t\t\"arrays are not commit evidence.\",\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst seen = new Set<object>();\n\t\t\tconst records: AggregateCommitRecord<Evt>[] = [];\n\t\t\tfor (const token of tokens) {\n\t\t\t\tif (\n\t\t\t\t\ttoken === null ||\n\t\t\t\t\t(typeof token !== \"object\" && typeof token !== \"function\")\n\t\t\t\t) {\n\t\t\t\t\tthrow new EventHarvestError(\n\t\t\t\t\t\t\"withCommit: a commit token was not minted by this callback's \" +\n\t\t\t\t\t\t\t\"enrollment capability. Forged and stale tokens are rejected.\",\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tconst tokenObject = token as object;\n\t\t\t\tconst record = recordsByToken.get(tokenObject);\n\t\t\t\tif (!record) {\n\t\t\t\t\tthrow new EventHarvestError(\n\t\t\t\t\t\t\"withCommit: a commit token was not minted by this callback's \" +\n\t\t\t\t\t\t\t\"enrollment capability. Forged and stale tokens are rejected.\",\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tif (seen.has(tokenObject)) continue;\n\t\t\t\tseen.add(tokenObject);\n\t\t\t\t// Harvest-time recheck of the enrollment snapshot: an event\n\t\t\t\t// recorded after enrollSaved but before the callback returned\n\t\t\t\t// would be excluded from the harvest and silently lost by the\n\t\t\t\t// post-commit prefix acknowledgement. Divergence fails loudly\n\t\t\t\t// inside the transaction instead.\n\t\t\t\tif (enrollmentDiverged(record)) {\n\t\t\t\t\tthrow new EventHarvestError(\n\t\t\t\t\t\t`withCommit: aggregate ${String(record.aggregate.id)} changed ` +\n\t\t\t\t\t\t\t\"after its commit batch was enrolled; events recorded after \" +\n\t\t\t\t\t\t\t\"enrollment are not part of the attested write and would be \" +\n\t\t\t\t\t\t\t\"silently dropped. Make domain decisions first, write, and \" +\n\t\t\t\t\t\t\t\"enroll last.\",\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\trecords.push(record);\n\t\t\t}\n\t\t\tif (seen.size !== mintedTokenCount) {\n\t\t\t\tthrow new EventHarvestError(\n\t\t\t\t\t\"withCommit: every token minted by the current enrollment \" +\n\t\t\t\t\t\t\"capability must be returned in `commits`. If an enrolled write \" +\n\t\t\t\t\t\t\"must not commit, throw so the transaction rolls back.\",\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn records;\n\t\t},\n\t};\n}\n\n/**\n * Helper for executing a write Use Case inside a transaction scope.\n *\n * The use-case callback receives an invocation-scoped enrollment capability\n * and returns opaque commit tokens for the repository writes that completed\n * in the transaction. `withCommit` owns the post-commit lifecycle (harvest,\n * outbox, mark-persisted, publish). A naked aggregate is not commit evidence:\n * merely touching or constructing one must never make it look persisted.\n *\n * **Trust boundary.** A token proves invocation-local enrollment, not that the\n * kit inspected a database write; a generic transaction helper cannot observe\n * adapter internals. Repository code must enroll only writes participating in\n * this transaction. `UnitOfWork` centralizes that rule in repository methods.\n * The opaque, scoped token prevents accidental aggregate smuggling and stale\n * reuse; it is not a security boundary against code that deliberately lies to\n * its own persistence capability.\n *\n * Order of operations:\n * 1. `fn(ctx, enrollment)` runs inside `scope.transactional(...)`; domain\n * mutations + repo writes happen here. After a repository write has\n * enrolled an aggregate, the callback includes that opaque token in its\n * `commits` result. Tokens are invocation-bound: forged or stale tokens\n * fail before harvest. `ctx` is whatever transaction handle the `scope`\n * exposes (Drizzle `tx`, Prisma `tx`, Mongo session, or `undefined` for\n * context-free scopes).\n * 2. **Still inside the transaction**, `withCommit` harvests every\n * aggregate's `pendingEvents` and writes them via `outbox.add` (so\n * events persist atomically with the state change). Skipped when no\n * events were recorded. Each bare domain event is composed into an\n * `EventCommitCandidate` carrying its aggregate source and the commit\n * facts known by the application. The outbox source atomically links\n * that candidate to the preceding eventful commit and persists the\n * resulting `CommittedDomainEvent`. The domain event itself is never\n * stamped or copied.\n *\n * **Harvest order.** Events are concatenated in the order\n * tokens appear in the returned `commits` array, then in\n * each aggregate's `pendingEvents` order (insertion order via\n * `apply` / `commit` / `addDomainEvent`). So tokens for `[a, b]`\n * with `a` emitting `[e1, e2]` and `b` emitting `[e3]` produces\n * `outbox.add([envelope(e1), envelope(e2), envelope(e3)])` and\n * `bus.publish([e1, e2, e3])` in that exact order.\n *\n * **Two ordering guarantees, not one.** Within a single aggregate\n * the order is *causal*: events are recorded in the order the\n * domain methods ran, and subscribers (handlers, projections,\n * replay) MUST process them in that order. Across aggregates the\n * order in this batch is deterministic but *not* a domain\n * guarantee. Greg Young / Vernon IDDD §10: aggregates are\n * independent consistency boundaries; events across them are\n * eventually consistent. Subscribers should NOT engineer\n * dependencies on cross-aggregate ordering; use\n * `EventMetadata.causationId` to express true causation, or a\n * process manager to coordinate. The in-process EventBus delivers\n * this batch in order, sequential outbox-dispatchers preserve it\n * too, but parallel dispatchers or message brokers may reorder\n * across aggregates at delivery time.\n * 3. The transaction commits.\n * 4. **After** the commit, a non-exported capability acknowledges every\n * saved enrollment and discards pending events for deleted enrollments.\n * Only after the complete commit set is clean does the optional\n * application-shell `onPersisted(aggregate, version, context)` observer run for\n * saved aggregates. Deleted rows never trigger that observer.\n * 5. `bus.publish(events)` fires for the in-process fast path (skipped\n * when no events or no `bus` is wired).\n *\n * Publishing AFTER commit prevents the classic \"publish before commit\"\n * footgun: in-process subscribers can never react to events from a\n * transaction that later rolled back. If `bus.publish` itself throws, the\n * outbox still holds the events and an outbox-dispatcher will deliver\n * them (eventual consistency).\n *\n * **A `bus.publish` failure never rejects `withCommit`.** Once the\n * transaction has committed, the write succeeded; surfacing a subscriber\n * failure as a rejection would hand the caller a use-case failure for a\n * committed write (a typical caller retries, double-executing it). The\n * in-process fast path is best-effort by design; the error is reported to\n * the optional `onPublishError(error, events)` hook (wire it to your\n * logger/metrics) and otherwise dropped; delivery is still guaranteed via\n * the outbox. The hook is an observer: if it throws, its error is\n * swallowed so the post-commit invariant holds.\n * The complete application-observer and bus-publication phase shares one\n * absolute `postCommitTimeoutMs` budget (30 seconds by default); later callbacks\n * are not started once it expires. A timeout or owner abort is reported\n * through the same observer paths and never changes the committed result.\n *\n * If the transaction rolls back, no acknowledgement occurs: the aggregate\n * keeps its pending events, so the caller can retry or discard the instance.\n *\n * Enrollment captures an exact version and event batch. Re-enrolling the same\n * aggregate after it changes rejects. `UnitOfWork` additionally seals the\n * adapter persistence projection and rejects later mutation before flush. For\n * direct `withCommit` use, make domain decisions first, write, and enroll last.\n *\n * **Duplicate enrollment is idempotent by reference.** Enrolling the same\n * instance repeatedly returns the same token, and a repeated token in\n * `commits` is harvested once. A repeat call that omits `expectedVersion`\n * makes no OCC assertion; only a supplied value that contradicts the\n * enrollment-time baseline rejects. Each event lands in the outbox exactly once\n * and post-commit acknowledgement runs exactly once. Two\n * *different* instances with the same logical id cannot be detected\n * at this layer; that is a Repository contract violation (failure to\n * maintain Fowler's Identity Map per Unit of Work). See\n * `docs/guide/repository.md` → \"Identity Map: one instance per\n * aggregate per Unit of Work\" for the requirement on repository\n * implementations that makes this dedupe sound.\n *\n * @example Tx-bound repos (Drizzle, Prisma, Mongo, …)\n * ```typescript\n * const result = await withCommit({ outbox, bus, scope }, async (tx, enrollment) => {\n * const orderRepository = makeOrderRepository(tx); // your factory binds tx to the repo\n * const order = await orderRepository.getById(orderId);\n * order.confirm();\n * await persistOrder(tx, order); // low-level adapter write\n * const commit = enrollment.enrollSaved(order); // attest the repository write\n * return { result: order.id, commits: [commit] };\n * });\n * ```\n */\nexport async function withCommit<Evt extends AnyDomainEvent, R, TCtx>(\n\tdeps: WithCommitDeps<Evt, TCtx>,\n\tfn: (\n\t\tctx: TCtx,\n\t\tenrollment: CommitEnrollment<Evt>,\n\t) => Promise<WithCommitWorkResult<Evt, R>>,\n): Promise<R> {\n\tconst postCommitTimeoutMs =\n\t\tdeps.postCommitTimeoutMs ?? DEFAULT_EXECUTION_TIMEOUT_MS;\n\tassertNonNegativeFinite(\n\t\t\"withCommit\",\n\t\t\"postCommitTimeoutMs\",\n\t\tpostCommitTimeoutMs,\n\t);\n\n\t// Pre-flight: an already-aborted caller never opens a transaction.\n\t// Throwing the signal's reason matches the web AbortSignal convention;\n\t// the `??` fallback mirrors event-bus.ts and guards a non-spec polyfill\n\t// whose `reason` is undefined (a bare `throw undefined` is unusable).\n\tif (deps.signal?.aborted) {\n\t\tthrow abortReason(\n\t\t\tdeps.signal,\n\t\t\t\"withCommit aborted before opening a transaction\",\n\t\t);\n\t}\n\n\tconst { result, commitRecords, events } = await deps.scope.transactional(\n\t\tasync (ctx) => {\n\t\t\tconst tokenScope = createCommitTokenScope<Evt>();\n\t\t\tlet fnResult: WithCommitWorkResult<Evt, R>;\n\t\t\ttry {\n\t\t\t\tfnResult = await fn(ctx, tokenScope.enrollment);\n\t\t\t} finally {\n\t\t\t\t// A callback can leak the capability into delayed work. Seal it as\n\t\t\t\t// soon as the callback settles so a late enrollment fails loudly\n\t\t\t\t// instead of being accepted after the harvest snapshot.\n\t\t\t\ttokenScope.close();\n\t\t\t}\n\t\t\tconst commitRecords = tokenScope.resolve(fnResult.commits);\n\t\t\t// Prepare each bare domain event for source finalization in the outbox.\n\t\t\t// The aggregate's event remains untouched and is what the in-process\n\t\t\t// domain bus receives.\n\t\t\tconst candidates = commitRecords.flatMap((record) => {\n\t\t\t\tconst agg = record.aggregate;\n\t\t\t\tif (\n\t\t\t\t\trecord.events.length > 0 &&\n\t\t\t\t\trecord.persistedVersion !== undefined &&\n\t\t\t\t\t(record.version as number) <= (record.persistedVersion as number)\n\t\t\t\t) {\n\t\t\t\t\tthrow new EventHarvestError(\n\t\t\t\t\t\t`withCommit: aggregate ${String(agg.id)} recorded events but ` +\n\t\t\t\t\t\t\t`did not advance its version beyond the persisted version ` +\n\t\t\t\t\t\t\t`(${String(record.persistedVersion)}). An eventful commit needs a unique ` +\n\t\t\t\t\t\t\t`cursor; use StateStoredAggregate.setState(currentState, event) instead ` +\n\t\t\t\t\t\t\t`of addDomainEvent(event) alone.`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tconst enrolledId = String(agg.id);\n\t\t\t\tconst enrolledType = record.eventLifecycle.aggregateType();\n\t\t\t\treturn record.events.map((event, index) => {\n\t\t\t\t\tif (!isRecordedDomainEvent(event)) {\n\t\t\t\t\t\tthrow new EventHarvestError(\n\t\t\t\t\t\t\t`withCommit: event \"${event.type}\" has not been recorded. ` +\n\t\t\t\t\t\t\t\t\"Call recordPendingEvents(aggregate, createStamp) in the \" +\n\t\t\t\t\t\t\t\t\"application shell before persistence or outbox harvest.\",\n\t\t\t\t\t\t\tevent.type,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\tconst recordedEvent = event as Evt;\n\t\t\t\t\tconst commitSize = record.events.length;\n\t\t\t\t\tconst aggregateId = recordedEvent.aggregateId;\n\t\t\t\t\tconst aggregateType = recordedEvent.aggregateType;\n\t\t\t\t\tconst missing: string[] = [];\n\t\t\t\t\tif (!aggregateId) missing.push(\"aggregateId\");\n\t\t\t\t\tif (!aggregateType) missing.push(\"aggregateType\");\n\t\t\t\t\tif (!aggregateId || !aggregateType) {\n\t\t\t\t\t\tthrow new EventHarvestError(\n\t\t\t\t\t\t\t`withCommit: event \"${recordedEvent.type}\" is missing ${missing.join(\n\t\t\t\t\t\t\t\t\" and \",\n\t\t\t\t\t\t\t)}. ` +\n\t\t\t\t\t\t\t\t`Use this.createEvent(type, payload) inside aggregate methods ` +\n\t\t\t\t\t\t\t\t`instead of createDomainEvent(...); createEvent auto-injects ` +\n\t\t\t\t\t\t\t\t`aggregateId and aggregateType. Outbox dispatchers and ` +\n\t\t\t\t\t\t\t\t`projection handlers rely on the envelope source.`,\n\t\t\t\t\t\t\trecordedEvent.type,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\t// Backstop behind the aggregate's own address check: the\n\t\t\t\t\t// envelope source is copied from the event, so an event that\n\t\t\t\t\t// names another aggregate must never become this commit.\n\t\t\t\t\tif (aggregateId !== enrolledId || aggregateType !== enrolledType) {\n\t\t\t\t\t\tthrow new EventHarvestError(\n\t\t\t\t\t\t\t`withCommit: event \"${recordedEvent.type}\" is addressed to ` +\n\t\t\t\t\t\t\t\t`${aggregateType} ${aggregateId} but was enrolled under ` +\n\t\t\t\t\t\t\t\t`${enrolledType} ${enrolledId}. The aggregate base ` +\n\t\t\t\t\t\t\t\t\"classes stamp the address on every recording path; an \" +\n\t\t\t\t\t\t\t\t\"instance from another package copy must stamp it the \" +\n\t\t\t\t\t\t\t\t\"same way.\",\n\t\t\t\t\t\t\trecordedEvent.type,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\treturn Object.freeze({\n\t\t\t\t\t\tevent: recordedEvent,\n\t\t\t\t\t\tsource: Object.freeze({ aggregateId, aggregateType }),\n\t\t\t\t\t\tposition: Object.freeze({\n\t\t\t\t\t\t\taggregateVersion: record.version as number,\n\t\t\t\t\t\t\tcommitSequence: index,\n\t\t\t\t\t\t\tcommitSize,\n\t\t\t\t\t\t}),\n\t\t\t\t\t}) as EventCommitCandidate<Evt>;\n\t\t\t\t});\n\t\t\t});\n\t\t\tif (candidates.length > 0) {\n\t\t\t\tawait deps.outbox.add(candidates);\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tresult: fnResult.result,\n\t\t\t\tcommitRecords,\n\t\t\t\tevents: candidates.map(({ event }) => event),\n\t\t\t};\n\t\t},\n\t\t{ signal: deps.signal },\n\t);\n\n\t// Post-commit: capture the persisted versions, acknowledge every saved\n\t// aggregate, and discard pending events for deleted aggregates through the\n\t// non-exported capability.\n\t// Done AFTER the tx commits so a rolled-back transaction never silently\n\t// \"consumes\" the in-memory pending events. A deleted row does not trigger\n\t// the saved-only application observer.\n\tconst persistedObservations: Array<{\n\t\treadonly aggregate: Aggregate<Id<string>, Evt>;\n\t\treadonly version: Version;\n\t}> = [];\n\tfor (const {\n\t\taggregate,\n\t\teventLifecycle,\n\t\tdisposition,\n\t\tversion,\n\t\tevents: committedEvents,\n\t} of commitRecords) {\n\t\ttry {\n\t\t\tif (disposition === \"deleted\") {\n\t\t\t\teventLifecycle.discardPendingEvents(committedEvents);\n\t\t\t} else {\n\t\t\t\teventLifecycle.acknowledge(committedEvents, version);\n\t\t\t\tpersistedObservations.push({ aggregate, version });\n\t\t\t}\n\t\t} catch (error) {\n\t\t\t// An aggregate can still be made hostile at runtime, for example by\n\t\t\t// freezing it after construction. The transaction has committed, so\n\t\t\t// continue cleaning peers and report the failed acknowledgement rather\n\t\t\t// than rejecting a successful write or double-emitting peer events.\n\t\t\treportToObserver(() => deps.onPersistError?.(error, aggregate));\n\t\t}\n\t}\n\n\t// Application observers run only after every commit record has completed\n\t// its acknowledgement attempt, and only for successful acknowledgements.\n\t// A slow or failing observer can therefore never prevent peer cleanup. Each\n\t// observer receives the version captured before any observer ran, so an\n\t// earlier callback cannot rewrite a later callback's commit receipt.\n\tconst postCommitDeadlineAt = Date.now() + postCommitTimeoutMs;\n\tconst onPersisted = deps.onPersisted;\n\tif (onPersisted) {\n\t\tfor (const { aggregate, version } of persistedObservations) {\n\t\t\ttry {\n\t\t\t\tawait runBoundedExecution(\n\t\t\t\t\t\"withCommit.onPersisted\",\n\t\t\t\t\t{ signal: deps.signal, deadlineAt: postCommitDeadlineAt },\n\t\t\t\t\t(context) => onPersisted(aggregate, version, context),\n\t\t\t\t);\n\t\t\t} catch (error) {\n\t\t\t\treportToObserver(() => deps.onPersistError?.(error, aggregate));\n\t\t\t}\n\t\t}\n\t}\n\n\tconst bus = deps.bus;\n\tif (bus && events.length > 0) {\n\t\ttry {\n\t\t\tawait runBoundedExecution(\n\t\t\t\t\"withCommit.bus.publish\",\n\t\t\t\t{ signal: deps.signal, deadlineAt: postCommitDeadlineAt },\n\t\t\t\t(context) =>\n\t\t\t\t\tbus.publish(events, {\n\t\t\t\t\t\tsignal: context.signal,\n\t\t\t\t\t\ttimeoutMs: Math.max(0, context.deadlineAt - Date.now()),\n\t\t\t\t\t}),\n\t\t\t);\n\t\t} catch (error) {\n\t\t\t// The tx has committed and the outbox holds the events; an\n\t\t\t// outbox dispatcher will deliver them. Rejecting here would turn\n\t\t\t// a committed write into an apparent use-case failure (callers\n\t\t\t// would retry and double-execute). A throwing OR async-rejecting\n\t\t\t// observer is neutralised so it cannot break the invariant either.\n\t\t\treportToObserver(() => deps.onPublishError?.(error, events));\n\t\t}\n\t}\n\n\treturn result;\n}\n","import { ok, type Result } from \"@shirudo/result\";\nimport {\n\ttype ExpectedErrorMapper,\n\thandlerOrThrow,\n\tmapHandlerFailure,\n\tregisterOnce,\n\ttype UntypedMapDispatch,\n} from \"../internal/bus-internals\";\nimport type { Query, QueryHandler } from \"./query\";\n\n/**\n * Internal adapter shape for handlers stored in the map.\n *\n * Registered handlers are typed as `QueryHandler<Q, TMap[K]>` (narrower\n * input, specific return) and cannot be stored directly in a heterogeneous\n * map (function-parameter contravariance). The closure in `register`\n * downcasts `Query` to the handler's expected `Q` based on the\n * dispatch-key invariant (we only call this entry when `query.type` matches\n * the key it was registered under). Result is widened to `unknown` here\n * and narrowed back via the public overloads on `execute` / `executeUnsafe`.\n */\ntype StoredQueryHandler = (query: Query) => Promise<unknown>;\n\n/**\n * Type map for query types to their return types.\n * Used to improve type inference in QueryBus.\n *\n * @example\n * ```typescript\n * type MyQueryMap = {\n * GetOrder: Order | null;\n * ListOrders: Order[];\n * };\n *\n * const bus = new QueryBus<MyQueryMap>();\n * const result = await bus.execute({ type: \"GetOrder\", orderId: \"123\" });\n * // result: Result<Order | null, string> ← automatically inferred\n * ```\n */\ntype QueryTypeMap = Record<string, unknown>;\n\n/**\n * Construction options for {@link QueryBus}.\n *\n * @template E - The error channel type of the bus.\n */\nexport interface QueryBusOptions<E = string> {\n\t/**\n\t * Explicitly recognizes an expected handler failure and maps it into the\n\t * bus's error channel. Return `{ error }` only for failures this boundary\n\t * owns; return `undefined` to rethrow the exact original value. With no\n\t * mapper, every handler throw propagates. Unregistered-handler and nested\n\t * bus wiring errors always propagate.\n\t */\n\tmapExpectedError?: (thrown: unknown) => { readonly error: E } | undefined;\n}\n\n/**\n * Query Bus interface for dispatching queries to their handlers.\n * Provides a centralized way to execute queries with handler registration.\n *\n * Supports an optional type map (`TMap`) for automatic return type inference.\n * Without a type map, the return type must be specified manually or defaults to `unknown`.\n * With a concrete result map, its entry is the only result type for that\n * query; the loose explicit-result overloads are unavailable.\n *\n * @template TMap - Optional mapping from query type strings to return types\n *\n * @example\n * ```typescript\n * // With a type map (recommended): the return type is inferred\n * type MyQueries = { GetOrder: Order | null; ListOrders: Order[] };\n * const bus = new QueryBus<MyQueries>();\n * const result = await bus.execute({ type: \"GetOrder\", orderId: \"123\" });\n * // result: Result<Order | null, string>\n *\n * // Without a type map: the return type defaults to `unknown`\n * const bus = new QueryBus();\n * const result = await bus.execute({ type: \"GetOrder\", orderId: \"123\" });\n * // result: Result<unknown, string>\n * ```\n */\nexport interface IQueryBus<\n\tTMap extends QueryTypeMap = QueryTypeMap,\n\tE = string,\n> {\n\t/**\n\t * Executes a query by dispatching it to the registered handler.\n\t * When a type map is provided, the return type is inferred from the query type.\n\t *\n\t * @param query - The query to execute\n\t * @returns Result containing the query result if successful, or an error of type `E`\n\t * @throws UnregisteredHandlerError when no handler is registered for\n\t * `query.type` (a wiring bug; never delivered through the channel)\n\t * @throws The exact handler failure when `mapExpectedError` is absent or\n\t * returns `undefined`\n\t * @throws ErrorMapperFailedError when `mapExpectedError` fails\n\t */\n\texecute<Q extends Query & { type: keyof TMap & string }>(\n\t\tquery: Q,\n\t): Promise<Result<TMap[Q[\"type\"]], E>>;\n\t// Manual result typing belongs only to the default untyped map shape.\n\texecute<Q extends Query, R>(\n\t\tquery: UntypedMapDispatch<TMap, Q>,\n\t): Promise<Result<R, E>>;\n\n\t/**\n\t * Executes a query by dispatching it to the registered handler.\n\t * Throws an error if no handler is registered.\n\t *\n\t * @param query - The query to execute\n\t * @returns The query result\n\t * @throws The exact handler failure or UnregisteredHandlerError\n\t */\n\texecuteUnsafe<Q extends Query & { type: keyof TMap & string }>(\n\t\tquery: Q,\n\t): Promise<TMap[Q[\"type\"]]>;\n\texecuteUnsafe<Q extends Query, R>(\n\t\tquery: UntypedMapDispatch<TMap, Q>,\n\t): Promise<R>;\n\n\t/**\n\t * Registers a handler for a specific query type.\n\t *\n\t * When `TMap` is supplied, the `queryType` argument is restricted to its\n\t * keys and the handler signature is forced to match `TMap[K]` for the\n\t * return value: typos and wrong-typed handlers are compile errors.\n\t * Without `TMap` the registration is loose (any string key, any return\n\t * type) so the no-config path keeps working.\n\t *\n\t * @param queryType - The query type to register the handler for\n\t * @param handler - The handler function for this query type\n\t */\n\tregister<\n\t\tK extends keyof TMap & string,\n\t\tQ extends Query & { type: K } = Query & { type: K },\n\t>(queryType: K, handler: QueryHandler<Q, TMap[K]>): void;\n}\n\n/**\n * Simple in-memory query bus implementation.\n * Handlers are stored in a Map and dispatched based on query type.\n *\n * Supports an optional type map (`TMap`) for automatic return type inference.\n * When `TMap` is concrete, `execute()` and `executeUnsafe()` infer the result type from the query type.\n * Explicit competing result generics cannot override that map.\n * Without `TMap`, the return type defaults to `unknown` or is specified per call.\n *\n * **Note:** This is a basic implementation suitable for development and simple use cases.\n * For production environments, consider implementing or using a more feature-rich bus that includes:\n * - Middleware/Pipeline support (logging, caching, rate limiting)\n * - Error handling\n * - Timeout handling\n * - Metrics and observability\n * - Query result caching\n * - Rate limiting\n *\n * The `QueryHandler` type can still be used with external production-grade buses\n * (e.g., RabbitMQ, AWS SQS) while maintaining type safety.\n *\n * @template TMap - Optional mapping from query type strings to return types\n *\n * @example\n * ```typescript\n * // With a type map: full inference\n * type Queries = { GetOrder: Order | null; ListOrders: Order[] };\n * const bus = new QueryBus<Queries>();\n * const result = await bus.execute({ type: \"GetOrder\", orderId: \"123\" });\n * // result: Result<Order | null, string>\n *\n * // Without a type map: specify the return type per call\n * const bus = new QueryBus();\n * bus.register(\"GetOrder\", async (query) => repository.findById(query.orderId));\n * const result = await bus.execute({ type: \"GetOrder\", orderId: \"123\" });\n * ```\n */\nexport class QueryBus<TMap extends QueryTypeMap = QueryTypeMap, E = string>\n\timplements IQueryBus<TMap, E>\n{\n\tprivate readonly handlers = new Map<string, StoredQueryHandler>();\n\tprivate readonly mapExpectedError: ExpectedErrorMapper<E> | undefined;\n\n\tconstructor(options?: QueryBusOptions<E>) {\n\t\tthis.mapExpectedError = options?.mapExpectedError;\n\t}\n\n\tregister<\n\t\tK extends keyof TMap & string,\n\t\tQ extends Query & { type: K } = Query & { type: K },\n\t>(queryType: K, handler: QueryHandler<Q, TMap[K]>): void {\n\t\tregisterOnce(this.handlers, \"query\", queryType, (query: Query) =>\n\t\t\thandler(query as Q),\n\t\t);\n\t}\n\n\tasync execute<Q extends Query & { type: keyof TMap & string }>(\n\t\tquery: Q,\n\t): Promise<Result<TMap[Q[\"type\"]], E>>;\n\t// Keep the class surface identical to IQueryBus's untyped fallback.\n\tasync execute<Q extends Query, R>(\n\t\tquery: UntypedMapDispatch<TMap, Q>,\n\t): Promise<Result<R, E>>;\n\tasync execute<Q extends Query, R>(query: Q): Promise<Result<R, E>> {\n\t\tconst handler = handlerOrThrow(this.handlers, \"query\", query.type);\n\t\ttry {\n\t\t\tconst result = (await handler(query)) as R;\n\t\t\treturn ok(result);\n\t\t} catch (error) {\n\t\t\treturn mapHandlerFailure(error, this.mapExpectedError, \"query\");\n\t\t}\n\t}\n\n\tasync executeUnsafe<Q extends Query & { type: keyof TMap & string }>(\n\t\tquery: Q,\n\t): Promise<TMap[Q[\"type\"]]>;\n\tasync executeUnsafe<Q extends Query, R>(\n\t\tquery: UntypedMapDispatch<TMap, Q>,\n\t): Promise<R>;\n\tasync executeUnsafe<Q extends Query, R>(query: Q): Promise<R> {\n\t\t// Same no-handler gate as execute: one implementation so the two\n\t\t// paths cannot drift.\n\t\tconst handler = handlerOrThrow(this.handlers, \"query\", query.type);\n\t\treturn (await handler(query)) as R;\n\t}\n}\n","import { InMemoryCapacityExceededError } from \"../../../errors/kit-errors\";\nimport {\n\tassertPositiveInteger,\n\tassertPositiveSafeInteger,\n} from \"../../../internal/validate\";\nimport type {\n\tDeadLetterDeadline,\n\tDeadlineStore,\n\tDueDeadline,\n} from \"../deadline-store\";\n\n/** Construction options for {@link InMemoryDeadlineStore}. */\nexport interface InMemoryDeadlineStoreOptions {\n\t/** Maximum records retained across pending and dead-letter states. */\n\treadonly maxRecords?: number;\n\n\t/**\n\t * How many failed delivery attempts move a deadline to the\n\t * dead-letter set. Default `5`.\n\t */\n\tmaxDeliveryAttempts?: number;\n}\n\ninterface StoredDeadline<TPayload> {\n\tdeliveryId: string;\n\tscope: string;\n\tkey: string;\n\tdueAt: Date;\n\tpayload: TPayload;\n\tattempts: number;\n\t/** Monotonic tie-breaker: scheduling order for equal due times. */\n\tsequence: number;\n\tlastError?: string;\n}\n\n/**\n * In-memory reference implementation of {@link DeadlineStore}: defines\n * the port's semantics and serves finite-lifetime tests and demos. Without\n * `maxRecords`, pending and dead-letter records are unbounded. A configured\n * limit rejects a new address before mutation; delivery state is never\n * silently evicted.\n *\n * **Not transaction-aware**, the same documented limitation as the\n * other in-memory references: a rolled-back `schedule` or `cancel`\n * stays applied here. The transactional half of the contract is the\n * SQL adapter's job; prove it with `createDeadlineStoreContractTests`\n * and its rollback capability.\n *\n * Payloads are deep-copied on schedule and on delivery\n * (`structuredClone`), so neither side can mutate the other's copy.\n */\nexport class InMemoryDeadlineStore<TPayload = unknown>\n\timplements DeadlineStore<TPayload>\n{\n\tprivate readonly pending = new Map<string, StoredDeadline<TPayload>>();\n\t/** Keyed by deliveryId: several incarnations of one address can be dead. */\n\tprivate readonly dead = new Map<string, StoredDeadline<TPayload>>();\n\tprivate readonly maxDeliveryAttempts: number;\n\tprivate readonly maxRecords: number | undefined;\n\tprivate nextSequence = 0;\n\n\tconstructor(options: InMemoryDeadlineStoreOptions = {}) {\n\t\tconst max = options.maxDeliveryAttempts ?? 5;\n\t\tassertPositiveInteger(\"InMemoryDeadlineStore\", \"maxDeliveryAttempts\", max);\n\t\tthis.maxDeliveryAttempts = max;\n\t\tif (options.maxRecords !== undefined) {\n\t\t\tassertPositiveSafeInteger(\n\t\t\t\t\"InMemoryDeadlineStore\",\n\t\t\t\t\"maxRecords\",\n\t\t\t\toptions.maxRecords,\n\t\t\t);\n\t\t}\n\t\tthis.maxRecords = options.maxRecords;\n\t}\n\n\tasync schedule(deadline: {\n\t\tscope: string;\n\t\tkey: string;\n\t\tdueAt: Date;\n\t\tpayload: TPayload;\n\t}): Promise<void> {\n\t\tconst deadlineAddress = address(deadline.scope, deadline.key);\n\t\tif (\n\t\t\t!this.pending.has(deadlineAddress) &&\n\t\t\tthis.maxRecords !== undefined &&\n\t\t\tthis.pending.size + this.dead.size >= this.maxRecords\n\t\t) {\n\t\t\tthrow new InMemoryCapacityExceededError({\n\t\t\t\tstore: \"InMemoryDeadlineStore\",\n\t\t\t\tresource: \"records\",\n\t\t\t\tlimit: this.maxRecords,\n\t\t\t\tcurrent: this.pending.size + this.dead.size,\n\t\t\t\tattempted: 1,\n\t\t\t});\n\t\t}\n\t\tconst sequence = this.nextSequence++;\n\t\t// Replacing an occupied address gets a FRESH incarnation: a late\n\t\t// ack or failure report against the old deliveryId must not touch\n\t\t// the successor.\n\t\tthis.pending.set(deadlineAddress, {\n\t\t\tdeliveryId: `deadline-${sequence}`,\n\t\t\tscope: deadline.scope,\n\t\t\tkey: deadline.key,\n\t\t\tdueAt: new Date(deadline.dueAt),\n\t\t\tpayload: structuredClone(deadline.payload),\n\t\t\tattempts: 0,\n\t\t\tsequence,\n\t\t});\n\t}\n\n\tasync cancel(scope: string, key: string): Promise<void> {\n\t\tthis.pending.delete(address(scope, key));\n\t}\n\n\tasync due(\n\t\tnow: Date,\n\t\tlimit: number,\n\t): Promise<ReadonlyArray<DueDeadline<TPayload>>> {\n\t\tif (!Number.isInteger(limit) || limit < 0) {\n\t\t\tthrow new Error(\n\t\t\t\t`InMemoryDeadlineStore: limit must be an integer >= 0, got ${limit}`,\n\t\t\t);\n\t\t}\n\t\t// \"Up to limit\": zero is a legal page size and yields an empty page\n\t\t// (a loop computing capacity - inFlight may legitimately pass it).\n\t\tif (limit === 0) return [];\n\t\treturn [...this.pending.values()]\n\t\t\t.filter((deadline) => deadline.dueAt.getTime() <= now.getTime())\n\t\t\t.sort(\n\t\t\t\t(a, b) =>\n\t\t\t\t\ta.dueAt.getTime() - b.dueAt.getTime() || a.sequence - b.sequence,\n\t\t\t)\n\t\t\t.slice(0, limit)\n\t\t\t.map((deadline) => toRecord(deadline));\n\t}\n\n\tasync markDelivered(deliveryIds: ReadonlyArray<string>): Promise<void> {\n\t\tfor (const deliveryId of deliveryIds) {\n\t\t\tthis.dead.delete(deliveryId);\n\t\t\tfor (const [key, deadline] of this.pending) {\n\t\t\t\tif (deadline.deliveryId === deliveryId) {\n\t\t\t\t\tthis.pending.delete(key);\n\t\t\t\t\tbreak; // deliveryIds are unique; nothing more to find\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tasync markFailed(\n\t\tdeliveryId: string,\n\t\terror?: unknown,\n\t): Promise<DeadLetterDeadline<TPayload> | undefined> {\n\t\tfor (const [key, deadline] of this.pending) {\n\t\t\tif (deadline.deliveryId !== deliveryId) continue;\n\t\t\tdeadline.attempts += 1;\n\t\t\t// An errorless report must not erase an earlier recorded reason.\n\t\t\tif (error !== undefined) deadline.lastError = String(error);\n\t\t\tif (deadline.attempts >= this.maxDeliveryAttempts) {\n\t\t\t\tthis.pending.delete(key);\n\t\t\t\tthis.dead.set(deadline.deliveryId, deadline);\n\t\t\t\treturn toDeadLetter(deadline);\n\t\t\t}\n\t\t\treturn undefined;\n\t\t}\n\t\t// Unknown, delivered, replaced, or already dead-lettered: a late\n\t\t// report must not resurrect or advance anything.\n\t\treturn undefined;\n\t}\n\n\tasync deadLetters(): Promise<ReadonlyArray<DeadLetterDeadline<TPayload>>> {\n\t\treturn [...this.dead.values()]\n\t\t\t.sort((a, b) => a.sequence - b.sequence)\n\t\t\t.map(toDeadLetter);\n\t}\n}\n\nfunction toDeadLetter<TPayload>(\n\tdeadline: StoredDeadline<TPayload>,\n): DeadLetterDeadline<TPayload> {\n\treturn {\n\t\t...toRecord(deadline),\n\t\t...(deadline.lastError === undefined\n\t\t\t? {}\n\t\t\t: { lastError: deadline.lastError }),\n\t};\n}\n\nfunction toRecord<TPayload>(\n\tdeadline: StoredDeadline<TPayload>,\n): DueDeadline<TPayload> {\n\treturn {\n\t\tdeliveryId: deadline.deliveryId,\n\t\tscope: deadline.scope,\n\t\tkey: deadline.key,\n\t\tdueAt: new Date(deadline.dueAt),\n\t\tpayload: structuredClone(deadline.payload),\n\t\tattempts: deadline.attempts,\n\t};\n}\n\n/** NUL-separated so no scope/key concatenation can collide. */\nfunction address(scope: string, key: string): string {\n\treturn `${scope}\\u0000${key}`;\n}\n","/**\n * Exponential backoff with jitter, shared by every retry loop in the\n * kit (`RetryingTransactionScope` attempt delays, `OutboxDispatcher`\n * failure backoff).\n *\n * `attempt` is 1-based. The exponential value\n * (`baseDelayMs * 2^(attempt-1)`) is capped at `maxDelayMs`, then a\n * jitter band (`* random(0.8, 1.2)`) is applied and re-clamped to the\n * cap. Pure and deterministic given `random`. Result is never\n * negative.\n *\n * Deliberately not exported from the package entries: it is shared\n * kit plumbing, not public API.\n */\nexport function computeBackoffDelay(\n\tattempt: number,\n\topts: { baseDelayMs: number; maxDelayMs: number; random: () => number },\n): number {\n\tconst exponential = opts.baseDelayMs * 2 ** (attempt - 1);\n\tconst capped = Math.min(opts.maxDelayMs, exponential);\n\tconst jitter = 0.8 + opts.random() * 0.4; // [0.8, 1.2)\n\treturn Math.max(0, Math.min(opts.maxDelayMs, Math.round(capped * jitter)));\n}\n\n/**\n * Wraps an injected jitter source with observer-grade robustness: a\n * throwing or non-finite source degrades to the midpoint multiplier\n * (no jitter) instead of rejecting the poller that uses it, which\n * documents itself as never rejecting and is typically `void`ed.\n */\nexport function neutralJitterSource(source: () => number): () => number {\n\treturn () => {\n\t\ttry {\n\t\t\tconst value = source();\n\t\t\treturn Number.isFinite(value) ? value : 0.5;\n\t\t} catch {\n\t\t\treturn 0.5;\n\t\t}\n\t};\n}\n","/**\n * Awaits an in-flight pass on behalf of a joining caller without\n * letting a signal-less pass hold the joiner hostage: on the joiner's\n * abort this resolves `\"stopped\"` and leaves the pass running for its\n * owner. The pass promise must never reject (the pollers' documented\n * contract), so a plain `then` suffices; the abort listener is removed\n * once the pass settles.\n */\nexport function joinWithoutBlockingOnAbort(\n\tpass: Promise<\"drained\" | \"stopped\">,\n\tsignal: AbortSignal | undefined,\n): Promise<\"drained\" | \"stopped\"> {\n\tif (signal === undefined) return pass;\n\tif (signal.aborted) return Promise.resolve(\"stopped\");\n\treturn new Promise((resolve) => {\n\t\tconst onAbort = (): void => resolve(\"stopped\");\n\t\tsignal.addEventListener(\"abort\", onAbort, { once: true });\n\t\tvoid pass.then((outcome) => {\n\t\t\tsignal.removeEventListener(\"abort\", onAbort);\n\t\t\tresolve(outcome);\n\t\t});\n\t});\n}\n","import { abortReason } from \"./abort\";\n\n/**\n * Abortable `setTimeout` that RESOLVES early when the signal fires.\n * The graceful-stop variant: callers that treat an abort as \"stop\n * sleeping and wind down\" (a worker loop's idle or backoff sleep) use\n * this so the loop can observe `signal.aborted` and return cleanly.\n */\nexport function sleepResolvingOnAbort(\n\tms: number,\n\tsignal: AbortSignal,\n): Promise<void> {\n\tif (ms <= 0 || signal.aborted) return Promise.resolve();\n\treturn new Promise((resolve) => {\n\t\tconst done = (): void => {\n\t\t\tclearTimeout(timer);\n\t\t\tsignal.removeEventListener(\"abort\", done);\n\t\t\tresolve();\n\t\t};\n\t\tconst timer = setTimeout(done, ms);\n\t\tsignal.addEventListener(\"abort\", done, { once: true });\n\t});\n}\n\n/**\n * Abortable `setTimeout` that REJECTS with the signal's reason when it\n * fires. The cancellation variant: callers that treat an abort as \"this\n * operation failed, propagate it\" (a retry loop whose caller awaits the\n * result) use this so the rejection carries through.\n */\nexport function sleepRejectingOnAbort(\n\tms: number,\n\tsignal: AbortSignal | undefined,\n\tabortMessage: string,\n): Promise<void> {\n\treturn new Promise<void>((resolve, reject) => {\n\t\tif (signal?.aborted) {\n\t\t\treject(abortReason(signal, abortMessage));\n\t\t\treturn;\n\t\t}\n\t\tlet onAbort: (() => void) | undefined;\n\t\tconst timer = setTimeout(() => {\n\t\t\tif (onAbort && signal) signal.removeEventListener(\"abort\", onAbort);\n\t\t\tresolve();\n\t\t}, ms);\n\t\tif (signal) {\n\t\t\tonAbort = () => {\n\t\t\t\tclearTimeout(timer);\n\t\t\t\treject(abortReason(signal, abortMessage));\n\t\t\t};\n\t\t\tsignal.addEventListener(\"abort\", onAbort, { once: true });\n\t\t}\n\t});\n}\n","import { assertNonNegativeFinite, assertPositiveInteger } from \"../validate\";\nimport { computeBackoffDelay, neutralJitterSource } from \"./backoff\";\nimport { joinWithoutBlockingOnAbort } from \"./in-flight\";\nimport { sleepResolvingOnAbort } from \"./sleep\";\n\n/** Numeric options every kit poll loop shares; see the concrete classes. */\nexport interface PollLoopOptions {\n\tbatchSize?: number;\n\tpollIntervalMs?: number;\n\tbaseDelayMs?: number;\n\tmaxDelayMs?: number;\n\trandom?: () => number;\n}\n\n/**\n * The hardened poll-loop shell shared by `OutboxDispatcher` and\n * `DeadlineProcessor`, so the operationally tricky parts exist exactly\n * once: the never-rejecting `run(signal)` cadence (idle sleep when\n * drained, jittered streak backoff when stopped), the reentrancy-safe\n * `drainOnce` that joins an in-flight pass instead of starting a\n * competing one, option validation, and the per-instance neutralized\n * jitter source. Subclasses implement one thing: {@link pass}, the\n * delivery semantics of their port. Internal plumbing, not exported\n * from the package entries.\n */\nexport abstract class PollLoop {\n\tprotected readonly batchSize: number;\n\tprivate readonly pollIntervalMs: number;\n\tprivate readonly baseDelayMs: number;\n\tprivate readonly maxDelayMs: number;\n\tprivate readonly jitter: () => number;\n\n\t/**\n\t * Failed cycles since the last clean one; drives the backoff.\n\t * Subclasses bump it once per failed cycle and reset it on clean or\n\t * empty cycles (a subclass may bump by more, e.g. to a record's\n\t * attempt count, via direct assignment).\n\t */\n\tprotected consecutiveFailures = 0;\n\n\t/** In-flight pass; overlapping drainOnce calls join it. */\n\tprivate inFlightPass?: Promise<\"drained\" | \"stopped\">;\n\n\tprotected constructor(context: string, options: PollLoopOptions) {\n\t\tconst batchSize = options.batchSize ?? 32;\n\t\tassertPositiveInteger(context, \"batchSize\", batchSize);\n\t\tthis.batchSize = batchSize;\n\t\tthis.pollIntervalMs = options.pollIntervalMs ?? 250;\n\t\tthis.baseDelayMs = options.baseDelayMs ?? 50;\n\t\tthis.maxDelayMs = options.maxDelayMs ?? 5000;\n\t\tassertNonNegativeFinite(context, \"pollIntervalMs\", this.pollIntervalMs);\n\t\tassertNonNegativeFinite(context, \"baseDelayMs\", this.baseDelayMs);\n\t\tassertNonNegativeFinite(context, \"maxDelayMs\", this.maxDelayMs);\n\t\tthis.jitter = neutralJitterSource(options.random ?? Math.random);\n\t}\n\n\t/**\n\t * One full pass over the backlog: loop batches until nothing is\n\t * pending (`\"drained\"`) or a failure ends the cycle (`\"stopped\"`).\n\t * Must never reject; only ever one pass is in flight.\n\t */\n\tprotected abstract pass(signal?: AbortSignal): Promise<\"drained\" | \"stopped\">;\n\n\t/**\n\t * Runs the poll loop until `signal` aborts, then resolves. Never\n\t * rejects: a `\"drained\"` pass sleeps `pollIntervalMs`, a `\"stopped\"`\n\t * one sleeps the current streak backoff.\n\t */\n\tasync run(signal: AbortSignal): Promise<void> {\n\t\twhile (!signal.aborted) {\n\t\t\tconst outcome = await this.drainOnce(signal);\n\t\t\tif (signal.aborted) return;\n\t\t\tif (outcome === \"drained\") {\n\t\t\t\tawait sleepResolvingOnAbort(this.pollIntervalMs, signal);\n\t\t\t} else {\n\t\t\t\tawait sleepResolvingOnAbort(this.currentBackoff(), signal);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Single pass for cron triggers and serverless runtimes; returns\n\t * without sleeping (the tick cadence is the retry pacing; only\n\t * `run` sleeps the backoff). Reentrancy-safe: a call during an\n\t * in-flight pass joins it, and the joining call's own `signal`\n\t * still ends its wait while the pass runs on for its owner.\n\t *\n\t * With producers that keep the backlog non-empty, \"until drained\"\n\t * can outlast a bounded invocation: pass a `signal` wired to your\n\t * runtime's deadline (`AbortSignal.timeout(...)`) so the pass ends\n\t * cleanly; completed work stays acknowledged, the rest waits for\n\t * the next tick.\n\t */\n\tasync drainOnce(signal?: AbortSignal): Promise<\"drained\" | \"stopped\"> {\n\t\tif (this.inFlightPass !== undefined) {\n\t\t\treturn joinWithoutBlockingOnAbort(this.inFlightPass, signal);\n\t\t}\n\t\tconst pass = this.pass(signal);\n\t\tthis.inFlightPass = pass;\n\t\ttry {\n\t\t\treturn await pass;\n\t\t} finally {\n\t\t\tthis.inFlightPass = undefined;\n\t\t}\n\t}\n\n\t/** Backoff for the current consecutive-failure streak. */\n\tprivate currentBackoff(): number {\n\t\treturn computeBackoffDelay(Math.max(1, this.consecutiveFailures), {\n\t\t\tbaseDelayMs: this.baseDelayMs,\n\t\t\tmaxDelayMs: this.maxDelayMs,\n\t\t\trandom: this.jitter,\n\t\t});\n\t}\n}\n","/** Operational classification applied to one failed background delivery. */\nexport type DeliveryFailureKind = \"transient\" | \"permanent\" | \"unknown\";\n\n/** Consumer-owned translation from an adapter error to delivery semantics. */\nexport type DeliveryFailureClassifier = (error: unknown) => DeliveryFailureKind;\n\n/** Result of applying a delivery-failure classifier safely. */\nexport interface DeliveryFailureAssessment {\n\t/** How the shell will account for and recover from the failure. */\n\treadonly kind: DeliveryFailureKind;\n\t/** Classifier bug or invalid return value, when classification itself failed. */\n\treadonly classifierError?: unknown;\n}\n\nconst KINDS = new Set<DeliveryFailureKind>([\n\t\"transient\",\n\t\"permanent\",\n\t\"unknown\",\n]);\n\n/**\n * Default delivery classification. A retryable marker anywhere in the cause\n * chain, or a native `TimeoutError`, is transient. An explicit\n * `retryable: false` marker is permanent. Unmapped errors stay unknown and use\n * the shell's safe accounting default.\n */\nexport function classifyDeliveryFailure(error: unknown): DeliveryFailureKind {\n\tlet current = error;\n\tlet sawNonRetryable = false;\n\tconst seen = new Set<object>();\n\n\twhile (\n\t\tcurrent !== null &&\n\t\t(typeof current === \"object\" || typeof current === \"function\")\n\t) {\n\t\tconst node = current as object;\n\t\tif (seen.has(node)) break;\n\t\tseen.add(node);\n\n\t\ttry {\n\t\t\tconst candidate = current as {\n\t\t\t\treadonly name?: unknown;\n\t\t\t\treadonly retryable?: unknown;\n\t\t\t\treadonly cause?: unknown;\n\t\t\t};\n\t\t\tif (candidate.name === \"TimeoutError\") return \"transient\";\n\t\t\tif (candidate.retryable === true) return \"transient\";\n\t\t\tif (candidate.retryable === false) sawNonRetryable = true;\n\t\t\tcurrent = candidate.cause;\n\t\t} catch {\n\t\t\treturn \"unknown\";\n\t\t}\n\t}\n\n\treturn sawNonRetryable ? \"permanent\" : \"unknown\";\n}\n\n/** Applies a custom/default classifier without letting it break the worker. */\nexport function assessDeliveryFailure(\n\terror: unknown,\n\tclassifier: DeliveryFailureClassifier = classifyDeliveryFailure,\n): DeliveryFailureAssessment {\n\ttry {\n\t\tconst kind = classifier(error);\n\t\tif (KINDS.has(kind)) return Object.freeze({ kind });\n\t\treturn Object.freeze({\n\t\t\tkind: \"unknown\",\n\t\t\tclassifierError: new TypeError(\n\t\t\t\t`Delivery failure classifier returned invalid kind: ${String(kind)}`,\n\t\t\t),\n\t\t});\n\t} catch (classifierError) {\n\t\treturn Object.freeze({ kind: \"unknown\", classifierError });\n\t}\n}\n","import {\n\tDEFAULT_EXECUTION_TIMEOUT_MS,\n\ttype ExecutionContext,\n\trunBoundedExecution,\n} from \"../../internal/async/execution\";\nimport { PollLoop } from \"../../internal/async/poll-loop\";\nimport {\n\tassessDeliveryFailure,\n\ttype DeliveryFailureAssessment,\n\ttype DeliveryFailureClassifier,\n} from \"../../internal/delivery-failure\";\nimport {\n\tcaptureObserverFunctions,\n\treportToObserver,\n} from \"../../internal/observer\";\nimport { assertNonNegativeFinite } from \"../../internal/validate\";\nimport type {\n\tDeadLetterDeadline,\n\tDeadlineStore,\n\tDueDeadline,\n} from \"./deadline-store\";\n\n/**\n * Required operational observers for {@link DeadlineProcessor}. All hooks are\n * best-effort notifications: synchronous throws and rejected promises are\n * neutralized so observability cannot change delivery state. The processor\n * captures and freezes these function references at construction, so later\n * mutation of the supplied object cannot disable an operational channel.\n *\n * `onDeadLetter` fires immediately after `markFailed` reports the exact\n * transition. It is not a durable notification boundary: a process can stop\n * after the store commits the transition and before the callback runs. Keep\n * polling {@link DeadlineStore.deadLetters} for durable alerting and\n * reconciliation; the hook provides low-latency diagnostics.\n */\nexport interface DeadlineProcessorObservers<TPayload> {\n\t/**\n\t * A handler, acknowledgement, or failure-tracking operation failed.\n\t * Handler failures include their accounting assessment; store failures do\n\t * not consume poison-message attempts and have no assessment.\n\t */\n\treadonly onDeliveryError: (\n\t\terror: unknown,\n\t\tdeadline: DueDeadline<TPayload>,\n\t\tassessment?: DeliveryFailureAssessment,\n\t) => void;\n\t/** Reading the poll clock or due page failed. */\n\treadonly onPollError: (error: unknown) => void;\n\t/** A deadline crossed the store's dead-letter threshold. */\n\treadonly onDeadLetter: (deadline: DeadLetterDeadline<TPayload>) => void;\n}\n\n/** Construction options for {@link DeadlineProcessor}. */\nexport interface DeadlineProcessorOptions<TPayload> {\n\t/** The poll surface; see {@link DeadlineStore}. */\n\tstore: DeadlineStore<TPayload>;\n\n\t/** Complete, required operational observer bundle. */\n\tobservers: DeadlineProcessorObservers<TPayload>;\n\n\t/**\n\t * Receives each due deadline as an input. A throw signals delivery\n\t * failure: the processor reports it via `markFailed` (the store\n\t * dead-letters past its ceiling) and moves on to the next deadline;\n\t * neighbors are independent. Remember the guide's discipline: a\n\t * delivered deadline is a proposal, so check it against current\n\t * state before acting. Pass `context.signal` to I/O adapters or enforce a\n\t * native timeout no later than `context.deadlineAt`. The shell bounds its\n\t * wait but cannot terminate an ignored foreign promise; production handlers\n\t * must prevent zombie work from overlapping a retry.\n\t */\n\thandler: (\n\t\tdeadline: DueDeadline<TPayload>,\n\t\tcontext: ExecutionContext,\n\t) => Promise<void> | void;\n\n\t/** Deadlines fetched per poll. Default `32`. */\n\tbatchSize?: number;\n\n\t/** Idle sleep between polls when nothing is due. Default `250`ms. */\n\tpollIntervalMs?: number;\n\n\t/**\n\t * First backoff delay after a failed cycle; grows exponentially with\n\t * the processor's consecutive-failure streak and is jittered.\n\t * Default `50`ms.\n\t */\n\tbaseDelayMs?: number;\n\n\t/** Ceiling for the failure backoff. Default `5000`ms. */\n\tmaxDelayMs?: number;\n\n\t/**\n\t * Maximum time to await one deadline handler. The handler receives the same\n\t * deadline as an AbortSignal and an absolute `deadlineAt`. Default `30000`ms.\n\t */\n\tdeliveryTimeoutMs?: number;\n\n\t/**\n\t * Maximum time to await one poll-store read, acknowledgement, or failure\n\t * update. The store receives the same cooperative context. This bounds the\n\t * worker's wait; production adapters must also cancel or natively bound the\n\t * underlying I/O. Default `30000`ms.\n\t */\n\tstorageTimeoutMs?: number;\n\n\t/**\n\t * Classifies handler failures as transient, permanent, or unknown. Transient\n\t * failures back off without consuming the poison ceiling; permanent and\n\t * unknown failures count. The default walks the cause chain: native\n\t * `TimeoutError` and `retryable: true` are transient, `retryable: false` is\n\t * permanent, and unmapped errors are unknown. A throwing or invalid custom\n\t * classifier becomes unknown and is exposed through the observer assessment\n\t * without replacing the original handler error.\n\t */\n\tclassifyFailure?: DeliveryFailureClassifier;\n\n\t/**\n\t * Jitter source for the failure backoff, injectable for\n\t * deterministic tests. Default `Math.random`. Neutralized like every\n\t * user callback: a throwing or non-finite source degrades to the\n\t * midpoint multiplier.\n\t */\n\trandom?: () => number;\n\n\t/**\n\t * The clock the poll passes to {@link DeadlineStore.due}. Omit it to use\n\t * `() => new Date()`. An injected clock that throws or returns an invalid\n\t * `Date` fails the cycle before the store is read, reports through\n\t * `onPollError`, and participates in the normal failure backoff.\n\t */\n\tclock?: () => Date;\n}\n\n/**\n * The hardened delivery loop for {@link DeadlineStore}: poll due\n * deadlines, hand each one to the handler, acknowledge or report the\n * failure. The delivery semantics are deliberately simpler than the\n * outbox dispatcher's, because deadlines carry no ordering: a HANDLER\n * failure never stops the batch; the failing deadline is reported via\n * `markFailed` and its neighbors keep flowing in the same cycle.\n *\n * What it shares with the dispatcher is the loop hardening, which is\n * exactly the part hand-rolled loops get wrong:\n *\n * - **Never rejects.** Clock and poll errors, handler throws, ack failures,\n * and observer bugs are absorbed and reported; `run(signal)` resolves on\n * abort and never becomes an unhandled rejection.\n * - **Backs off under failure.** A cycle containing any failure grows\n * the jittered exponential backoff toward `maxDelayMs` (one step per\n * cycle); an empty backlog or a clean cycle resets the streak.\n * - **Reentrancy-safe.** A `drainOnce` call while a pass is in flight\n * joins that pass instead of starting a competing poll (overlapping\n * cron ticks would double-deliver); a joining call still honors its\n * own signal.\n * - **At-least-once.** A crash or ack failure after handling\n * redelivers; handlers stay idempotent (the guide shows the\n * idempotency-store wiring). Delivered deadlines are acknowledged in\n * ONE `markDelivered` call per cycle, and an ack failure ends the\n * cycle: it signals the store's write path, not a poison record, so\n * it is reported per affected deadline, never to `markFailed`\n * (counting it toward the poison ceiling would dead-letter healthy\n * work), and the backoff paces the redelivery instead of the pass\n * re-running every handler against a dead write path.\n * - **Bounded waiting requires bounded adapters.** Delivery and store operations\n * receive cooperative cancellation and an absolute deadline. The processor\n * returns after its configured bound even when a promise ignores the signal,\n * but only the adapter can terminate native I/O and prevent late work from\n * overlapping a retry. A late idempotent acknowledgement remains valid.\n *\n * Run one logical processor per store unless the adapter's `due`\n * claims records; the same rule as the dispatcher.\n */\nexport class DeadlineProcessor<TPayload = unknown> extends PollLoop {\n\tprivate readonly store: DeadlineStore<TPayload>;\n\tprivate readonly handler: (\n\t\tdeadline: DueDeadline<TPayload>,\n\t\tcontext: ExecutionContext,\n\t) => Promise<void> | void;\n\tprivate readonly clock: () => Date;\n\tprivate readonly observers: DeadlineProcessorObservers<TPayload>;\n\tprivate readonly deliveryTimeoutMs: number;\n\tprivate readonly storageTimeoutMs: number;\n\tprivate readonly classifyFailure?: DeliveryFailureClassifier;\n\n\tconstructor(options: DeadlineProcessorOptions<TPayload>) {\n\t\tsuper(\"DeadlineProcessor\", options);\n\t\tthis.observers = captureObserverFunctions(\n\t\t\t\"DeadlineProcessor\",\n\t\t\toptions.observers,\n\t\t\t[\"onDeliveryError\", \"onPollError\", \"onDeadLetter\"],\n\t\t);\n\t\tthis.store = options.store;\n\t\tthis.handler = options.handler;\n\t\tthis.classifyFailure = options.classifyFailure;\n\t\tthis.clock = options.clock ?? (() => new Date());\n\t\tthis.deliveryTimeoutMs =\n\t\t\toptions.deliveryTimeoutMs ?? DEFAULT_EXECUTION_TIMEOUT_MS;\n\t\tthis.storageTimeoutMs =\n\t\t\toptions.storageTimeoutMs ?? DEFAULT_EXECUTION_TIMEOUT_MS;\n\t\tassertNonNegativeFinite(\n\t\t\t\"DeadlineProcessor\",\n\t\t\t\"deliveryTimeoutMs\",\n\t\t\tthis.deliveryTimeoutMs,\n\t\t);\n\t\tassertNonNegativeFinite(\n\t\t\t\"DeadlineProcessor\",\n\t\t\t\"storageTimeoutMs\",\n\t\t\tthis.storageTimeoutMs,\n\t\t);\n\t}\n\n\t/**\n\t * One full delivery pass (the `run`/`drainOnce` shell lives on\n\t * {@link PollLoop}): delivers due deadlines batch by batch until\n\t * nothing is due or a cycle contained a failure.\n\t */\n\tprotected async pass(signal?: AbortSignal): Promise<\"drained\" | \"stopped\"> {\n\t\twhile (!signal?.aborted) {\n\t\t\tlet batch: ReadonlyArray<DueDeadline<TPayload>>;\n\t\t\ttry {\n\t\t\t\tbatch = await runBoundedExecution(\n\t\t\t\t\t\"DeadlineProcessor.due\",\n\t\t\t\t\t{ signal, timeoutMs: this.storageTimeoutMs },\n\t\t\t\t\t(context) => this.store.due(this.now(), this.batchSize, context),\n\t\t\t\t);\n\t\t\t} catch (error) {\n\t\t\t\tif (signal?.aborted) return \"stopped\";\n\t\t\t\tthis.consecutiveFailures += 1;\n\t\t\t\treportToObserver(() => this.observers.onPollError(error));\n\t\t\t\treturn \"stopped\";\n\t\t\t}\n\t\t\tif (batch.length === 0) {\n\t\t\t\tthis.consecutiveFailures = 0;\n\t\t\t\treturn \"drained\";\n\t\t\t}\n\n\t\t\t// Handler failures do NOT stop the batch: deadlines carry no\n\t\t\t// cross-address ordering, so a poison deadline blocks only\n\t\t\t// itself and is reported to the store's bounded retries.\n\t\t\tlet handlerFailed = false;\n\t\t\tconst delivered: DueDeadline<TPayload>[] = [];\n\t\t\tfor (const deadline of batch) {\n\t\t\t\tif (signal?.aborted) break;\n\t\t\t\tlet boundedContext: ExecutionContext | undefined;\n\t\t\t\ttry {\n\t\t\t\t\tawait runBoundedExecution(\n\t\t\t\t\t\t\"DeadlineProcessor.handler\",\n\t\t\t\t\t\t{ signal, timeoutMs: this.deliveryTimeoutMs },\n\t\t\t\t\t\t(context) => {\n\t\t\t\t\t\t\tboundedContext = context;\n\t\t\t\t\t\t\treturn this.handler(deadline, context);\n\t\t\t\t\t\t},\n\t\t\t\t\t);\n\t\t\t\t\tdelivered.push(deadline);\n\t\t\t\t} catch (error) {\n\t\t\t\t\tif (signal?.aborted) break;\n\t\t\t\t\thandlerFailed = true;\n\t\t\t\t\tconst assessment = assessDeliveryFailure(error, this.classifyFailure);\n\t\t\t\t\treportToObserver(() =>\n\t\t\t\t\t\tthis.observers.onDeliveryError(error, deadline, assessment),\n\t\t\t\t\t);\n\t\t\t\t\t// The processor's own delivery budget expiring is\n\t\t\t\t\t// deterministic evidence against THIS deliveryId, not a\n\t\t\t\t\t// transient infrastructure hiccup: without consuming an\n\t\t\t\t\t// attempt, a handler that permanently ignores\n\t\t\t\t\t// context.signal never reaches the dead letter and every\n\t\t\t\t\t// poll re-serves it and spawns another zombie execution.\n\t\t\t\t\tconst ownBudgetExpired =\n\t\t\t\t\t\t!signal?.aborted && boundedContext?.signal.aborted === true;\n\t\t\t\t\tif (assessment.kind !== \"transient\" || ownBudgetExpired) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst deadLetter = await runBoundedExecution(\n\t\t\t\t\t\t\t\t\"DeadlineProcessor.markFailed\",\n\t\t\t\t\t\t\t\t{ signal, timeoutMs: this.storageTimeoutMs },\n\t\t\t\t\t\t\t\t(context) =>\n\t\t\t\t\t\t\t\t\tthis.store.markFailed(deadline.deliveryId, error, context),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\tif (deadLetter !== undefined) {\n\t\t\t\t\t\t\t\treportToObserver(() => this.observers.onDeadLetter(deadLetter));\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} catch (markError) {\n\t\t\t\t\t\t\tif (!signal?.aborted) {\n\t\t\t\t\t\t\t\treportToObserver(() =>\n\t\t\t\t\t\t\t\t\tthis.observers.onDeliveryError(markError, deadline),\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// One ack round-trip per cycle. An ack failure DOES stop the\n\t\t\t// cycle: it signals the store's write path, not a poison\n\t\t\t// record; continuing would re-run every handler against a dead\n\t\t\t// write path on each backoff step. Every handled deadline will\n\t\t\t// redeliver (the documented duplicates), so each is reported.\n\t\t\tlet acked = true;\n\t\t\tif (delivered.length > 0) {\n\t\t\t\ttry {\n\t\t\t\t\t// A completed handler keeps one bounded acknowledgement attempt\n\t\t\t\t\t// when shutdown won immediately after completion. An acknowledgement\n\t\t\t\t\t// that was already running remains owner-cancellable.\n\t\t\t\t\tconst acknowledgementSignal = signal?.aborted ? undefined : signal;\n\t\t\t\t\tawait runBoundedExecution(\n\t\t\t\t\t\t\"DeadlineProcessor.markDelivered\",\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tsignal: acknowledgementSignal,\n\t\t\t\t\t\t\ttimeoutMs: this.storageTimeoutMs,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t(context) =>\n\t\t\t\t\t\t\tthis.store.markDelivered(\n\t\t\t\t\t\t\t\tdelivered.map((deadline) => deadline.deliveryId),\n\t\t\t\t\t\t\t\tcontext,\n\t\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\t} catch (error) {\n\t\t\t\t\tacked = false;\n\t\t\t\t\tif (!signal?.aborted) {\n\t\t\t\t\t\tfor (const deadline of delivered) {\n\t\t\t\t\t\t\treportToObserver(() =>\n\t\t\t\t\t\t\t\tthis.observers.onDeliveryError(error, deadline),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (handlerFailed || !acked) {\n\t\t\t\t// One streak bump per failed cycle; run()'s backoff sleep\n\t\t\t\t// paces the retry (a bare drainOnce loop gets its pacing\n\t\t\t\t// from the tick cadence instead).\n\t\t\t\tthis.consecutiveFailures += 1;\n\t\t\t\treturn \"stopped\";\n\t\t\t}\n\t\t\tthis.consecutiveFailures = 0;\n\t\t\t// An abort mid-batch left deadlines unhandled; not a failure,\n\t\t\t// but not a drained backlog either.\n\t\t\tif (signal?.aborted) return \"stopped\";\n\t\t}\n\t\treturn \"stopped\";\n\t}\n\n\t/**\n\t * Reads and validates the poll clock before the store is consulted.\n\t * The caller's poll-error path reports any throw and applies backoff.\n\t */\n\tprivate now(): Date {\n\t\tconst value = this.clock();\n\t\tif (!(value instanceof Date) || Number.isNaN(value.getTime())) {\n\t\t\tthrow new TypeError(\"DeadlineProcessor: clock must return a valid Date\");\n\t\t}\n\t\treturn value;\n\t}\n}\n","import { err, ok, type Result } from \"@shirudo/result\";\nimport { DomainError } from \"../errors/kit-errors\";\n\n/** A concrete consumer-defined DomainError subclass accepted at a boundary. */\nexport type DomainErrorClass<E extends DomainError = DomainError> = new (\n\t...args: never[]\n) => E;\n\ntype ListedDomainError<TClasses extends readonly DomainErrorClass[]> =\n\tInstanceType<TClasses[number]>;\n\n/**\n * Runs application-boundary work and turns only explicitly listed domain\n * rejections into a typed Result error. Every unlisted DomainError and every\n * non-domain failure is rethrown unchanged. The class list is copied and\n * validated before work starts.\n *\n * @throws TypeError when expectedErrors is empty or contains a non-DomainError\n * class\n * @throws The exact operation failure when it is not an instance of a listed\n * class\n */\nexport async function domainErrorToResult<\n\tT,\n\tconst TClasses extends readonly [DomainErrorClass, ...DomainErrorClass[]],\n>(\n\toperation: () => T | PromiseLike<T>,\n\texpectedErrors: TClasses,\n): Promise<Result<T, ListedDomainError<TClasses>>> {\n\tconst stableExpectedErrors = [...expectedErrors];\n\tassertExpectedErrorClasses(stableExpectedErrors);\n\n\ttry {\n\t\treturn ok(await operation());\n\t} catch (error) {\n\t\tfor (const errorClass of stableExpectedErrors) {\n\t\t\tif (\n\t\t\t\t((typeof error === \"object\" && error !== null) ||\n\t\t\t\t\ttypeof error === \"function\") &&\n\t\t\t\tObject.prototype.isPrototypeOf.call(errorClass.prototype, error)\n\t\t\t) {\n\t\t\t\treturn err(error as ListedDomainError<TClasses>);\n\t\t\t}\n\t\t}\n\t\tthrow error;\n\t}\n}\n\nfunction assertExpectedErrorClasses(\n\terrorClasses: readonly unknown[],\n): asserts errorClasses is readonly [DomainErrorClass, ...DomainErrorClass[]] {\n\tif (errorClasses.length === 0) {\n\t\tthrow new TypeError(\n\t\t\t\"domainErrorToResult requires at least one expected DomainError class\",\n\t\t);\n\t}\n\tfor (const errorClass of errorClasses) {\n\t\tif (\n\t\t\ttypeof errorClass !== \"function\" ||\n\t\t\t!Object.prototype.isPrototypeOf.call(\n\t\t\t\tDomainError.prototype,\n\t\t\t\terrorClass.prototype,\n\t\t\t)\n\t\t) {\n\t\t\tthrow new TypeError(\n\t\t\t\t\"domainErrorToResult expected every entry to be a concrete DomainError subclass\",\n\t\t\t);\n\t\t}\n\t}\n}\n","import {\n\tIdempotencyClaimLostError,\n\tIdempotencyCompletionWithoutClaimError,\n\tIdempotencyInFlightError,\n\tIdempotencyKeyReuseError,\n\tInMemoryCapacityExceededError,\n} from \"../../../errors/kit-errors\";\nimport { assertPositiveSafeInteger } from \"../../../internal/validate\";\nimport type {\n\tIdempotencyClaim,\n\tIdempotencyClaimHandle,\n\tIdempotencyLease,\n\tIdempotencyReconciliation,\n\tIdempotencyReconciliationDecision,\n\tIdempotencyStore,\n} from \"../idempotency\";\n\ninterface PendingEntry {\n\treadonly fingerprint: string;\n\treadonly status: \"pending\";\n\treadonly token: string;\n\treadonly expiresAtMs: number;\n}\n\ninterface StagedEntry {\n\treadonly fingerprint: string;\n\treadonly status: \"staged\";\n\treadonly token: string;\n\treadonly expiresAtMs: number;\n\treadonly outcome: unknown;\n}\n\ninterface ConfirmedEntry {\n\treadonly fingerprint: string;\n\treadonly status: \"confirmed\";\n\treadonly token: string;\n\treadonly outcome: unknown;\n}\n\ntype IdempotencyEntry = PendingEntry | StagedEntry | ConfirmedEntry;\n\nexport interface InMemoryIdempotencyStoreOptions {\n\t/** Store-local clock. Durable adapters should prefer server/database time. */\n\treadonly clock?: () => Date;\n\t/** Token component source; an internal generation keeps ownership unique. */\n\treadonly claimTokenFactory?: () => string;\n\t/** Lease lifetime for pending and staged records. Default: 30 seconds. */\n\treadonly leaseDurationMs?: number;\n\t/** Heartbeat delay advertised to the wrapper. Default: half the lease. */\n\treadonly renewAfterMs?: number;\n\t/** Maximum number of pending, staged, and confirmed records. */\n\treadonly maxEntries?: number;\n}\n\nconst DEFAULT_LEASE_DURATION_MS = 30_000;\n\nfunction positiveSafeInteger(value: number): boolean {\n\treturn Number.isSafeInteger(value) && value > 0;\n}\n\n/**\n * In-memory reference implementation of {@link IdempotencyStore} for\n * finite-lifetime tests and demos. Without `maxEntries`, every confirmed\n * receipt remains reachable for the lifetime of the instance. A long-lived\n * process must configure the limit or use a durable adapter; exhaustion\n * rejects new keys before mutation and never forgets an idempotency decision.\n *\n * It is deliberately not transaction-aware. Claims and staged outcomes carry\n * bounded leases, while every mutation compares the store-minted token. An\n * expired pending claim may be replaced; an expired staged outcome cannot be\n * guessed away and instead returns `reconciliation-required`. Only an\n * authoritative `committed` / `not-committed` decision can settle it.\n */\nexport class InMemoryIdempotencyStore<TCtx = unknown>\n\timplements IdempotencyStore<TCtx>\n{\n\tprivate readonly entries = new Map<string, IdempotencyEntry>();\n\tprivate readonly clock: () => Date;\n\tprivate readonly claimTokenFactory: () => string;\n\tprivate readonly leaseDurationMs: number;\n\tprivate readonly renewAfterMs: number;\n\tprivate readonly maxEntries: number | undefined;\n\tprivate tokenGeneration = 0;\n\n\tconstructor(options: InMemoryIdempotencyStoreOptions = {}) {\n\t\tthis.clock = options.clock ?? (() => new Date());\n\t\tthis.claimTokenFactory =\n\t\t\toptions.claimTokenFactory ?? (() => globalThis.crypto.randomUUID());\n\t\tthis.leaseDurationMs = options.leaseDurationMs ?? DEFAULT_LEASE_DURATION_MS;\n\t\tthis.renewAfterMs =\n\t\t\toptions.renewAfterMs ?? Math.floor(this.leaseDurationMs / 2);\n\t\tif (options.maxEntries !== undefined) {\n\t\t\tassertPositiveSafeInteger(\n\t\t\t\t\"InMemoryIdempotencyStore\",\n\t\t\t\t\"maxEntries\",\n\t\t\t\toptions.maxEntries,\n\t\t\t);\n\t\t}\n\t\tthis.maxEntries = options.maxEntries;\n\t\tif (\n\t\t\t!positiveSafeInteger(this.leaseDurationMs) ||\n\t\t\tthis.leaseDurationMs > 2_147_483_647\n\t\t) {\n\t\t\tthrow new RangeError(\n\t\t\t\t\"leaseDurationMs must be a positive safe integer no greater than 2147483647\",\n\t\t\t);\n\t\t}\n\t\tif (\n\t\t\t!positiveSafeInteger(this.renewAfterMs) ||\n\t\t\tthis.renewAfterMs >= this.leaseDurationMs ||\n\t\t\tthis.renewAfterMs > 2_147_483_647\n\t\t) {\n\t\t\tthrow new RangeError(\n\t\t\t\t\"renewAfterMs must be a positive safe integer below leaseDurationMs and no greater than 2147483647\",\n\t\t\t);\n\t\t}\n\t}\n\n\tasync claim(\n\t\t_ctx: TCtx,\n\t\tkey: string,\n\t\tfingerprint: string,\n\t): Promise<IdempotencyClaim> {\n\t\tconst now = this.nowMs();\n\t\tconst existing = this.entries.get(key);\n\t\tif (existing === undefined) {\n\t\t\tif (\n\t\t\t\tthis.maxEntries !== undefined &&\n\t\t\t\tthis.entries.size >= this.maxEntries\n\t\t\t) {\n\t\t\t\tthrow new InMemoryCapacityExceededError({\n\t\t\t\t\tstore: \"InMemoryIdempotencyStore\",\n\t\t\t\t\tresource: \"entries\",\n\t\t\t\t\tlimit: this.maxEntries,\n\t\t\t\t\tcurrent: this.entries.size,\n\t\t\t\t\tattempted: 1,\n\t\t\t\t});\n\t\t\t}\n\t\t\treturn this.createPending(key, fingerprint, now);\n\t\t}\n\t\tif (existing.fingerprint !== fingerprint) {\n\t\t\tthrow new IdempotencyKeyReuseError({\n\t\t\t\tkey,\n\t\t\t\tstoredFingerprint: existing.fingerprint,\n\t\t\t\treceivedFingerprint: fingerprint,\n\t\t\t});\n\t\t}\n\t\tif (existing.status === \"confirmed\") {\n\t\t\treturn {\n\t\t\t\tstatus: \"completed\",\n\t\t\t\toutcome: structuredClone(existing.outcome),\n\t\t\t};\n\t\t}\n\t\tif (now < existing.expiresAtMs) {\n\t\t\tthrow new IdempotencyInFlightError({ key });\n\t\t}\n\t\tif (existing.status === \"staged\") {\n\t\t\treturn {\n\t\t\t\tstatus: \"reconciliation-required\",\n\t\t\t\treconciliation: Object.freeze({\n\t\t\t\t\tkey,\n\t\t\t\t\tfingerprint,\n\t\t\t\t\ttoken: existing.token,\n\t\t\t\t\texpiredAt: new Date(existing.expiresAtMs).toISOString(),\n\t\t\t\t}),\n\t\t\t};\n\t\t}\n\t\treturn this.createPending(key, fingerprint, now);\n\t}\n\n\tasync complete(\n\t\t_ctx: TCtx,\n\t\tclaim: IdempotencyClaimHandle,\n\t\toutcome: unknown,\n\t): Promise<void> {\n\t\tconst now = this.nowMs();\n\t\tconst existing = this.entries.get(claim.key);\n\t\tif (existing === undefined) {\n\t\t\tthrow new IdempotencyCompletionWithoutClaimError(claim.key);\n\t\t}\n\t\tif (\n\t\t\texisting.status !== \"pending\" ||\n\t\t\texisting.token !== claim.token ||\n\t\t\tnow >= existing.expiresAtMs\n\t\t) {\n\t\t\tthrow this.claimLost(claim);\n\t\t}\n\t\tconst expiresAtMs = now + this.leaseDurationMs;\n\t\tthis.lease(expiresAtMs);\n\t\tthis.entries.set(claim.key, {\n\t\t\tfingerprint: existing.fingerprint,\n\t\t\tstatus: \"staged\",\n\t\t\ttoken: existing.token,\n\t\t\texpiresAtMs,\n\t\t\toutcome: structuredClone(outcome),\n\t\t});\n\t}\n\n\tasync renew(\n\t\tclaim: IdempotencyClaimHandle,\n\t): Promise<IdempotencyLease | undefined> {\n\t\tconst now = this.nowMs();\n\t\tconst existing = this.entries.get(claim.key);\n\t\tif (\n\t\t\texisting === undefined ||\n\t\t\texisting.status === \"confirmed\" ||\n\t\t\texisting.token !== claim.token ||\n\t\t\tnow >= existing.expiresAtMs\n\t\t) {\n\t\t\tthrow this.claimLost(claim);\n\t\t}\n\t\tconst expiresAtMs = now + this.leaseDurationMs;\n\t\tconst lease = this.lease(expiresAtMs);\n\t\tthis.entries.set(claim.key, { ...existing, expiresAtMs });\n\t\treturn lease;\n\t}\n\n\tasync confirm(claim: IdempotencyClaimHandle): Promise<void> {\n\t\tconst existing = this.entries.get(claim.key);\n\t\tif (existing?.status === \"staged\" && existing.token === claim.token) {\n\t\t\tthis.entries.set(claim.key, {\n\t\t\t\tfingerprint: existing.fingerprint,\n\t\t\t\tstatus: \"confirmed\",\n\t\t\t\ttoken: existing.token,\n\t\t\t\toutcome: existing.outcome,\n\t\t\t});\n\t\t}\n\t}\n\n\tasync abandon(claim: IdempotencyClaimHandle): Promise<void> {\n\t\tconst existing = this.entries.get(claim.key);\n\t\tif (\n\t\t\texisting !== undefined &&\n\t\t\texisting.status !== \"confirmed\" &&\n\t\t\texisting.token === claim.token\n\t\t) {\n\t\t\tthis.entries.delete(claim.key);\n\t\t}\n\t}\n\n\tasync reconcile(\n\t\treconciliation: IdempotencyReconciliation,\n\t\tdecision: Exclude<IdempotencyReconciliationDecision, \"unknown\">,\n\t): Promise<void> {\n\t\tif (decision !== \"committed\" && decision !== \"not-committed\") {\n\t\t\tthrow new TypeError(\n\t\t\t\t\"reconcile decision must be committed or not-committed; uncertainty must leave the record untouched\",\n\t\t\t);\n\t\t}\n\t\tconst existing = this.entries.get(reconciliation.key);\n\t\tif (\n\t\t\texisting === undefined ||\n\t\t\texisting.status !== \"staged\" ||\n\t\t\texisting.token !== reconciliation.token ||\n\t\t\texisting.fingerprint !== reconciliation.fingerprint ||\n\t\t\tnew Date(existing.expiresAtMs).toISOString() !==\n\t\t\t\treconciliation.expiredAt ||\n\t\t\tthis.nowMs() < existing.expiresAtMs\n\t\t) {\n\t\t\tthrow new IdempotencyClaimLostError({\n\t\t\t\tkey: reconciliation.key,\n\t\t\t\ttoken: reconciliation.token,\n\t\t\t});\n\t\t}\n\t\tif (decision === \"committed\") {\n\t\t\tthis.entries.set(reconciliation.key, {\n\t\t\t\tfingerprint: existing.fingerprint,\n\t\t\t\tstatus: \"confirmed\",\n\t\t\t\ttoken: existing.token,\n\t\t\t\toutcome: existing.outcome,\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\t\tthis.entries.delete(reconciliation.key);\n\t}\n\n\t/** Test hook: number of stored records in any state. */\n\tget size(): number {\n\t\treturn this.entries.size;\n\t}\n\n\t/** Test hook: drops every record. */\n\tclear(): void {\n\t\tthis.entries.clear();\n\t}\n\n\tprivate createPending(\n\t\tkey: string,\n\t\tfingerprint: string,\n\t\tnow: number,\n\t): IdempotencyClaim {\n\t\tconst tokenPart = this.claimTokenFactory();\n\t\tif (typeof tokenPart !== \"string\" || tokenPart.length === 0) {\n\t\t\tthrow new TypeError(\"claimTokenFactory must return a non-empty string\");\n\t\t}\n\t\tthis.tokenGeneration += 1;\n\t\tif (!Number.isSafeInteger(this.tokenGeneration)) {\n\t\t\tthrow new RangeError(\"idempotency claim-token generation exhausted\");\n\t\t}\n\t\tconst token = `${this.tokenGeneration}:${tokenPart}`;\n\t\tconst expiresAtMs = now + this.leaseDurationMs;\n\t\tconst lease = this.lease(expiresAtMs);\n\t\tthis.entries.set(key, {\n\t\t\tfingerprint,\n\t\t\tstatus: \"pending\",\n\t\t\ttoken,\n\t\t\texpiresAtMs,\n\t\t});\n\t\treturn {\n\t\t\tstatus: \"claimed\",\n\t\t\tclaim: Object.freeze({ key, token, lease }),\n\t\t};\n\t}\n\n\tprivate lease(expiresAtMs: number): IdempotencyLease {\n\t\treturn Object.freeze({\n\t\t\texpiresAt: new Date(expiresAtMs).toISOString(),\n\t\t\trenewAfterMs: this.renewAfterMs,\n\t\t});\n\t}\n\n\tprivate nowMs(): number {\n\t\tconst now = this.clock();\n\t\tconst value = now instanceof Date ? now.getTime() : Number.NaN;\n\t\tif (!Number.isFinite(value)) {\n\t\t\tthrow new TypeError(\"idempotency clock must return a valid Date\");\n\t\t}\n\t\treturn value;\n\t}\n\n\tprivate claimLost(claim: IdempotencyClaimHandle): IdempotencyClaimLostError {\n\t\treturn new IdempotencyClaimLostError({\n\t\t\tkey: claim.key,\n\t\t\ttoken: claim.token,\n\t\t});\n\t}\n}\n","import type { AnyDomainEvent } from \"../../domain/event/domain-event\";\nimport {\n\tEventHarvestError,\n\tIdempotencyReconciliationRequiredError,\n} from \"../../errors/kit-errors\";\nimport { reportToObserver } from \"../../internal/observer\";\nimport type { TransactionScope } from \"../../persistence/repository/scope\";\nimport {\n\ttype CommitEnrollment,\n\ttype WithCommitDeps,\n\ttype WithCommitWorkResult,\n\twithCommit,\n} from \"../cqrs/handler\";\n\n/**\n * Result of `IdempotencyStore.claim()`: this execution owns the key and must\n * run the command (`claimed`), a previous execution completed and its outcome\n * is replayed (`completed`), or an expired staged outcome needs evidence from\n * the authoritative write model (`reconciliation-required`).\n *\n * The two FAILURE answers are thrown, not returned, following the kit's\n * error posture: a concurrent unfinished execution throws\n * `IdempotencyInFlightError` (retryable), and the same key arriving\n * with a different fingerprint throws `IdempotencyKeyReuseError`\n * (not retryable).\n */\nexport interface IdempotencyLease {\n\t/** Adapter-clock expiry as a canonical ISO-8601 timestamp. */\n\treadonly expiresAt: string;\n\t/** Delay after which the wrapper should renew this lease. */\n\treadonly renewAfterMs: number;\n}\n\n/** Store-minted ownership receipt for one successful claim. */\nexport interface IdempotencyClaimHandle {\n\treadonly key: string;\n\t/** Unique across ownership generations for this key; treat as opaque. */\n\treadonly token: string;\n\t/** Absent for a transactional store; required for a leased store. */\n\treadonly lease?: IdempotencyLease;\n}\n\n/** Receipt for an expired staged outcome that needs authoritative evidence. */\nexport interface IdempotencyReconciliation {\n\treadonly key: string;\n\treadonly fingerprint: string;\n\treadonly token: string;\n\treadonly expiredAt: string;\n}\n\nexport type IdempotencyReconciliationDecision =\n\t| \"committed\"\n\t| \"not-committed\"\n\t| \"unknown\";\n\nexport type IdempotencyClaim =\n\t| { readonly status: \"claimed\"; readonly claim: IdempotencyClaimHandle }\n\t| { readonly status: \"completed\"; readonly outcome: unknown }\n\t| {\n\t\t\treadonly status: \"reconciliation-required\";\n\t\t\treadonly reconciliation: IdempotencyReconciliation;\n\t };\n\n/**\n * Driven port for command idempotency and message-inbox deduplication.\n *\n * The store keeps one record per idempotency key: the key, a\n * fingerprint of the command that first claimed it, and, once the\n * execution completed, the stored outcome. The intended integration is\n * the SINGLE-TRANSACTION pattern via {@link withIdempotentCommit}: the\n * record is written in the same transaction as the aggregate and the\n * outbox, so a rollback releases the claim and there is no crash window\n * between claim and commit.\n *\n * Adapter contract (mirror of the repository/event-store delegation\n * model): the adapter maps its store's native signals onto the kit's\n * errors instead of leaking driver errors:\n *\n * - unique-constraint conflict from a CONCURRENT uncommitted claim ->\n * `IdempotencyInFlightError` (retryable; a retry replays the outcome\n * or claims fresh),\n * - existing COMPLETED record with the same fingerprint -> return\n * `{ status: \"completed\", outcome }`,\n * - existing record with a DIFFERENT fingerprint ->\n * `IdempotencyKeyReuseError`.\n *\n * **Transactional vs leased non-transactional stores.** A transactional\n * adapter (the record lives in the same database as the aggregate)\n * gets the commit boundary for free: `complete` is atomic with the\n * command's commit, a rollback releases everything, and `confirm` /\n * `abandon` / `renew` / `reconcile` are no-ops. This remains the recommended\n * production pattern and the only family that proves atomic command effect +\n * idempotency completion without reconciliation.\n *\n * A NON-transactional store (the in-memory reference, a separate durable\n * store) cannot see commits or rollbacks. Every fresh claim therefore returns\n * a store-minted token and bounded lease. The wrapper renews it while the\n * transaction runs; `complete`, `renew`, `confirm`, `abandon`, and `reconcile`\n * compare the token so a stale owner cannot mutate a successor claim. An\n * expired PENDING claim may be replaced. An expired STAGED outcome is never\n * replayed or released automatically: `claim` returns\n * `reconciliation-required`, and the application must consult the source of\n * truth. `unknown` keeps it blocked.\n *\n * A lease is coordination, not a security or exactly-once boundary. To return\n * `not-committed` safely, the source transaction must persist an idempotency\n * key or claim token (available as the callback's `execution` argument), or\n * offer equivalent durable fencing proving the old transaction cannot still\n * commit. Without that evidence, return `unknown`. A database row merely being\n * absent while an old transaction may still be in flight is not proof.\n * A takeover can overlap briefly with the stale worker, so `fn` must keep\n * irreversible external side effects out of the transaction. Persist an\n * outbox record and deliver after commit; token fencing can stop the stale\n * database commit, but it cannot undo an HTTP call already sent.\n *\n * The same store doubles as a message INBOX: use the message id as the\n * key and a constant fingerprint; a duplicate delivery replays the\n * stored (possibly `undefined`) outcome instead of re-running the\n * handler.\n *\n * The stored outcome must be PLAIN, serialisable data (the same\n * discipline as snapshots and event payloads): the record round-trips\n * through the adapter's storage, so class instances would silently lose\n * their prototype.\n *\n * @template TCtx - The transaction context the surrounding scope\n * exposes (Drizzle `tx`, Prisma `tx`, `undefined` for context-free\n * scopes). `claim` and `complete` run inside that transaction.\n */\nexport interface IdempotencyStore<TCtx = unknown> {\n\t/**\n\t * Claims the key for this execution, atomically with respect to\n\t * concurrent claimers (`INSERT ... ON CONFLICT` or equivalent).\n\t * Returns `claimed` when this execution owns the key, or\n\t * `completed` with the stored outcome when a previous execution\n\t * already finished under the same key and fingerprint. Throws\n\t * `IdempotencyInFlightError` / `IdempotencyKeyReuseError` for the\n\t * failure answers (see the port docs). A live staged outcome is in-flight;\n\t * after its lease expires it returns `reconciliation-required`, never a\n\t * replay or fresh claim.\n\t */\n\tclaim(ctx: TCtx, key: string, fingerprint: string): Promise<IdempotencyClaim>;\n\n\t/**\n\t * Stores the outcome for a key this execution claimed, in the same\n\t * transaction as the command's writes. On a transactional store the\n\t * commit makes it durable and replayable; on a non-transactional\n\t * store the outcome is only STAGED until {@link confirm} runs.\n\t * Throws `IdempotencyCompletionWithoutClaimError` when no claim exists, and\n\t * `IdempotencyClaimLostError` when the receipt is stale, already settled, or\n\t * expired. A stale completion must fail before the source transaction can\n\t * commit.\n\t */\n\tcomplete(\n\t\tctx: TCtx,\n\t\tclaim: IdempotencyClaimHandle,\n\t\toutcome: unknown,\n\t): Promise<void>;\n\n\t/**\n\t * Extends a non-transactional claim's lease and returns its new timing.\n\t * The update is compare-and-set on key + token. A transactional adapter\n\t * implements this as a no-op returning `undefined`; the wrapper never calls\n\t * it for a claim without a lease.\n\t */\n\trenew(claim: IdempotencyClaimHandle): Promise<IdempotencyLease | undefined>;\n\n\t/**\n\t * Finalizes a staged outcome AFTER the surrounding transaction\n\t * committed. Called by {@link withIdempotentCommit} post-commit on\n\t * every fresh execution. A transactional adapter implements this as\n\t * a no-op (the commit already finalized the record). Idempotent:\n\t * confirming an already-confirmed receipt is a no-op. A missing or stale\n\t * receipt is also a no-op and must never confirm its successor.\n\t */\n\tconfirm(claim: IdempotencyClaimHandle): Promise<void>;\n\n\t/**\n\t * Releases a claim whose attempt did not commit: a pending claim or\n\t * a staged, unconfirmed outcome. Called by\n\t * {@link withIdempotentCommit} once per failed attempt, best-effort.\n\t * A transactional adapter implements this as a no-op: the rollback\n\t * already removed the row, and the method must be SAFE to call when\n\t * the commit outcome is unknown; it never releases a confirmed\n\t * record. A stale receipt is a no-op and must never release its successor.\n\t */\n\tabandon(claim: IdempotencyClaimHandle): Promise<void>;\n\n\t/**\n\t * Resolves an EXPIRED staged outcome after the application consulted its\n\t * authoritative write model. `committed` makes the staged result replayable;\n\t * `not-committed` releases it for a fresh execution. `unknown` is\n\t * intentionally not accepted here: uncertainty must preserve the record.\n\t * The receipt is compare-and-set so a stale reconciler cannot settle a newer\n\t * owner. Transactional adapters implement this as a no-op because they never\n\t * return `reconciliation-required`.\n\t */\n\treconcile(\n\t\treconciliation: IdempotencyReconciliation,\n\t\tdecision: Exclude<IdempotencyReconciliationDecision, \"unknown\">,\n\t): Promise<void>;\n}\n\n/** Identifies one logical command execution for {@link withIdempotentCommit}. */\nexport interface IdempotentCommitRequest {\n\t/**\n\t * The idempotency key: client-supplied header, message id, or a key\n\t * derived from actor + intention. One key names one logical command.\n\t */\n\treadonly key: string;\n\t/**\n\t * Fingerprint of the command's content (a hash or canonical string\n\t * of the request payload). Detects the same key being reused for a\n\t * DIFFERENT command, which is rejected instead of replayed.\n\t */\n\treadonly fingerprint: string;\n}\n\n/**\n * Outcome of {@link withIdempotentCommit}: `replayed: false` carries the\n * fresh result of this execution; `replayed: true` carries the stored\n * outcome of the previous execution with the same key and fingerprint.\n * The replayed value is typed `R` on the strength of the fingerprint\n * match: the same command was executed, so the stored outcome has the\n * shape this command produces, provided the adapter round-trips plain\n * data faithfully.\n */\nexport interface IdempotentCommitResult<R> {\n\treadonly replayed: boolean;\n\treadonly result: R;\n}\n\n/** Claim identity visible to work that persists a source-of-truth marker. */\nexport interface IdempotentExecution extends IdempotentCommitRequest {\n\treadonly claimToken: string;\n}\n\nexport interface IdempotencyOperationErrorContext {\n\treadonly operation: \"abandon\" | \"confirm\" | \"renew\";\n\treadonly key: string;\n\treadonly token: string;\n}\n\nexport interface WithIdempotentCommitDeps<Evt extends AnyDomainEvent, TCtx>\n\textends WithCommitDeps<Evt, TCtx> {\n\tidempotency: IdempotencyStore<TCtx>;\n\t/**\n\t * Source-of-truth decision for an expired staged outcome. The callback must\n\t * return `committed` only when the command effect is durably visible, and\n\t * `not-committed` only when a durable marker proves the attempt cannot still\n\t * commit. `unknown` keeps the key blocked.\n\t */\n\treconcileIdempotency?: (\n\t\treconciliation: IdempotencyReconciliation,\n\t\tctx: TCtx,\n\t) => Promise<IdempotencyReconciliationDecision>;\n\t/**\n\t * Observer for best-effort post-commit confirm, rollback abandon, and a\n\t * secondary heartbeat failure masked by the primary work error.\n\t */\n\tonIdempotencyError?: (\n\t\terror: unknown,\n\t\tcontext: IdempotencyOperationErrorContext,\n\t) => void;\n}\n\ninterface LeaseHeartbeat {\n\tstop(): Promise<void>;\n\tfailure(): unknown | undefined;\n}\n\nfunction validRenewAfterMs(value: number): boolean {\n\treturn Number.isSafeInteger(value) && value > 0 && value <= 2_147_483_647;\n}\n\nfunction startLeaseHeartbeat<TCtx>(\n\tstore: IdempotencyStore<TCtx>,\n\tclaim: IdempotencyClaimHandle,\n): LeaseHeartbeat | undefined {\n\tif (!claim.lease) return undefined;\n\tlet stopped = false;\n\tlet timer: ReturnType<typeof setTimeout> | undefined;\n\tlet inFlight: Promise<void> = Promise.resolve();\n\tlet heartbeatFailure: unknown | undefined;\n\n\tconst schedule = (delayMs: number): void => {\n\t\tif (!validRenewAfterMs(delayMs)) {\n\t\t\theartbeatFailure = new TypeError(\n\t\t\t\t\"IdempotencyStore returned an invalid lease renewAfterMs; expected a positive safe integer no greater than 2147483647\",\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\t\ttimer = setTimeout(() => {\n\t\t\tinFlight = store\n\t\t\t\t.renew(claim)\n\t\t\t\t.then((lease) => {\n\t\t\t\t\tif (!lease) {\n\t\t\t\t\t\tthrow new TypeError(\n\t\t\t\t\t\t\t\"IdempotencyStore returned no lease while renewing a leased claim\",\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\tif (stopped) return;\n\t\t\t\t\tschedule(lease.renewAfterMs);\n\t\t\t\t})\n\t\t\t\t.catch((error: unknown) => {\n\t\t\t\t\theartbeatFailure = error;\n\t\t\t\t});\n\t\t}, delayMs);\n\t};\n\n\tschedule(claim.lease.renewAfterMs);\n\treturn {\n\t\tstop: async () => {\n\t\t\tstopped = true;\n\t\t\tif (timer !== undefined) clearTimeout(timer);\n\t\t\tawait inFlight;\n\t\t},\n\t\tfailure: () => heartbeatFailure,\n\t};\n}\n\nfunction scopeWorkEnrollment<Evt extends AnyDomainEvent>(\n\tparent: CommitEnrollment<Evt>,\n): { readonly enrollment: CommitEnrollment<Evt>; close(): void } {\n\tlet open = true;\n\tconst assertOpen = (): void => {\n\t\tif (!open) {\n\t\t\tthrow new EventHarvestError(\n\t\t\t\t\"withIdempotentCommit: commit enrollment was used after the \" +\n\t\t\t\t\t\"user work callback settled. Await every repository write before \" +\n\t\t\t\t\t\"returning from the callback.\",\n\t\t\t);\n\t\t}\n\t};\n\n\treturn {\n\t\tenrollment: Object.freeze({\n\t\t\tenrollSaved: (\n\t\t\t\taggregate: Parameters<CommitEnrollment<Evt>[\"enrollSaved\"]>[0],\n\t\t\t) => {\n\t\t\t\tassertOpen();\n\t\t\t\treturn parent.enrollSaved(aggregate);\n\t\t\t},\n\t\t\tenrollDeleted: (\n\t\t\t\taggregate: Parameters<CommitEnrollment<Evt>[\"enrollDeleted\"]>[0],\n\t\t\t) => {\n\t\t\t\tassertOpen();\n\t\t\t\treturn parent.enrollDeleted(aggregate);\n\t\t\t},\n\t\t}),\n\t\tclose: () => {\n\t\t\topen = false;\n\t\t},\n\t};\n}\n\n/**\n * {@link withCommit} with command idempotency: the duplicate-safe write\n * path for retryable deliveries (client retries, at-least-once\n * messages, scheduler re-runs).\n *\n * Order of operations:\n * 1. Inside the transaction, `store.claim(ctx, key, fingerprint)` runs\n * FIRST. A completed execution short-circuits without touching the domain.\n * An expired staged outcome invokes `reconcileIdempotency`; `committed`\n * replays it, `not-committed` releases and claims fresh, and `unknown` (or\n * no callback) throws `IdempotencyReconciliationRequiredError` without\n * changing the store.\n * 2. A fresh claim carries an opaque ownership token. For a leased store the\n * wrapper renews it at `renewAfterMs` until the transaction callback is\n * ready to commit. A renewal failure rejects before commit and releases\n * the claim. `fn(ctx, enrollment, execution)` receives the same token so a\n * source-side marker can make later reconciliation conclusive.\n * 3. `store.complete(ctx, claim, fn's result)` stages or completes the outcome\n * in the same transaction as aggregate writes and outbox. The enrollment\n * capability is sealed and its token array copied before `complete` can\n * yield, so leaked callback state cannot change the harvest receipt.\n * 4. After commit, `store.confirm(claim)` finalizes a leased store's staged\n * outcome; it is a no-op for transactional stores. A failure cannot reject\n * an already committed write, so it is sent to `onIdempotencyError` and the\n * record later enters reconciliation after lease expiry.\n * 5. Any pre-commit failure releases that exact token through\n * `store.abandon(claim)` before leaving the transactional region. A stale\n * abandon cannot release a successor. Secondary abandon/renew failures are\n * observable but never mask the primary error.\n *\n * Composes with `RetryingTransactionScope`: a retryable failure inside\n * one attempt releases that attempt's claim, and the retry either\n * executes fresh or, when a concurrent execution completed meanwhile,\n * replays its confirmed outcome. A concurrent duplicate while the first\n * execution is still running surfaces as `IdempotencyInFlightError`\n * (retryable); unwrapped, map it to a conflict/retry-later application\n * outcome.\n *\n * The stored outcome is `fn`'s `result` value; it must be plain, serialisable\n * data (see {@link IdempotencyStore}). Transactional storage remains the\n * production default. Leases make the non-transactional family recoverable;\n * they do not manufacture an atomic exactly-once boundary across two stores.\n */\nexport async function withIdempotentCommit<Evt extends AnyDomainEvent, R, TCtx>(\n\tdeps: WithIdempotentCommitDeps<Evt, TCtx>,\n\trequest: IdempotentCommitRequest,\n\tfn: (\n\t\tctx: TCtx,\n\t\tenrollment: CommitEnrollment<Evt>,\n\t\texecution: IdempotentExecution,\n\t) => Promise<WithCommitWorkResult<Evt, R>>,\n): Promise<IdempotentCommitResult<R>> {\n\tconst store = deps.idempotency;\n\tconst attempt: {\n\t\tclaim: IdempotencyClaimHandle | undefined;\n\t\theartbeat: LeaseHeartbeat | undefined;\n\t} = { claim: undefined, heartbeat: undefined };\n\n\t// Decorator around the caller's scope: releases the current\n\t// attempt's claim before an error leaves the transactional region.\n\t// This is the only place that sees EVERY failure point of one\n\t// attempt (the work, withCommit's harvest guards, the outbox write),\n\t// including the ones outside this module's own callback, and it runs\n\t// INSIDE a retrying scope's loop, so the next attempt starts clean.\n\tconst scope: TransactionScope<TCtx> = {\n\t\ttransactional: async (work, options) => {\n\t\t\ttry {\n\t\t\t\treturn await deps.scope.transactional(async (ctx) => {\n\t\t\t\t\tattempt.claim = undefined;\n\t\t\t\t\tattempt.heartbeat = undefined;\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst result = await work(ctx);\n\t\t\t\t\t\tconst currentHeartbeat = attempt.heartbeat as\n\t\t\t\t\t\t\t| LeaseHeartbeat\n\t\t\t\t\t\t\t| undefined;\n\t\t\t\t\t\tawait currentHeartbeat?.stop();\n\t\t\t\t\t\tconst heartbeatFailure = currentHeartbeat?.failure();\n\t\t\t\t\t\tif (heartbeatFailure !== undefined) throw heartbeatFailure;\n\t\t\t\t\t\treturn result;\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\tconst currentHeartbeat = attempt.heartbeat as\n\t\t\t\t\t\t\t| LeaseHeartbeat\n\t\t\t\t\t\t\t| undefined;\n\t\t\t\t\t\tawait currentHeartbeat?.stop();\n\t\t\t\t\t\tconst heartbeatFailure = currentHeartbeat?.failure();\n\t\t\t\t\t\tconst currentClaim = attempt.claim as\n\t\t\t\t\t\t\t| IdempotencyClaimHandle\n\t\t\t\t\t\t\t| undefined;\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\theartbeatFailure !== undefined &&\n\t\t\t\t\t\t\theartbeatFailure !== error &&\n\t\t\t\t\t\t\tcurrentClaim\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\treportToObserver(() =>\n\t\t\t\t\t\t\t\tdeps.onIdempotencyError?.(heartbeatFailure, {\n\t\t\t\t\t\t\t\t\toperation: \"renew\",\n\t\t\t\t\t\t\t\t\tkey: currentClaim.key,\n\t\t\t\t\t\t\t\t\ttoken: currentClaim.token,\n\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst abandoned = attempt.claim as\n\t\t\t\t\t\t\t| IdempotencyClaimHandle\n\t\t\t\t\t\t\t| undefined;\n\t\t\t\t\t\tif (abandoned) {\n\t\t\t\t\t\t\tattempt.claim = undefined;\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tawait store.abandon(abandoned);\n\t\t\t\t\t\t\t} catch (abandonError) {\n\t\t\t\t\t\t\t\t// Best-effort release: the abandon failure must not\n\t\t\t\t\t\t\t\t// mask the attempt's error. Transactional stores\n\t\t\t\t\t\t\t\t// release via rollback anyway; a leased store can\n\t\t\t\t\t\t\t\t// recover after expiry. The observer keeps the\n\t\t\t\t\t\t\t\t// secondary operational failure visible.\n\t\t\t\t\t\t\t\treportToObserver(() =>\n\t\t\t\t\t\t\t\t\tdeps.onIdempotencyError?.(abandonError, {\n\t\t\t\t\t\t\t\t\t\toperation: \"abandon\",\n\t\t\t\t\t\t\t\t\t\tkey: abandoned.key,\n\t\t\t\t\t\t\t\t\t\ttoken: abandoned.token,\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tthrow error;\n\t\t\t\t\t}\n\t\t\t\t}, options);\n\t\t\t} catch (error) {\n\t\t\t\t// COMMIT-time failure: the driver rejected AFTER the callback\n\t\t\t\t// resolved, so the catch above never saw it and the staged\n\t\t\t\t// claim would stay wedged until lease expiry (and demand\n\t\t\t\t// reconciliation after). The store contract declares abandon\n\t\t\t\t// safe when the commit outcome is unknown: a transactional\n\t\t\t\t// store's claim died with the rollback anyway, and a leased\n\t\t\t\t// store releases the lease while the durable outcome record\n\t\t\t\t// still decides replay on the next attempt.\n\t\t\t\tconst staged = attempt.claim as IdempotencyClaimHandle | undefined;\n\t\t\t\tif (staged) {\n\t\t\t\t\tattempt.claim = undefined;\n\t\t\t\t\tattempt.heartbeat = undefined;\n\t\t\t\t\ttry {\n\t\t\t\t\t\tawait store.abandon(staged);\n\t\t\t\t\t} catch (abandonError) {\n\t\t\t\t\t\treportToObserver(() =>\n\t\t\t\t\t\t\tdeps.onIdempotencyError?.(abandonError, {\n\t\t\t\t\t\t\t\toperation: \"abandon\",\n\t\t\t\t\t\t\t\tkey: staged.key,\n\t\t\t\t\t\t\t\ttoken: staged.token,\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t},\n\t};\n\n\tconst outcome = await withCommit<Evt, IdempotentCommitResult<R>, TCtx>(\n\t\t{ ...deps, scope },\n\t\tasync (ctx, enrollment) => {\n\t\t\tlet claim = await store.claim(ctx, request.key, request.fingerprint);\n\t\t\tif (claim.status === \"reconciliation-required\") {\n\t\t\t\tconst decision = deps.reconcileIdempotency\n\t\t\t\t\t? await deps.reconcileIdempotency(claim.reconciliation, ctx)\n\t\t\t\t\t: \"unknown\";\n\t\t\t\tif (decision === \"unknown\") {\n\t\t\t\t\tthrow new IdempotencyReconciliationRequiredError(\n\t\t\t\t\t\tclaim.reconciliation,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tif (decision !== \"committed\" && decision !== \"not-committed\") {\n\t\t\t\t\tthrow new TypeError(\n\t\t\t\t\t\t\"reconcileIdempotency must return committed, not-committed, or unknown\",\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tawait store.reconcile(claim.reconciliation, decision);\n\t\t\t\tclaim = await store.claim(ctx, request.key, request.fingerprint);\n\t\t\t\tif (claim.status === \"reconciliation-required\") {\n\t\t\t\t\tthrow new IdempotencyReconciliationRequiredError(\n\t\t\t\t\t\tclaim.reconciliation,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (claim.status === \"completed\") {\n\t\t\t\treturn {\n\t\t\t\t\tresult: { replayed: true, result: claim.outcome as R },\n\t\t\t\t\tcommits: [],\n\t\t\t\t};\n\t\t\t}\n\t\t\tattempt.claim = claim.claim;\n\t\t\tattempt.heartbeat = startLeaseHeartbeat(store, claim.claim);\n\t\t\tconst workEnrollment = scopeWorkEnrollment(enrollment);\n\t\t\tlet work: WithCommitWorkResult<Evt, R>;\n\t\t\ttry {\n\t\t\t\twork = await fn(ctx, workEnrollment.enrollment, {\n\t\t\t\t\tkey: request.key,\n\t\t\t\t\tfingerprint: request.fingerprint,\n\t\t\t\t\tclaimToken: claim.claim.token,\n\t\t\t\t});\n\t\t\t} finally {\n\t\t\t\tworkEnrollment.close();\n\t\t\t}\n\t\t\t// Snapshot the user-controlled receipt before complete() yields. A\n\t\t\t// leaked mutable array must not be able to add or remove aggregate\n\t\t\t// commits while the idempotency adapter is persisting the outcome.\n\t\t\tconst result = work.result;\n\t\t\tconst commits = Array.isArray(work.commits)\n\t\t\t\t? Object.freeze([...work.commits])\n\t\t\t\t: work.commits;\n\t\t\tawait store.complete(ctx, claim.claim, result);\n\t\t\treturn {\n\t\t\t\tresult: { replayed: false, result },\n\t\t\t\tcommits,\n\t\t\t};\n\t\t},\n\t);\n\n\tif (!outcome.replayed) {\n\t\t// Post-commit finalize: flips a leased store's staged\n\t\t// outcome to confirmed so only committed outcomes ever replay.\n\t\t// No-op for transactional stores. Runs after the commit, so a\n\t\t// throw here must not reject the committed write. The staged record\n\t\t// remains in-flight until lease expiry and then requires an\n\t\t// authoritative reconciliation decision.\n\t\tconst committedClaim = attempt.claim as IdempotencyClaimHandle | undefined;\n\t\tif (!committedClaim) {\n\t\t\tthrow new EventHarvestError(\n\t\t\t\t\"withIdempotentCommit: a fresh result committed without its claim receipt.\",\n\t\t\t);\n\t\t}\n\t\ttry {\n\t\t\tawait store.confirm(committedClaim);\n\t\t} catch (confirmError) {\n\t\t\t// Swallowed by the post-commit invariant: the write has committed.\n\t\t\t// Report it so the staged record enters the reconciliation path\n\t\t\t// visibly instead of becoming a silent permanent blockage.\n\t\t\treportToObserver(() =>\n\t\t\t\tdeps.onIdempotencyError?.(confirmError, {\n\t\t\t\t\toperation: \"confirm\",\n\t\t\t\t\tkey: committedClaim.key,\n\t\t\t\t\ttoken: committedClaim.token,\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\t}\n\treturn outcome;\n}\n","/**\n * Stable value address of one aggregate instance.\n *\n * Aggregate ids are type-scoped, so the raw id alone is not globally unique:\n * `SalesOrder 1` and `FulfillmentOrder 1` are different aggregates. Event\n * streams, snapshots, committed-event sources, and projection checkpoints\n * therefore carry both fields instead of defining boundary-specific variants.\n *\n * `aggregateType` is a stable technical stream category. Renaming it changes\n * persistence keys and orphans checkpoints unless the stored addresses are\n * migrated. When bounded contexts share infrastructure and reuse a domain\n * name, qualify it at the source (`sales.order`, `fulfillment.order`). The kit\n * deliberately adds no separate `boundedContext` field: qualification remains\n * the consumer's naming decision.\n */\nexport interface AggregateAddress<TAggregateId extends string = string> {\n\treadonly aggregateType: string;\n\treadonly aggregateId: TAggregateId;\n}\n\n/**\n * Collision-safe map-key encoding shared by the in-memory adapters.\n * Internal: durable adapters key on the two storage columns themselves.\n */\nexport function encodeAggregateAddress(address: AggregateAddress): string {\n\treturn JSON.stringify([address.aggregateType, address.aggregateId]);\n}\n","import type { AggregateAddress } from \"../../domain/aggregate/aggregate-address\";\nimport type { AnyDomainEvent } from \"../../domain/event/domain-event\";\nimport type { CommitPosition } from \"../../messaging/committed-event\";\n\n/**\n * A projection's gap-proof cursor into one aggregate's commit chain.\n * `aggregateVersion` plus `commitSequence` orders events; `commitSize`\n * proves the current commit is complete; `previousEventfulAggregateVersion`\n * links the next commit to the eventful predecessor. `withCommit` supplies\n * the current commit facts; the event source finalizes the predecessor on the\n * surrounding `CommittedDomainEvent`.\n *\n * A source MUST map exactly one immutable receipt to each qualified position:\n * one `eventId`, one `commitSize`, and one eventful predecessor. Custom\n * envelopes may translate another store's cursor into these fields, but\n * changing any part of an already observed receipt destroys the proof and is\n * a source-adapter bug.\n */\nexport type ProjectionPosition = CommitPosition;\n\n/**\n * Durable receipt for the last event one projection applied from an aggregate\n * stream. The position answers \"how far?\"; `lastAppliedEventId` identifies the\n * event at exactly that watermark. Together they let the projector distinguish\n * a true watermark redelivery from a source changing the event identity,\n * commit cardinality, or predecessor at the same position. Older positions\n * still rely on the source's immutable-receipt-per-position contract because a\n * checkpoint deliberately retains no full history.\n */\nexport interface ProjectionCheckpoint {\n\treadonly position: ProjectionPosition;\n\treadonly lastAppliedEventId: string;\n}\n\n/**\n * `true` when `candidate` comes strictly after `reference` in the\n * per-aggregate tuple order (higher version, or same version and higher\n * commit sequence). This comparison alone does not prove continuity;\n * the projector checks the boundary fields before advancing.\n */\nexport function isPositionAfter(\n\tcandidate: ProjectionPosition,\n\treference: ProjectionPosition,\n): boolean {\n\tif (candidate.aggregateVersion !== reference.aggregateVersion) {\n\t\treturn candidate.aggregateVersion > reference.aggregateVersion;\n\t}\n\treturn candidate.commitSequence > reference.commitSequence;\n}\n\n/**\n * Driven port for projection checkpoints: the per-`(projection,\n * aggregateType, aggregateId)` watermark receipt that makes a projection\n * idempotent and rebuild-safe. The {@link\n * ProjectionCheckpointStore.withCheckpointLocks} callback and every\n * {@link ProjectionCheckpointStore.load} / {@link\n * ProjectionCheckpointStore.save} it contains run inside the SAME transaction\n * as the read-model update (the `Projector` guarantees the pairing); the store\n * itself is a dumb last-write-wins record, monotonicity is the projector's job.\n *\n * Production adapters put the checkpoint table in the same database\n * as the read model, so update and checkpoint commit atomically: a\n * checkpoint without its update loses events, an update without its\n * checkpoint replays work. Verify an adapter with\n * `createProjectionCheckpointStoreContractTests` from\n * `@shirudo/ddd-kit/testing`.\n *\n * @template TCtx - The transaction context of the ambient\n * `TransactionScope` (a knex trx, a drizzle tx, a pg client)\n */\nexport interface ProjectionCheckpointStore<TCtx = unknown> {\n\t/**\n\t * Runs the complete checkpoint read / read-model update / checkpoint save\n\t * critical section with exclusive access to every supplied\n\t * `(projection, aggregateType, aggregateId)` key.\n\t *\n\t * Exclusivity MUST cover keys for which no checkpoint row exists yet. A\n\t * plain `SELECT ... FOR UPDATE` against the checkpoint table is therefore\n\t * insufficient at genesis: use transaction-scoped advisory/key locks, or\n\t * first materialize durable lock rows and lock those. Acquire multiple keys\n\t * in a deterministic order to avoid deadlocks, and keep database locks until\n\t * the surrounding transaction commits or rolls back. On entry, `work` must\n\t * observe checkpoint commits made by the preceding lock holder; choose the\n\t * transaction isolation level accordingly, or surface and retry a\n\t * serialization conflict instead of applying against a stale snapshot.\n\t *\n\t * Implementations may serialize more than the requested keys, but never\n\t * less. The callback is non-reentrant for an overlapping key set.\n\t */\n\twithCheckpointLocks<R>(\n\t\tctx: TCtx,\n\t\tprojection: string,\n\t\taddresses: ReadonlyArray<AggregateAddress>,\n\t\twork: () => Promise<R>,\n\t): Promise<R>;\n\n\t/**\n\t * The stored watermark receipt for `(projection, address)`, or `undefined`\n\t * when this projection has never applied an event of that\n\t * aggregate. Called inside the projector's transaction.\n\t */\n\tload(\n\t\tctx: TCtx,\n\t\tprojection: string,\n\t\taddress: AggregateAddress,\n\t): Promise<ProjectionCheckpoint | undefined>;\n\n\t/**\n\t * Persists the watermark receipt, overwriting a previous one (last write\n\t * wins; the projector only calls this with advancing checkpoints).\n\t * Called inside the projector's transaction, after the read-model\n\t * update it accounts for.\n\t */\n\tsave(\n\t\tctx: TCtx,\n\t\tprojection: string,\n\t\taddress: AggregateAddress,\n\t\tcheckpoint: ProjectionCheckpoint,\n\t): Promise<void>;\n\n\t/**\n\t * The wait-for-version building block: `true` when the stored\n\t * watermark for `(projection, address)` is at or past\n\t * `position`. Runs OUTSIDE any transaction (a query-side poll).\n\t *\n\t * Pass the position of the LAST event your commit emitted: all\n\t * events of one commit share the `aggregateVersion`, so comparing\n\t * on the version alone would report \"reached\" while later events\n\t * of the same commit are still unapplied.\n\t */\n\thasReached(\n\t\tprojection: string,\n\t\taddress: AggregateAddress,\n\t\tposition: ProjectionPosition,\n\t): Promise<boolean>;\n\n\t/**\n\t * Deletes every checkpoint of `projection` (other projections'\n\t * checkpoints are untouched): the rebuild entry point. Called\n\t * inside the rebuild transaction, together with the projection's\n\t * `truncate`, so a rebuild starts from a consistent zero.\n\t */\n\treset(ctx: TCtx, projection: string): Promise<void>;\n}\n\n/**\n * One projection: the consumer-owned mapping from events to ONE read\n * model (one table/view per projection; run several `Projector`s for\n * several read shapes). The kit owns the mechanics around it\n * (cursor skip, atomic checkpointing, rebuild); the handler owns the\n * read-model writes.\n *\n * The projector feed MUST contain every committed envelope for each aggregate\n * address it carries, including event types this read model does not use.\n * Handle those events as explicit no-ops in `apply`: the projector still\n * advances their cursor. Filtering a broker subscription by event type drops\n * positions from the source chain and turns the next commit into a real gap.\n * For correctness-critical read models, use `projectionFromHandlers` to make\n * every event in the declared union a compile-time handler-or-ignore decision;\n * implement this interface directly when intentionally partial routing is the\n * better fit.\n */\nexport interface Projection<Evt extends AnyDomainEvent, TCtx = unknown> {\n\t/**\n\t * Stable unique name; keys the checkpoints. Renaming it orphans the\n\t * old checkpoints and replays everything under the new name.\n\t */\n\tname: string;\n\n\t/**\n\t * Applies ONE event's read-model change inside the ambient\n\t * transaction. The projector's cursor already filtered duplicates\n\t * and stale events, so plain writes are safe; route on\n\t * `event.type` and handle creates, updates, deletes, corrections,\n\t * and tombstones explicitly (an upsert-only handler silently\n\t * retains stale rows). For a known event type this projection does not use,\n\t * return without writing; that explicit no-op still consumes and checkpoints\n\t * the envelope's source position.\n\t *\n\t * MUST be side-effect-free beyond the read model: no mails, no\n\t * external calls, no commands. A rebuild replays every event; side\n\t * effects would fire again.\n\t */\n\tapply(ctx: TCtx, event: Evt): Promise<void>;\n\n\t/**\n\t * Optional: clears the read model, called by `Projector.reset()`\n\t * in the same transaction as the checkpoint reset, so a rebuild\n\t * never observes a half-cleared state. Without it, truncating the\n\t * read model before a rebuild is the caller's responsibility.\n\t */\n\ttruncate?(ctx: TCtx): Promise<void>;\n}\n","import {\n\ttype AggregateAddress,\n\tencodeAggregateAddress,\n} from \"../../../domain/aggregate/aggregate-address\";\nimport { InMemoryCapacityExceededError } from \"../../../errors/kit-errors\";\nimport { assertPositiveSafeInteger } from \"../../../internal/validate\";\nimport {\n\tisPositionAfter,\n\ttype ProjectionCheckpoint,\n\ttype ProjectionCheckpointStore,\n\ttype ProjectionPosition,\n} from \"../ports\";\n\nexport interface InMemoryProjectionCheckpointStoreOptions {\n\t/** Maximum checkpoints across all projection names and aggregate addresses. */\n\treadonly maxCheckpoints?: number;\n}\n\n/**\n * In-memory reference implementation of\n * {@link ProjectionCheckpointStore}: defines the port's semantics and\n * serves tests and in-memory read models.\n *\n * Its checkpoint-key locks serialize competing projectors only inside one\n * process and only when they share this store instance. It is **not\n * transaction-aware** (the `ctx` parameter is ignored): a rolled-back\n * projector batch does not roll back its checkpoints. Use it for tests and\n * disposable in-memory read models; production atomicity is the durable\n * adapter's contract, proved with `createProjectionCheckpointStoreContractTests`\n * and its rollback capability.\n *\n * Without `maxCheckpoints`, checkpoint retention is unbounded and supported\n * only for finite-lifetime tests and demos. A configured limit rejects a new\n * address before mutation; existing watermarks remain updatable and are never\n * evicted because forgetting one would change projection correctness.\n *\n * Do not nest `withCheckpointLocks` calls whose key sets overlap. This\n * reference has no async-context tracking for reentrancy: a nested call waits\n * on the key its caller still holds and therefore neither enters nor fails\n * loudly.\n */\nexport class InMemoryProjectionCheckpointStore\n\timplements ProjectionCheckpointStore<unknown>\n{\n\t/** projection name -> JSON [aggregateType, aggregateId] -> receipt */\n\tprivate readonly checkpoints = new Map<\n\t\tstring,\n\t\tMap<string, ProjectionCheckpoint>\n\t>();\n\t/** Full checkpoint key -> tail of the process-local exclusive-access queue. */\n\tprivate readonly lockTails = new Map<string, Promise<void>>();\n\tprivate readonly maxCheckpoints: number | undefined;\n\tprivate checkpointCount = 0;\n\n\tconstructor(options: InMemoryProjectionCheckpointStoreOptions = {}) {\n\t\tif (options.maxCheckpoints !== undefined) {\n\t\t\tassertPositiveSafeInteger(\n\t\t\t\t\"InMemoryProjectionCheckpointStore\",\n\t\t\t\t\"maxCheckpoints\",\n\t\t\t\toptions.maxCheckpoints,\n\t\t\t);\n\t\t}\n\t\tthis.maxCheckpoints = options.maxCheckpoints;\n\t}\n\n\tasync withCheckpointLocks<R>(\n\t\t_ctx: unknown,\n\t\tprojection: string,\n\t\taddresses: ReadonlyArray<AggregateAddress>,\n\t\twork: () => Promise<R>,\n\t): Promise<R> {\n\t\tconst keys = [\n\t\t\t...new Set(\n\t\t\t\taddresses.map((address) =>\n\t\t\t\t\tJSON.stringify([\n\t\t\t\t\t\tprojection,\n\t\t\t\t\t\taddress.aggregateType,\n\t\t\t\t\t\taddress.aggregateId,\n\t\t\t\t\t]),\n\t\t\t\t),\n\t\t\t),\n\t\t].sort();\n\t\tconst releases: Array<() => void> = [];\n\n\t\tfor (const key of keys) {\n\t\t\tconst previous = this.lockTails.get(key) ?? Promise.resolve();\n\t\t\tlet releaseCurrent!: () => void;\n\t\t\tconst current = new Promise<void>((resolve) => {\n\t\t\t\treleaseCurrent = resolve;\n\t\t\t});\n\t\t\tconst tail = previous.then(() => current);\n\t\t\tthis.lockTails.set(key, tail);\n\t\t\tawait previous;\n\t\t\treleases.push(() => {\n\t\t\t\treleaseCurrent();\n\t\t\t\tif (this.lockTails.get(key) === tail) this.lockTails.delete(key);\n\t\t\t});\n\t\t}\n\n\t\ttry {\n\t\t\treturn await work();\n\t\t} finally {\n\t\t\tfor (let index = releases.length - 1; index >= 0; index -= 1) {\n\t\t\t\treleases[index]?.();\n\t\t\t}\n\t\t}\n\t}\n\n\tasync load(\n\t\t_ctx: unknown,\n\t\tprojection: string,\n\t\taddress: AggregateAddress,\n\t): Promise<ProjectionCheckpoint | undefined> {\n\t\tconst stored = this.checkpoints\n\t\t\t.get(projection)\n\t\t\t?.get(encodeAggregateAddress(address));\n\t\t// Detached copy: a caller mutating the loaded receipt must not\n\t\t// move the stored watermark.\n\t\treturn stored === undefined\n\t\t\t? undefined\n\t\t\t: { ...stored, position: { ...stored.position } };\n\t}\n\n\tasync save(\n\t\t_ctx: unknown,\n\t\tprojection: string,\n\t\taddress: AggregateAddress,\n\t\tcheckpoint: ProjectionCheckpoint,\n\t): Promise<void> {\n\t\tconst addressKey = encodeAggregateAddress(address);\n\t\tlet perAggregate = this.checkpoints.get(projection);\n\t\tconst isNewCheckpoint = perAggregate?.has(addressKey) !== true;\n\t\tif (\n\t\t\tisNewCheckpoint &&\n\t\t\tthis.maxCheckpoints !== undefined &&\n\t\t\tthis.checkpointCount >= this.maxCheckpoints\n\t\t) {\n\t\t\tthrow new InMemoryCapacityExceededError({\n\t\t\t\tstore: \"InMemoryProjectionCheckpointStore\",\n\t\t\t\tresource: \"checkpoints\",\n\t\t\t\tlimit: this.maxCheckpoints,\n\t\t\t\tcurrent: this.checkpointCount,\n\t\t\t\tattempted: 1,\n\t\t\t});\n\t\t}\n\t\tif (perAggregate === undefined) {\n\t\t\tperAggregate = new Map();\n\t\t\tthis.checkpoints.set(projection, perAggregate);\n\t\t}\n\t\tperAggregate.set(addressKey, {\n\t\t\t...checkpoint,\n\t\t\tposition: { ...checkpoint.position },\n\t\t});\n\t\tif (isNewCheckpoint) this.checkpointCount += 1;\n\t}\n\n\tasync hasReached(\n\t\tprojection: string,\n\t\taddress: AggregateAddress,\n\t\tposition: ProjectionPosition,\n\t): Promise<boolean> {\n\t\tconst stored = this.checkpoints\n\t\t\t.get(projection)\n\t\t\t?.get(encodeAggregateAddress(address));\n\t\tif (stored === undefined) return false;\n\t\treturn !isPositionAfter(position, stored.position);\n\t}\n\n\tasync reset(_ctx: unknown, projection: string): Promise<void> {\n\t\tthis.checkpointCount -= this.checkpoints.get(projection)?.size ?? 0;\n\t\tthis.checkpoints.delete(projection);\n\t}\n}\n","import type { AnyDomainEvent } from \"../../domain/event/domain-event\";\nimport { MissingHandlerError } from \"../../errors/kit-errors\";\nimport type { Projection } from \"./ports\";\n\n/**\n * Explicit no-op entry for {@link ProjectionHandlers}. The projector still\n * consumes and checkpoints the event; only the read-model write is skipped.\n */\nexport const ignoreProjectionEvent = Symbol(\"ignoreProjectionEvent\");\n\n/** One discriminator-narrowed projection handler. */\nexport type ProjectionEventHandler<Evt extends AnyDomainEvent, TCtx> = (\n\tctx: TCtx,\n\tevent: Evt,\n) => Promise<void>;\n\n/**\n * Exhaustive handler map for a declared event union. Every discriminator needs\n * either a narrowed handler or {@link ignoreProjectionEvent}; adding an event\n * to `Evt` therefore creates a compile error until the projection decides how\n * to handle it.\n */\nexport type ProjectionHandlers<Evt extends AnyDomainEvent, TCtx> = {\n\treadonly [K in Evt[\"type\"]]:\n\t\t| ProjectionEventHandler<Extract<Evt, { type: K }>, TCtx>\n\t\t| typeof ignoreProjectionEvent;\n};\n\ntype RuntimeProjectionHandlerEntry<TCtx, Evt extends AnyDomainEvent> =\n\t| ProjectionEventHandler<Evt, TCtx>\n\t| typeof ignoreProjectionEvent;\n\n/** Construction options for {@link projectionFromHandlers}. */\nexport interface ProjectionFromHandlersOptions<\n\tEvt extends AnyDomainEvent,\n\tTCtx,\n> {\n\t/** Stable projection name used by its checkpoints. */\n\treadonly name: string;\n\t/** One handler or explicit ignore token for every event in `Evt`. */\n\treadonly handlers: ProjectionHandlers<Evt, TCtx>;\n\t/** Optional read-model reset passed through to {@link Projection.truncate}. */\n\treadonly truncate?: (ctx: TCtx) => Promise<void>;\n}\n\n/**\n * Builds a {@link Projection} from an exhaustive, discriminator-narrowed\n * handler map. This is the correctness-oriented alternative to a free-form\n * `Projection.apply`: extending `Evt` forces every projection using that union\n * to add a handler or an explicit {@link ignoreProjectionEvent} entry.\n *\n * The compile-time proof is only as complete as the supplied `Evt` union.\n * At runtime, an undeclared type (including object-prototype names such as\n * `constructor`) throws {@link MissingHandlerError}; the projector rejects the\n * batch without advancing its checkpoint.\n *\n * @example\n * ```ts\n * const projection = projectionFromHandlers<OrderEvent, DbTx>({\n * name: \"order-list\",\n * handlers: {\n * OrderPlaced: async (tx, event) => {\n * await tx.orders.insert({ id: event.aggregateId });\n * },\n * OrderShipped: ignoreProjectionEvent,\n * },\n * });\n * ```\n */\nexport function projectionFromHandlers<Evt extends AnyDomainEvent, TCtx>(\n\toptions: ProjectionFromHandlersOptions<Evt, TCtx>,\n): Projection<Evt, TCtx> {\n\treturn {\n\t\tname: options.name,\n\t\ttruncate: options.truncate,\n\t\tapply: async (ctx, event) => {\n\t\t\tconst entry = Object.hasOwn(options.handlers, event.type)\n\t\t\t\t? (options.handlers[event.type as Evt[\"type\"]] as\n\t\t\t\t\t\t| RuntimeProjectionHandlerEntry<TCtx, Evt>\n\t\t\t\t\t\t| undefined)\n\t\t\t\t: undefined;\n\t\t\tif (entry === undefined) {\n\t\t\t\tthrow new MissingHandlerError(event.type);\n\t\t\t}\n\t\t\tif (entry === ignoreProjectionEvent) return;\n\t\t\tawait entry(ctx, event);\n\t\t},\n\t};\n}\n","import {\n\ttype AggregateAddress,\n\tencodeAggregateAddress,\n} from \"../../domain/aggregate/aggregate-address\";\nimport type { AnyDomainEvent } from \"../../domain/event/domain-event\";\nimport {\n\tForeignEventError,\n\tProjectionGapError,\n\tProjectionIdentityViolationError,\n\tProjectionOrderViolationError,\n\tProjectionReceiptViolationError,\n\tUnprojectableEventError,\n} from \"../../errors/kit-errors\";\nimport { abortReason } from \"../../internal/async/abort\";\nimport type { CommittedDomainEvent } from \"../../messaging/committed-event\";\nimport type { OutboxSink } from \"../../messaging/outbox/outbox-dispatcher\";\nimport type { TransactionScope } from \"../../persistence/repository/scope\";\nimport {\n\tisPositionAfter,\n\ttype Projection,\n\ttype ProjectionCheckpoint,\n\ttype ProjectionCheckpointStore,\n\ttype ProjectionPosition,\n} from \"./ports\";\n\n/** Construction options for {@link Projector}. */\nexport interface ProjectorOptions<Evt extends AnyDomainEvent, TCtx> {\n\t/**\n\t * The transaction boundary that makes read-model update and\n\t * checkpoint atomic. Wire the SAME scope (same database) the\n\t * read model and the checkpoint table live in.\n\t */\n\tscope: TransactionScope<TCtx>;\n\n\t/** The checkpoint store; see {@link ProjectionCheckpointStore}. */\n\tcheckpoints: ProjectionCheckpointStore<TCtx>;\n\n\t/** The consumer-owned event-to-read-model mapping. */\n\tprojection: Projection<Evt, TCtx>;\n}\n\n/** Controls one atomic projection batch. */\nexport interface ProjectOptions {\n\t/** Cancellation forwarded cooperatively to the projection transaction. */\n\treadonly signal?: AbortSignal;\n}\n\n/** Outcome of one {@link Projector.project} batch. */\nexport interface ProjectionBatchResult {\n\t/** Events applied and checkpointed in this batch. */\n\tapplied: number;\n\t/** Events skipped at positions already traversed under the source contract. */\n\tskipped: number;\n}\n\n/**\n * The projection runner: applies event batches to ONE projection with\n * the mechanics `read-model-design.md` demands, so the consumer's\n * {@link Projection.apply} can be a plain mapping.\n *\n * Contract:\n *\n * - **Update and checkpoint commit atomically.** One batch runs in one\n * `TransactionScope` transaction; each advanced aggregate's watermark\n * is saved once, inside that transaction, after its events applied. A\n * failure anywhere rolls back the WHOLE batch (updates and\n * checkpoints together), so redelivery replays it from the previous\n * watermark. It is never possible to checkpoint an unapplied event or\n * apply an uncheckpointed one, and a retrying scope re-runs the\n * callback from zero (counts included).\n * - **Gaps reject instead of becoming silent skips.** `commitSize`\n * proves every event in a commit was consumed, while\n * `previousEventfulAggregateVersion` links the next eventful commit to the\n * checkpoint. A missing sequence, incomplete commit, missing aggregate\n * commit, or non-genesis first event throws before its event is applied.\n * Because checkpoints advance only across a verified chain, a position\n * at or behind the watermark is already traversed and can be skipped under\n * the source's one-logical-event-per-position contract.\n * - **Feeds are complete per aggregate address.** Once a feed supplies one\n * address, it must supply every committed envelope in that address's cursor\n * chain. Do not event-type-filter a projector subscription. Irrelevant event\n * types are explicit no-ops in `Projection.apply`; invoking the handler and\n * checkpointing their positions preserves continuity.\n * - **The watermark carries an exact receipt.** A different `eventId` at the\n * exact stored watermark, or at one position inside the current batch,\n * throws {@link ProjectionIdentityViolationError} before `apply`. The same\n * ID with a changed commit size or predecessor throws\n * {@link ProjectionReceiptViolationError}. The checkpoint deliberately keeps\n * no full position history, so older skips continue to rely on the source\n * contract rather than claiming a receipt proof it cannot provide.\n * - **Batch inversions reject as transport violations.** Before applying, the\n * projector scans distinct positions that were still unseen at batch start.\n * A descending pair for one aggregate throws\n * {@link ProjectionOrderViolationError}; positions the stored checkpoint had\n * already covered and exact receipts repeated inside the batch remain valid\n * redeliveries.\n * - **Malformed envelopes reject loudly.** A missing/empty `eventId`, a\n * missing/invalid `position`, missing `source.aggregateId` /\n * `source.aggregateType`, or an optional event address contradicting its\n * authoritative envelope source fails the batch BEFORE anything is applied.\n * The domain event remains persistence-agnostic.\n * - **Competing instances serialize by checkpoint key.** The required\n * {@link ProjectionCheckpointStore.withCheckpointLocks} callback covers the\n * complete load / apply / save critical section for every addressed\n * aggregate. The adapter must lock a key even when its checkpoint row does\n * not exist yet; a plain row lock is insufficient at genesis. Without that\n * adapter guarantee, only a hard single-projector deployment is safe.\n *\n * Feeding: hand batches to {@link Projector.project} from any source\n * (an outbox poll, a queue consumer, a replay), or wire the projector\n * straight into an `OutboxDispatcher` via {@link Projector.toOutboxSink}.\n *\n * Rebuild: {@link Projector.reset} clears checkpoints and (when the\n * projection provides `truncate`) the read model in one transaction;\n * then replay the source through `project` again. Rebuild-safety is\n * exactly why {@link Projection.apply} must be side-effect-free.\n */\nexport class Projector<Evt extends AnyDomainEvent, TCtx = unknown> {\n\tprivate readonly scope: TransactionScope<TCtx>;\n\tprivate readonly checkpoints: ProjectionCheckpointStore<TCtx>;\n\tprivate readonly projection: Projection<Evt, TCtx>;\n\n\tconstructor(options: ProjectorOptions<Evt, TCtx>) {\n\t\tthis.scope = options.scope;\n\t\tthis.checkpoints = options.checkpoints;\n\t\tthis.projection = options.projection;\n\t}\n\n\t/**\n\t * Applies one batch: one transaction and one exclusive checkpoint-key\n\t * section, per envelope a cursor check and `apply`, then one checkpoint save\n\t * per advanced aggregate. Rejects\n\t * (after rollback) when a handler throws or an envelope carries no\n\t * valid cursor; the caller's at-least-once redelivery retries the batch.\n\t * The input must be a complete, ordered feed per aggregate address; an\n\t * event-type-filtered subscription cannot satisfy the cursor contract.\n\t * An already-aborted signal rejects before validation or transaction setup.\n\t * In-flight cancellation is forwarded to the transaction scope rather than\n\t * raced, so the adapter remains the authority on rollback and atomicity.\n\t */\n\tasync project(\n\t\tevents: ReadonlyArray<CommittedDomainEvent<Evt>>,\n\t\toptions: ProjectOptions = {},\n\t): Promise<ProjectionBatchResult> {\n\t\tif (options.signal?.aborted) {\n\t\t\tthrow abortReason(\n\t\t\t\toptions.signal,\n\t\t\t\t\"Projector.project aborted before opening a transaction\",\n\t\t\t);\n\t\t}\n\t\t// Validate cursors BEFORE opening the transaction: a malformed\n\t\t// batch must not burn a transaction or apply a prefix.\n\t\tconst cursored = events.map(({ event, source, position }) => {\n\t\t\tif (typeof event.eventId !== \"string\" || event.eventId.length === 0) {\n\t\t\t\tthrow new UnprojectableEventError(\n\t\t\t\t\tthis.projection.name,\n\t\t\t\t\ttypeof event.eventId === \"string\" ? event.eventId : \"<missing>\",\n\t\t\t\t\t\"carries no non-empty eventId. Projection checkpoints retain the \" +\n\t\t\t\t\t\t\"event identity at their watermark, so every projectable event must \" +\n\t\t\t\t\t\t\"have a stable identifier.\",\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (position === undefined) {\n\t\t\t\tthrow new UnprojectableEventError(\n\t\t\t\t\tthis.projection.name,\n\t\t\t\t\tevent.eventId,\n\t\t\t\t\t\"carries no complete projection cursor envelope. Events written \" +\n\t\t\t\t\t\t\"by withCommit are wrapped automatically; other sources must \" +\n\t\t\t\t\t\t\"provide source and position explicitly.\",\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (!isValidPosition(position)) {\n\t\t\t\tthrow new UnprojectableEventError(\n\t\t\t\t\tthis.projection.name,\n\t\t\t\t\tevent.eventId,\n\t\t\t\t\t\"carries an invalid projection cursor: aggregateVersion and \" +\n\t\t\t\t\t\t\"commitSequence must be non-negative integers, commitSize must \" +\n\t\t\t\t\t\t\"be a positive integer greater than commitSequence, and \" +\n\t\t\t\t\t\t\"previousEventfulAggregateVersion must be an earlier non-negative \" +\n\t\t\t\t\t\t\"version or null at genesis.\",\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (source === undefined) {\n\t\t\t\tthrow new UnprojectableEventError(\n\t\t\t\t\tthis.projection.name,\n\t\t\t\t\tevent.eventId,\n\t\t\t\t\t\"carries no aggregateId/aggregateType in its commit envelope source.\",\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst { aggregateId, aggregateType } = source;\n\t\t\tif (!aggregateId || !aggregateType) {\n\t\t\t\tthrow new UnprojectableEventError(\n\t\t\t\t\tthis.projection.name,\n\t\t\t\t\tevent.eventId,\n\t\t\t\t\t\"carries no aggregateId/aggregateType; the checkpoint watermark \" +\n\t\t\t\t\t\t\"is keyed per (aggregateType, aggregateId), because ids are \" +\n\t\t\t\t\t\t\"type-scoped. Events written by withCommit carry both stamps.\",\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst idContradictsSource =\n\t\t\t\tevent.aggregateId !== undefined && event.aggregateId !== aggregateId;\n\t\t\tconst typeContradictsSource =\n\t\t\t\tevent.aggregateType !== undefined &&\n\t\t\t\tevent.aggregateType !== aggregateType;\n\t\t\tif (idContradictsSource || typeContradictsSource) {\n\t\t\t\tthrow new ForeignEventError({\n\t\t\t\t\texpected: { aggregateType, aggregateId },\n\t\t\t\t\tactual: {\n\t\t\t\t\t\taggregateType: event.aggregateType,\n\t\t\t\t\t\taggregateId: event.aggregateId,\n\t\t\t\t\t},\n\t\t\t\t\teventType: event.type,\n\t\t\t\t});\n\t\t\t}\n\t\t\tconst address: AggregateAddress = { aggregateType, aggregateId };\n\t\t\treturn { event, position, address };\n\t\t});\n\t\tconst lockAddresses = [\n\t\t\t...new Map(\n\t\t\t\tcursored.map(\n\t\t\t\t\t({ address }) => [encodeAggregateAddress(address), address] as const,\n\t\t\t\t),\n\t\t\t).entries(),\n\t\t]\n\t\t\t.sort(([left], [right]) => (left < right ? -1 : left > right ? 1 : 0))\n\t\t\t.map(([, address]) => address);\n\n\t\t// Everything mutable lives INSIDE the transactional callback: a\n\t\t// retrying scope re-runs it from zero, so a rolled-back attempt\n\t\t// can never leak counts or watermarks into the next one.\n\t\tconst projectWithLocks = async (\n\t\t\tctx: TCtx,\n\t\t): Promise<ProjectionBatchResult> => {\n\t\t\tlet applied = 0;\n\t\t\tlet skipped = 0;\n\t\t\t// Load and validate every addressed checkpoint before any handler\n\t\t\t// runs. Legacy/partial rows therefore cannot turn a batch prefix\n\t\t\t// into visible work even under the in-memory passthrough scope.\n\t\t\tconst checkpointsAtBatchStart = new Map<\n\t\t\t\tstring,\n\t\t\t\tProjectionCheckpoint | undefined\n\t\t\t>();\n\t\t\tconst watermarks = new Map<string, ProjectionPosition | undefined>();\n\t\t\tfor (const { event, address } of cursored) {\n\t\t\t\tconst key = encodeAggregateAddress(address);\n\t\t\t\tif (watermarks.has(key)) continue;\n\t\t\t\tconst stored = await this.checkpoints.load(\n\t\t\t\t\tctx,\n\t\t\t\t\tthis.projection.name,\n\t\t\t\t\taddress,\n\t\t\t\t);\n\t\t\t\tif (stored !== undefined && !isValidCheckpoint(stored)) {\n\t\t\t\t\tthrow new UnprojectableEventError(\n\t\t\t\t\t\tthis.projection.name,\n\t\t\t\t\t\tevent.eventId,\n\t\t\t\t\t\t\"found a stored checkpoint with an invalid or legacy cursor. \" +\n\t\t\t\t\t\t\t\"Migrate the commitSize/previousEventfulAggregateVersion/\" +\n\t\t\t\t\t\t\t\"lastAppliedEventId columns or \" +\n\t\t\t\t\t\t\t\"reset and rebuild this projection.\",\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tcheckpointsAtBatchStart.set(key, stored);\n\t\t\t\twatermarks.set(key, stored?.position);\n\t\t\t}\n\n\t\t\t// A checkpoint remembers the complete receipt at exactly its watermark. A\n\t\t\t// different eventId or different commit-boundary metadata at that same\n\t\t\t// ordered position is therefore a provable source collision. Older\n\t\t\t// positions cannot be identity-checked without retaining an unbounded\n\t\t\t// per-position ledger and continue to rely on the source contract that one\n\t\t\t// position names one immutable logical event receipt.\n\t\t\tfor (const { event, position, address } of cursored) {\n\t\t\t\tconst stored = checkpointsAtBatchStart.get(\n\t\t\t\t\tencodeAggregateAddress(address),\n\t\t\t\t);\n\t\t\t\tif (\n\t\t\t\t\tstored !== undefined &&\n\t\t\t\t\tisSameOrderedPosition(position, stored.position)\n\t\t\t\t) {\n\t\t\t\t\tif (event.eventId !== stored.lastAppliedEventId) {\n\t\t\t\t\t\tthrow new ProjectionIdentityViolationError(\n\t\t\t\t\t\t\tthis.projection.name,\n\t\t\t\t\t\t\tevent.eventId,\n\t\t\t\t\t\t\tstored.lastAppliedEventId,\n\t\t\t\t\t\t\tformatPosition(position),\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\tif (!isSamePositionReceipt(position, stored.position)) {\n\t\t\t\t\t\tthrow new ProjectionReceiptViolationError(\n\t\t\t\t\t\t\tthis.projection.name,\n\t\t\t\t\t\t\tevent.eventId,\n\t\t\t\t\t\t\tformatReceipt(stored.position),\n\t\t\t\t\t\t\tformatReceipt(position),\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst batchReceiptsByPosition = new Map<\n\t\t\t\tstring,\n\t\t\t\t{ eventId: string; position: ProjectionPosition }\n\t\t\t>();\n\t\t\tfor (const { event, position, address } of cursored) {\n\t\t\t\tconst key = addressedPositionKey(address, position);\n\t\t\t\tconst recorded = batchReceiptsByPosition.get(key);\n\t\t\t\tif (recorded !== undefined && recorded.eventId !== event.eventId) {\n\t\t\t\t\tthrow new ProjectionIdentityViolationError(\n\t\t\t\t\t\tthis.projection.name,\n\t\t\t\t\t\tevent.eventId,\n\t\t\t\t\t\trecorded.eventId,\n\t\t\t\t\t\tformatPosition(position),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tif (\n\t\t\t\t\trecorded !== undefined &&\n\t\t\t\t\t!isSamePositionReceipt(position, recorded.position)\n\t\t\t\t) {\n\t\t\t\t\tthrow new ProjectionReceiptViolationError(\n\t\t\t\t\t\tthis.projection.name,\n\t\t\t\t\t\tevent.eventId,\n\t\t\t\t\t\tformatReceipt(recorded.position),\n\t\t\t\t\t\tformatReceipt(position),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tbatchReceiptsByPosition.set(key, {\n\t\t\t\t\teventId: event.eventId,\n\t\t\t\t\tposition,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\t// A descending pair among DISTINCT positions that were still unseen at\n\t\t\t// batch start is direct evidence of transport reordering. Ignore positions\n\t\t\t// the stored checkpoint had already covered and exact receipts already seen\n\t\t\t// in this batch: those are harmless redeliveries. The preceding collision\n\t\t\t// pass proved that a repeated ordered position has the same eventId and full\n\t\t\t// receipt, so this skip cannot hide conflicting source data.\n\t\t\tconst newestUnprocessed = new Map<string, ProjectionPosition>();\n\t\t\tconst positionsSeenInBatch = new Set<string>();\n\t\t\tfor (const { event, position, address } of cursored) {\n\t\t\t\tconst key = encodeAggregateAddress(address);\n\t\t\t\tconst stored = watermarks.get(key);\n\t\t\t\tif (stored !== undefined && !isPositionAfter(position, stored))\n\t\t\t\t\tcontinue;\n\t\t\t\tconst positionKey = addressedPositionKey(address, position);\n\t\t\t\tif (positionsSeenInBatch.has(positionKey)) continue;\n\t\t\t\tpositionsSeenInBatch.add(positionKey);\n\t\t\t\tconst newest = newestUnprocessed.get(key);\n\t\t\t\tif (newest !== undefined && isPositionAfter(newest, position)) {\n\t\t\t\t\tthrow new ProjectionOrderViolationError(\n\t\t\t\t\t\tthis.projection.name,\n\t\t\t\t\t\tevent.eventId,\n\t\t\t\t\t\tformatPosition(newest),\n\t\t\t\t\t\tformatPosition(position),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tif (newest === undefined || isPositionAfter(position, newest)) {\n\t\t\t\t\tnewestUnprocessed.set(key, position);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Prove the whole batch's cursor chain before mutating the read\n\t\t\t// model. The simulated watermark also provides intra-batch dedupe\n\t\t\t// without relying on checkpoint-store read-your-writes behavior.\n\t\t\tconst advanced = new Map<\n\t\t\t\tstring,\n\t\t\t\t{ address: AggregateAddress; checkpoint: ProjectionCheckpoint }\n\t\t\t>();\n\t\t\tconst toApply: Array<{ event: Evt }> = [];\n\t\t\tfor (const { event, position, address } of cursored) {\n\t\t\t\tconst key = encodeAggregateAddress(address);\n\t\t\t\tconst watermark = watermarks.get(key);\n\t\t\t\tif (watermark !== undefined && !isPositionAfter(position, watermark)) {\n\t\t\t\t\tskipped += 1;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (!isContiguousPosition(position, watermark)) {\n\t\t\t\t\tthrow new ProjectionGapError(\n\t\t\t\t\t\tthis.projection.name,\n\t\t\t\t\t\tevent.eventId,\n\t\t\t\t\t\tformatPosition(watermark),\n\t\t\t\t\t\tformatPosition(position),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\twatermarks.set(key, position);\n\t\t\t\tadvanced.set(key, {\n\t\t\t\t\taddress,\n\t\t\t\t\tcheckpoint: {\n\t\t\t\t\t\tposition,\n\t\t\t\t\t\tlastAppliedEventId: event.eventId,\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t\ttoApply.push({ event });\n\t\t\t\tapplied += 1;\n\t\t\t}\n\t\t\tfor (const { event } of toApply) {\n\t\t\t\tawait this.projection.apply(ctx, event);\n\t\t\t}\n\t\t\tfor (const { address, checkpoint } of advanced.values()) {\n\t\t\t\tawait this.checkpoints.save(\n\t\t\t\t\tctx,\n\t\t\t\t\tthis.projection.name,\n\t\t\t\t\taddress,\n\t\t\t\t\tcheckpoint,\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn { applied, skipped };\n\t\t};\n\t\treturn this.scope.transactional(\n\t\t\t(ctx) =>\n\t\t\t\tthis.checkpoints.withCheckpointLocks(\n\t\t\t\t\tctx,\n\t\t\t\t\tthis.projection.name,\n\t\t\t\t\tlockAddresses,\n\t\t\t\t\t() => projectWithLocks(ctx),\n\t\t\t\t),\n\t\t\t{ signal: options.signal },\n\t\t);\n\t}\n\n\t/**\n\t * The wait-for-version query: `true` when this projection has\n\t * processed the addressed aggregate at least up to `position`. Pass the\n\t * position of the last event the awaited commit emitted (see\n\t * {@link ProjectionCheckpointStore.hasReached} for why the full\n\t * cursor, not just the version).\n\t */\n\thasProcessed(\n\t\taddress: AggregateAddress,\n\t\tposition: ProjectionPosition,\n\t): Promise<boolean> {\n\t\treturn this.checkpoints.hasReached(this.projection.name, address, position);\n\t}\n\n\t/**\n\t * Rebuild entry point: one transaction that clears this\n\t * projection's checkpoints and, when the projection provides\n\t * `truncate`, the read model with them. Replay the source through\n\t * {@link Projector.project} afterwards. Stop all live consumers for this\n\t * projection before reset and keep them stopped through catch-up replay;\n\t * rebuild is not coordinated by the per-address delivery locks.\n\t */\n\tasync reset(): Promise<void> {\n\t\tawait this.scope.transactional(async (ctx) => {\n\t\t\tawait this.projection.truncate?.(ctx);\n\t\t\tawait this.checkpoints.reset(ctx, this.projection.name);\n\t\t});\n\t}\n\n\t/**\n\t * Adapts this projector as an `OutboxSink`, so an `OutboxDispatcher`\n\t * can feed it directly: each record becomes a single-event batch\n\t * (apply + checkpoint in its own transaction), a throw leaves the\n\t * record pending for the dispatcher's retry/dead-letter mechanics.\n\t * Duplicates the dispatcher redelivers are absorbed by the cursor.\n\t *\n\t * **Dead-lettering a projection event stalls that aggregate chain.**\n\t * A later event cannot advance past the missing commit/sequence: it\n\t * fails with `ProjectionGapError` until the dead letter is repaired\n\t * and replayed (or the projection is reset and rebuilt). No unseen\n\t * event is silently classified as a duplicate.\n\t */\n\ttoOutboxSink(): OutboxSink<Evt> {\n\t\treturn {\n\t\t\tpublish: async (record, context) => {\n\t\t\t\tawait this.project([record], { signal: context.signal });\n\t\t\t},\n\t\t};\n\t}\n}\n\ntype GapAwareProjectionPosition = ProjectionPosition & {\n\tcommitSize: number;\n\tpreviousEventfulAggregateVersion: number | null;\n};\n\nfunction isGapAwarePosition(\n\tposition: ProjectionPosition,\n): position is GapAwareProjectionPosition {\n\treturn (\n\t\tNumber.isInteger(position.commitSize) &&\n\t\tObject.hasOwn(position, \"previousEventfulAggregateVersion\")\n\t);\n}\n\nfunction isValidPosition(\n\tposition: ProjectionPosition,\n): position is GapAwareProjectionPosition {\n\tif (!isGapAwarePosition(position)) return false;\n\tconst previous = position.previousEventfulAggregateVersion;\n\treturn (\n\t\tNumber.isInteger(position.aggregateVersion) &&\n\t\tposition.aggregateVersion >= 0 &&\n\t\tNumber.isInteger(position.commitSequence) &&\n\t\tposition.commitSequence >= 0 &&\n\t\tposition.commitSize > position.commitSequence &&\n\t\t(previous === null ||\n\t\t\t(Number.isInteger(previous) &&\n\t\t\t\tprevious >= 0 &&\n\t\t\t\tprevious < position.aggregateVersion))\n\t);\n}\n\nfunction isValidCheckpoint(\n\tcheckpoint: unknown,\n): checkpoint is ProjectionCheckpoint {\n\tif (typeof checkpoint !== \"object\" || checkpoint === null) return false;\n\tconst candidate = checkpoint as Partial<ProjectionCheckpoint>;\n\treturn (\n\t\ttypeof candidate.lastAppliedEventId === \"string\" &&\n\t\tcandidate.lastAppliedEventId.length > 0 &&\n\t\tcandidate.position !== undefined &&\n\t\tisValidPosition(candidate.position)\n\t);\n}\n\nfunction isSameOrderedPosition(\n\tleft: ProjectionPosition,\n\tright: ProjectionPosition,\n): boolean {\n\treturn (\n\t\tleft.aggregateVersion === right.aggregateVersion &&\n\t\tleft.commitSequence === right.commitSequence\n\t);\n}\n\nfunction isSamePositionReceipt(\n\tleft: ProjectionPosition,\n\tright: ProjectionPosition,\n): boolean {\n\treturn (\n\t\tisSameOrderedPosition(left, right) &&\n\t\tleft.commitSize === right.commitSize &&\n\t\tleft.previousEventfulAggregateVersion ===\n\t\t\tright.previousEventfulAggregateVersion\n\t);\n}\n\nfunction addressedPositionKey(\n\taddress: AggregateAddress,\n\tposition: ProjectionPosition,\n): string {\n\treturn JSON.stringify([\n\t\taddress.aggregateType,\n\t\taddress.aggregateId,\n\t\tposition.aggregateVersion,\n\t\tposition.commitSequence,\n\t]);\n}\n\nfunction isContiguousPosition(\n\tcandidate: GapAwareProjectionPosition,\n\twatermark: ProjectionPosition | undefined,\n): boolean {\n\tif (\n\t\tcandidate.commitSize < 1 ||\n\t\tcandidate.commitSequence < 0 ||\n\t\tcandidate.commitSequence >= candidate.commitSize\n\t) {\n\t\treturn false;\n\t}\n\tif (watermark === undefined) {\n\t\treturn (\n\t\t\tcandidate.commitSequence === 0 &&\n\t\t\tcandidate.previousEventfulAggregateVersion === null\n\t\t);\n\t}\n\tif (!isGapAwarePosition(watermark)) return false;\n\tif (candidate.aggregateVersion === watermark.aggregateVersion) {\n\t\treturn (\n\t\t\tcandidate.previousEventfulAggregateVersion ===\n\t\t\t\twatermark.previousEventfulAggregateVersion &&\n\t\t\tcandidate.commitSize === watermark.commitSize &&\n\t\t\tcandidate.commitSequence === watermark.commitSequence + 1\n\t\t);\n\t}\n\treturn (\n\t\twatermark.commitSequence === watermark.commitSize - 1 &&\n\t\tcandidate.commitSequence === 0 &&\n\t\tcandidate.previousEventfulAggregateVersion === watermark.aggregateVersion\n\t);\n}\n\nfunction formatPosition(position: ProjectionPosition | undefined): string {\n\tif (position === undefined) return \"genesis\";\n\treturn `(${position.aggregateVersion}, ${position.commitSequence})`;\n}\n\nfunction formatReceipt(position: ProjectionPosition): string {\n\treturn (\n\t\t`(${position.aggregateVersion}, ${position.commitSequence}; ` +\n\t\t`commitSize=${position.commitSize}, ` +\n\t\t`previousEventfulAggregateVersion=${String(\n\t\t\tposition.previousEventfulAggregateVersion,\n\t\t)})`\n\t);\n}\n","import { InfrastructureError, KitWiringError } from \"../../errors/kit-errors\";\nimport type { AggregateWriteIntent } from \"./persistence-contract\";\n\n/**\n * Thrown when `UnitOfWork.run()` is called while the same instance is\n * already executing a unit of work: either a genuinely nested `run()`\n * inside the work callback, or two concurrent operations sharing one\n * instance.\n *\n * Both are contract violations, not recoverable infrastructure\n * failures, so this carries the `WIRING` category (same reasoning as\n * `MissingHandlerError`): a generic `catch (e instanceof\n * InfrastructureError)` handler must not mask it.\n *\n * A nested `run()` would NOT join the outer transaction; it would open\n * an independent one, silently breaking the all-or-nothing guarantee.\n * If two operations must commit together, they are ONE unit of work:\n * merge them into a single `run()` callback. For concurrent requests,\n * construct one `UnitOfWork` per operation (construction is trivially\n * cheap; the dependency object is the thing you share).\n */\nexport class NestedUnitOfWorkError extends KitWiringError<\"NESTED_UNIT_OF_WORK\"> {\n\tconstructor() {\n\t\tsuper(\n\t\t\t\"NESTED_UNIT_OF_WORK\",\n\t\t\t\"UnitOfWork.run() was called while this instance is already running. \" +\n\t\t\t\t\"A nested run() would open an independent transaction, not join the \" +\n\t\t\t\t\"outer one - merge the work into a single run() callback. For \" +\n\t\t\t\t\"concurrent operations, construct one UnitOfWork per operation.\",\n\t\t);\n\t}\n}\n\n/**\n * Thrown when the unit-of-work context is used after `run()` has\n * settled: reading `context.repositories`, calling an adapter-held\n * `tracking.trackLoaded`, or using a repository facade after the transaction\n * has committed or rolled back.\n *\n * Use-after-close is a programming bug (typically a leaked context\n * reference or a fire-and-forget promise outliving the callback), so\n * this carries the `WIRING` category and should crash loud.\n *\n * **Honest scope of this guard:** the kit can only invalidate what it\n * controls: context getters, repository-facade operations, and the tracking\n * capability. An adapter that captures its raw transaction handle can still call\n * it as far as the kit can see;\n * whether the driver rejects after close is ORM-specific. Adapter factories\n * must not let that handle escape into application code.\n */\nexport class TransactionClosedError extends KitWiringError<\"TRANSACTION_CLOSED\"> {\n\tconstructor(public readonly operation: string) {\n\t\tsuper(\n\t\t\t\"TRANSACTION_CLOSED\",\n\t\t\t`Unit of work is closed: ${operation} was called after the ` +\n\t\t\t\t\"transaction committed or rolled back. Do not use the context or \" +\n\t\t\t\t\"repository facade or tracking capability outside the run() callback.\",\n\t\t);\n\t}\n}\n\n/** A repository factory returned a value that cannot be wrapped as a facade. */\nexport class InvalidRepositoryAdapterError extends KitWiringError<\"INVALID_REPOSITORY_ADAPTER\"> {\n\tconstructor(\n\t\tpublic readonly repository: string,\n\t\tpublic readonly receivedType: string,\n\t) {\n\t\tsuper(\n\t\t\t\"INVALID_REPOSITORY_ADAPTER\",\n\t\t\t`Repository factory \"${repository}\" returned ${receivedType}; ` +\n\t\t\t\t\"it must return an adapter object.\",\n\t\t);\n\t}\n}\n\n/** A Unit of Work received repository wiring that bypassed {@link defineRepository}. */\nexport class InvalidRepositoryDefinitionError extends KitWiringError<\"INVALID_REPOSITORY_DEFINITION\"> {\n\tconstructor(public readonly repository: string) {\n\t\tsuper(\n\t\t\t\"INVALID_REPOSITORY_DEFINITION\",\n\t\t\t`Repository \"${repository}\" was not created by defineRepository. ` +\n\t\t\t\t\"Declare the application port explicitly and pass the helper-created \" +\n\t\t\t\t\"definition to UnitOfWork.\",\n\t\t);\n\t}\n}\n\n/** A repository's persistence-error policy threw or returned a non-kit error. */\nexport class RepositoryErrorMappingFailedError extends KitWiringError<\"REPOSITORY_ERROR_MAPPING_FAILED\"> {\n\treadonly aggregateId: string;\n\treadonly intent: AggregateWriteIntent;\n\treadonly mapperCause: unknown;\n\n\tconstructor(options: {\n\t\treadonly aggregateId: string;\n\t\treadonly intent: AggregateWriteIntent;\n\t\treadonly persistenceError: unknown;\n\t\treadonly mapperError: unknown;\n\t}) {\n\t\tsuper(\n\t\t\t\"REPOSITORY_ERROR_MAPPING_FAILED\",\n\t\t\t`The repository error mapper failed for ${options.intent} of aggregate ` +\n\t\t\t\t`${options.aggregateId}. The original persistence failure is preserved ` +\n\t\t\t\t\"as cause; the mapper failure is available as mapperCause.\",\n\t\t\toptions.persistenceError,\n\t\t);\n\t\tthis.aggregateId = options.aggregateId;\n\t\tthis.intent = options.intent;\n\t\tthis.mapperCause = options.mapperError;\n\t}\n}\n\n/** Why an aggregate lifecycle registration was rejected. */\nexport type AggregateTrackingFailure =\n\t| \"not_loaded\"\n\t| \"loaded_as_new\"\n\t| \"different_repository\"\n\t| \"conflicting_intent\"\n\t| \"mutated_after_registration\";\n\n/**\n * A deterministic violation of the Unit of Work's aggregate lifecycle.\n *\n * This is a wiring error rather than a domain or infrastructure failure: the\n * application registered persistence intent in an order the Unit of Work\n * cannot execute truthfully. Retrying the same callback cannot repair it.\n */\nexport class AggregateTrackingError extends KitWiringError<\"AGGREGATE_TRACKING\"> {\n\tconstructor(\n\t\tpublic readonly aggregateId: string,\n\t\tpublic readonly operation: AggregateWriteIntent | \"load\" | \"commit\",\n\t\tpublic readonly reason: AggregateTrackingFailure,\n\t\tpublic readonly registeredIntent?: AggregateWriteIntent,\n\t) {\n\t\tsuper(\n\t\t\t\"AGGREGATE_TRACKING\",\n\t\t\ttrackingFailureMessage(aggregateId, operation, reason, registeredIntent),\n\t\t);\n\t}\n}\n\nfunction trackingFailureMessage(\n\taggregateId: string,\n\toperation: AggregateWriteIntent | \"load\" | \"commit\",\n\treason: AggregateTrackingFailure,\n\tregisteredIntent: AggregateWriteIntent | undefined,\n): string {\n\tswitch (reason) {\n\t\tcase \"not_loaded\":\n\t\t\treturn (\n\t\t\t\t`Aggregate ${aggregateId} cannot be registered for ${operation}: ` +\n\t\t\t\t\"it was not loaded into this unit of work. Load it through the \" +\n\t\t\t\t\"repository before updating or removing it.\"\n\t\t\t);\n\t\tcase \"loaded_as_new\":\n\t\t\treturn (\n\t\t\t\t`Aggregate ${aggregateId} cannot be added as new because it was ` +\n\t\t\t\t\"loaded by this unit of work. Use update for a loaded aggregate.\"\n\t\t\t);\n\t\tcase \"different_repository\":\n\t\t\treturn (\n\t\t\t\t`Aggregate ${aggregateId} cannot be registered for ${operation} through ` +\n\t\t\t\t\"a different repository in the same unit of work. One aggregate instance \" +\n\t\t\t\t\"must remain owned by the repository definition that first tracked it.\"\n\t\t\t);\n\t\tcase \"conflicting_intent\":\n\t\t\treturn (\n\t\t\t\t`Aggregate ${aggregateId} is already registered for ` +\n\t\t\t\t`${registeredIntent ?? \"another write\"}; ${operation} would create ` +\n\t\t\t\t\"conflicting persistence intent in one unit of work. Decide the final \" +\n\t\t\t\t\"lifecycle outcome before registering it.\"\n\t\t\t);\n\t\tcase \"mutated_after_registration\":\n\t\t\treturn (\n\t\t\t\t`Aggregate ${aggregateId} changed after ${registeredIntent ?? \"write\"} ` +\n\t\t\t\t\"was registered. Make domain decisions first and call add, update, or \" +\n\t\t\t\t\"remove last so persisted state and recorded events cannot diverge.\"\n\t\t\t);\n\t}\n}\n\n/**\n * The unit of work failed AFTER the work callback completed\n * successfully, at the persistence boundary: the outbox write or the\n * transaction commit itself rejected. The kit cannot see inside\n * `TransactionScope.transactional`, so these are deliberately one error\n * class; the underlying failure is attached as `cause`.\n *\n * `InfrastructureError`: the business logic ran to completion; the\n * persistence boundary failed. The transaction rolled back (or never\n * committed), no aggregate was marked persisted, and pending events\n * survive on the aggregates; the operation left no partial state behind.\n * A `CommitError` is the **potentially transient** post-completion\n * failure (a commit-time serialization failure is the classic case), so\n * it is the one a retrying caller should consider re-running. The\n * deterministic post-completion failure, a harvest-guard violation (an\n * event missing `aggregateId` / `aggregateType`, or an eventful persisted\n * aggregate that did not advance its version), is a programming bug and surfaces as\n * {@link EventHarvestError} instead, which does NOT extend\n * `InfrastructureError`, so it stays out of retry paths by construction.\n */\nexport class CommitError extends InfrastructureError<\"COMMIT_FAILED\"> {\n\tconstructor(cause: unknown) {\n\t\tsuper({\n\t\t\tcode: \"COMMIT_FAILED\",\n\t\t\tmessage:\n\t\t\t\t\"Unit of work failed after the work callback completed: the outbox \" +\n\t\t\t\t\"write or the transaction commit rejected. The transaction did \" +\n\t\t\t\t\"not commit; this failure may be transient, inspect the cause \" +\n\t\t\t\t\"(e.g. someChainRetryable) before retrying.\",\n\t\t\tcause,\n\t\t});\n\t}\n}\n\n/**\n * The work callback threw AND the transaction scope rejected with a\n * DIFFERENT error that does not wrap the callback's error in its cause\n * chain - the strongest available signal that the rollback itself\n * failed. The callback's (primary) error is preserved as `cause`, so\n * cause-chain helpers (`someChainRetryable`, `findInCauseChain`) still\n * see a wrapped `ConcurrencyConflictError` & co.; the scope's error is\n * carried in {@link rollbackCause}.\n *\n * Scopes that rethrow the original error (Drizzle, Prisma do) never\n * produce this; scopes that WRAP the original are detected via the\n * cause chain and passed through unchanged instead.\n */\nexport class RollbackError extends InfrastructureError<\"ROLLBACK_FAILED\"> {\n\tconstructor(\n\t\tcause: unknown,\n\t\tpublic readonly rollbackCause: unknown,\n\t) {\n\t\tsuper({\n\t\t\tcode: \"ROLLBACK_FAILED\",\n\t\t\tmessage:\n\t\t\t\t\"The work callback failed and the transaction scope rejected with a \" +\n\t\t\t\t\"different error (possible rollback failure). The callback's error \" +\n\t\t\t\t\"is the cause; the scope's error is in rollbackCause.\",\n\t\t\tcause,\n\t\t});\n\t}\n}\n","import type {\n\tAnyDomainEvent,\n\tAnyUncommittedDomainEvent,\n\tDomainEventStamp,\n} from \"../event/domain-event\";\nimport { createGlobalCapabilityRegistry } from \"./internal/global-capability-registry\";\n\nexport type PendingEventStampFactory = (\n\tevent: AnyUncommittedDomainEvent,\n\tindex: number,\n) => DomainEventStamp;\n\nexport interface PendingEventRecordingCapability {\n\treadonly record: (\n\t\tcreateStamp: PendingEventStampFactory,\n\t) => ReadonlyArray<AnyDomainEvent>;\n}\n\n// The key version stamps the capability SHAPE, mirroring\n// pending-event-lifecycle.ts, and the shape includes the event type that\n// crosses record(). Bump it whenever the interface above or that event\n// shape changes: registrations made under another key stay invisible, so\n// an aggregate constructed by an incompatible package copy fails the\n// caller's UnmanagedInstanceError check instead of half-working.\nconst recordingCapabilityRegistryKey = Symbol.for(\n\t\"@shirudo/ddd-kit/pending-event-recording-registry/v2\",\n);\n\nconst { registry: capabilities, require } =\n\tcreateGlobalCapabilityRegistry<PendingEventRecordingCapability>(\n\t\trecordingCapabilityRegistryKey,\n\t);\n\n/** Resolves the recording capability or throws `UnmanagedInstanceError`. */\nexport function requirePendingEventRecordingCapability(\n\taggregate: object,\n\toperation: string,\n): PendingEventRecordingCapability {\n\treturn require(aggregate, operation, \"aggregate\");\n}\n\nexport function registerPendingEventRecordingCapability(\n\taggregate: object,\n\tcapability: PendingEventRecordingCapability,\n): void {\n\tcapabilities.set(aggregate, Object.freeze(capability));\n}\n\nexport function pendingEventRecordingCapabilityFor(\n\taggregate: object,\n): PendingEventRecordingCapability | undefined {\n\treturn capabilities.get(aggregate);\n}\n","import type { Aggregate } from \"../../domain/aggregate/aggregate\";\nimport { requirePendingEventRecordingCapability } from \"../../domain/aggregate/pending-event-recording\";\nimport type {\n\tAnyDomainEvent,\n\tCreateDomainEventStampOptions,\n\tDomainEventFactory,\n\tDomainEventStamp,\n\tUncommittedDomainEventOf,\n} from \"../../domain/event/domain-event\";\nimport type { Id } from \"../../domain/identity/id\";\n\n/** Minimal shell role accepted by {@link recordPendingEvents}. */\nexport type DomainEventStampFactory = Pick<DomainEventFactory, \"createStamp\">;\n\n/** Per-decision stamp provider for metadata that depends on the event. */\nexport type DomainEventStampProvider<TEvent extends AnyDomainEvent> = (\n\tevent: UncommittedDomainEventOf<TEvent>,\n\tindex: number,\n) => DomainEventStamp;\n\n/**\n * Stamp options that every decision of one recording shares: a recording time\n * and metadata such as the correlation id of the request. An `eventId` is per\n * fact, so the factory mints it for each decision.\n */\nexport type SharedDomainEventStampOptions = Omit<\n\tCreateDomainEventStampOptions,\n\t\"eventId\"\n>;\n\n/**\n * Records every still-unstamped event accepted by an aggregate.\n *\n * The function is a command that also returns the recorded batch, a\n * deliberate exception to command-query separation: the caller hands the\n * batch on to persistence and needs no second read of `pendingEvents`.\n *\n * Recording is atomic with respect to the aggregate's pending list: if stamp\n * creation or validation fails, every decision remains unrecorded. A\n * successful second call returns the same event objects and does not read the\n * factory again, which keeps event identity stable across transaction retries.\n *\n * Pass a `DomainEventFactory` (only its `createStamp` role is required) for one\n * uniform recording policy. Add `stampOptions` for metadata that every\n * decision of the batch shares, such as the correlation id of the request.\n * Pass a callback instead when metadata depends on the concrete decision.\n */\nexport function recordPendingEvents<\n\tTId extends Id<string>,\n\tTEvent extends AnyDomainEvent,\n>(\n\taggregate: Aggregate<TId, TEvent>,\n\tfactory: DomainEventStampFactory,\n\tstampOptions?: SharedDomainEventStampOptions,\n): ReadonlyArray<TEvent>;\nexport function recordPendingEvents<\n\tTId extends Id<string>,\n\tTEvent extends AnyDomainEvent,\n>(\n\taggregate: Aggregate<TId, TEvent>,\n\tcreateStamp: DomainEventStampProvider<TEvent>,\n): ReadonlyArray<TEvent>;\nexport function recordPendingEvents<\n\tTId extends Id<string>,\n\tTEvent extends AnyDomainEvent,\n>(\n\taggregate: Aggregate<TId, TEvent>,\n\tsource: DomainEventStampFactory | DomainEventStampProvider<TEvent>,\n\tstampOptions?: SharedDomainEventStampOptions,\n): ReadonlyArray<TEvent> {\n\tconst capability = requirePendingEventRecordingCapability(\n\t\taggregate,\n\t\t\"recordPendingEvents\",\n\t);\n\t// Only the two shared fields reach the factory. The type omits eventId,\n\t// but a wider options object passes the structural check with one at\n\t// runtime, and one fixed id on every decision would collide.\n\tconst shared = {\n\t\toccurredAt: stampOptions?.occurredAt,\n\t\tmetadata: stampOptions?.metadata,\n\t};\n\tconst createStamp: DomainEventStampProvider<TEvent> =\n\t\ttypeof source === \"function\" ? source : () => source.createStamp(shared);\n\treturn capability.record((event, index) =>\n\t\tcreateStamp(event as UncommittedDomainEventOf<TEvent>, index),\n\t) as ReadonlyArray<TEvent>;\n}\n","import type { Aggregate } from \"../../domain/aggregate/aggregate\";\nimport type { AnyDomainEvent } from \"../../domain/event/domain-event\";\nimport type { Id } from \"../../domain/identity/id\";\nimport { InvalidRepositoryAdapterError } from \"./errors\";\nimport type { RuntimePersistenceDefinition } from \"./persistence-contract\";\n\n/**\n * The part of the running unit of work that a facade needs: the open\n * check, and the three lifecycle writes it installs on the facade. The\n * facade never reaches further into the session, and stating that here\n * keeps the dependency pointing one way.\n */\ninterface RepositoryFacadeSession<Evt extends AnyDomainEvent> {\n\tassertOpen(operation: string): void;\n\tadd(\n\t\taggregate: Aggregate<Id<string>, Evt>,\n\t\tdefinition: RuntimePersistenceDefinition<Evt>,\n\t): void;\n\tupdate(\n\t\taggregate: Aggregate<Id<string>, Evt>,\n\t\tdefinition: RuntimePersistenceDefinition<Evt>,\n\t): void;\n\tremove(\n\t\taggregate: Aggregate<Id<string>, Evt>,\n\t\tdefinition: RuntimePersistenceDefinition<Evt>,\n\t): void;\n}\n\n/**\n * Builds the application-facing repository facade. Standard lifecycle writes\n * are always supplied by the Unit of Work; similarly named adapter methods are\n * never invoked. Other methods are bound to the adapter so classes with private\n * fields keep their normal receiver.\n */\nexport function bindRepositoryWrites<TRepository, Evt extends AnyDomainEvent>(\n\tadapter: TRepository,\n\tsession: RepositoryFacadeSession<Evt>,\n\tdefinition: RuntimePersistenceDefinition<Evt>,\n\trepository: string,\n): TRepository {\n\tif (adapter === null || typeof adapter !== \"object\") {\n\t\tthrow new InvalidRepositoryAdapterError(\n\t\t\trepository,\n\t\t\tadapter === null ? \"null\" : typeof adapter,\n\t\t);\n\t}\n\n\tconst state = createRepositoryFacadeState(\n\t\tadapter as object,\n\t\tsession,\n\t\tdefinition,\n\t);\n\tinstallRepositoryLifecycleOperations(state);\n\tforwardAdapterOwnProperties(state);\n\treturn new Proxy(\n\t\tstate.target,\n\t\tcreateRepositoryFacadeHandler(state),\n\t) as TRepository;\n}\n\nconst REPOSITORY_LIFECYCLE_OPERATIONS = [\"add\", \"update\", \"remove\"] as const;\n\ninterface GuardedMethodCacheEntry {\n\t/** The source function the wrapper was built over; identity-checked on\n\t * every read so a self-mutated adapter method cannot serve stale. */\n\treadonly sourceMethod: (...args: unknown[]) => unknown;\n\treadonly guarded: (...args: unknown[]) => unknown;\n}\n\ninterface RepositoryFacadeState<Evt extends AnyDomainEvent> {\n\treadonly source: object;\n\treadonly target: object;\n\treadonly session: RepositoryFacadeSession<Evt>;\n\treadonly definition: RuntimePersistenceDefinition<Evt>;\n\treadonly methodCache: Map<PropertyKey, GuardedMethodCacheEntry>;\n\treadonly forwardedOwnProperties: Set<PropertyKey>;\n\treadonly writes: Set<PropertyKey>;\n}\n\nfunction createRepositoryFacadeState<Evt extends AnyDomainEvent>(\n\tsource: object,\n\tsession: RepositoryFacadeSession<Evt>,\n\tdefinition: RuntimePersistenceDefinition<Evt>,\n): RepositoryFacadeState<Evt> {\n\treturn {\n\t\tsource,\n\t\ttarget: Object.create(Reflect.getPrototypeOf(source)) as object,\n\t\tsession,\n\t\tdefinition,\n\t\tmethodCache: new Map(),\n\t\tforwardedOwnProperties: new Set(),\n\t\twrites: new Set(),\n\t};\n}\n\nfunction repositoryOperationName(property: PropertyKey): string {\n\tconst name =\n\t\ttypeof property === \"symbol\"\n\t\t\t? (property.description ?? property.toString())\n\t\t\t: property;\n\treturn `repository.${name}`;\n}\n\nfunction isRepositoryLifecycleOperation(property: PropertyKey): boolean {\n\treturn REPOSITORY_LIFECYCLE_OPERATIONS.includes(\n\t\tproperty as (typeof REPOSITORY_LIFECYCLE_OPERATIONS)[number],\n\t);\n}\n\n/**\n * Own-or-inherited presence that stops BEFORE `Object.prototype`: members\n * every object inherits (`toString`, `valueOf`, `constructor`) are language\n * plumbing, not repository surface, and must not trip the facade's\n * session-open assertion.\n */\nfunction hasMemberBelowObjectPrototype(\n\tobject: object,\n\tproperty: PropertyKey,\n): boolean {\n\tlet current: object | null = object;\n\twhile (current !== null && current !== Object.prototype) {\n\t\tif (Reflect.getOwnPropertyDescriptor(current, property)) return true;\n\t\tcurrent = Reflect.getPrototypeOf(current);\n\t}\n\treturn false;\n}\n\nfunction readRepositorySource<Evt extends AnyDomainEvent>(\n\tstate: RepositoryFacadeState<Evt>,\n\tproperty: PropertyKey,\n): unknown {\n\tstate.session.assertOpen(repositoryOperationName(property));\n\tconst value = Reflect.get(state.source, property, state.source);\n\tif (typeof value !== \"function\") return value;\n\t// Cache validity is keyed on the CURRENT source function, not the\n\t// property name alone: adapter methods run with `this` bound to the raw\n\t// source, so a lazy-init self-assignment replaces the method without any\n\t// proxy trap firing. A name-only cache would keep serving the wrapper\n\t// closed over the replaced function for the rest of the run.\n\tconst cached = state.methodCache.get(property);\n\tif (cached && cached.sourceMethod === value) return cached.guarded;\n\tconst sourceMethod = value as (...args: unknown[]) => unknown;\n\tconst guarded = (...args: unknown[]): unknown => {\n\t\tstate.session.assertOpen(repositoryOperationName(property));\n\t\treturn Reflect.apply(sourceMethod, state.source, args);\n\t};\n\tstate.methodCache.set(property, { sourceMethod, guarded });\n\treturn guarded;\n}\n\nfunction defineForwardedRepositoryProperty<Evt extends AnyDomainEvent>(\n\tstate: RepositoryFacadeState<Evt>,\n\tproperty: PropertyKey,\n\tdescriptor: PropertyDescriptor,\n): void {\n\tObject.defineProperty(state.target, property, {\n\t\tconfigurable: true,\n\t\tenumerable: descriptor.enumerable ?? false,\n\t\tget: () => readRepositorySource(state, property),\n\t\tset:\n\t\t\t(\"value\" in descriptor && descriptor.writable) || descriptor.set\n\t\t\t\t? (value: unknown) => {\n\t\t\t\t\t\tstate.session.assertOpen(repositoryOperationName(property));\n\t\t\t\t\t\tif (!Reflect.set(state.source, property, value, state.source)) {\n\t\t\t\t\t\t\tthrow new TypeError(\n\t\t\t\t\t\t\t\t`Cannot assign to repository property ${String(property)}`,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t: undefined,\n\t});\n\tstate.forwardedOwnProperties.add(property);\n}\n\nfunction installRepositoryLifecycleOperations<Evt extends AnyDomainEvent>(\n\tstate: RepositoryFacadeState<Evt>,\n): void {\n\tconst operations = state.definition.physicalRemoval\n\t\t? REPOSITORY_LIFECYCLE_OPERATIONS\n\t\t: REPOSITORY_LIFECYCLE_OPERATIONS.slice(0, 2);\n\tfor (const operation of operations) {\n\t\tstate.writes.add(operation);\n\t\tObject.defineProperty(state.target, operation, {\n\t\t\tconfigurable: false,\n\t\t\tenumerable: false,\n\t\t\twritable: false,\n\t\t\tvalue: (aggregate: unknown) => {\n\t\t\t\tstate.session.assertOpen(repositoryOperationName(operation));\n\t\t\t\tstate.session[operation](\n\t\t\t\t\taggregate as Aggregate<Id<string>, Evt>,\n\t\t\t\t\tstate.definition,\n\t\t\t\t);\n\t\t\t},\n\t\t});\n\t}\n}\n\nfunction forwardAdapterOwnProperties<Evt extends AnyDomainEvent>(\n\tstate: RepositoryFacadeState<Evt>,\n): void {\n\tfor (const property of Reflect.ownKeys(state.source)) {\n\t\tif (isRepositoryLifecycleOperation(property)) continue;\n\t\tconst descriptor = Reflect.getOwnPropertyDescriptor(state.source, property);\n\t\tif (descriptor) {\n\t\t\tdefineForwardedRepositoryProperty(state, property, descriptor);\n\t\t}\n\t}\n}\n\nfunction createRepositoryFacadeHandler<Evt extends AnyDomainEvent>(\n\tstate: RepositoryFacadeState<Evt>,\n): ProxyHandler<object> {\n\treturn {\n\t\tget: (target, property, receiver) => {\n\t\t\t// Language-level probes are not repository operations: promise\n\t\t\t// resolution reads `then` on any value returned from run(),\n\t\t\t// JSON.stringify probes `toJSON`, string interpolation reads\n\t\t\t// `toString`, and inspection utilities read well-known symbols.\n\t\t\t// One principled rule instead of one exemption per discovered\n\t\t\t// probe: only a property present BELOW Object.prototype is\n\t\t\t// repository surface and gets the session-open assertion.\n\t\t\t// Everything else is language plumbing and answers normally, so\n\t\t\t// logging a leaked facade after close cannot mask the original\n\t\t\t// failure. Member reads keep the loud TransactionClosedError\n\t\t\t// (a probe cannot leak state; a member read can).\n\t\t\tif (\n\t\t\t\t!hasMemberBelowObjectPrototype(target, property) &&\n\t\t\t\t!hasMemberBelowObjectPrototype(state.source, property)\n\t\t\t) {\n\t\t\t\treturn Reflect.get(target, property, receiver);\n\t\t\t}\n\t\t\tstate.session.assertOpen(repositoryOperationName(property));\n\t\t\tconst own = Reflect.getOwnPropertyDescriptor(target, property);\n\t\t\tif (own) return Reflect.get(target, property, receiver);\n\t\t\tif (property === \"remove\") return undefined;\n\t\t\treturn readRepositorySource(state, property);\n\t\t},\n\t\tset: (target, property, value, receiver) =>\n\t\t\tsetRepositoryFacadeProperty(state, target, property, value, receiver),\n\t\thas: (target, property) => {\n\t\t\tstate.session.assertOpen(repositoryOperationName(property));\n\t\t\treturn (\n\t\t\t\tstate.writes.has(property) ||\n\t\t\t\t(property !== \"remove\" &&\n\t\t\t\t\t(Reflect.has(target, property) ||\n\t\t\t\t\t\tReflect.has(state.source, property)))\n\t\t\t);\n\t\t},\n\t\tdefineProperty: (target, property, descriptor) =>\n\t\t\tdefineRepositoryFacadeProperty(state, target, property, descriptor),\n\t\tdeleteProperty: (target, property) =>\n\t\t\tdeleteRepositoryFacadeProperty(state, target, property),\n\t};\n}\n\nfunction setRepositoryFacadeProperty<Evt extends AnyDomainEvent>(\n\tstate: RepositoryFacadeState<Evt>,\n\ttarget: object,\n\tproperty: PropertyKey,\n\tvalue: unknown,\n\treceiver: unknown,\n): boolean {\n\tstate.session.assertOpen(repositoryOperationName(property));\n\tif (isRepositoryLifecycleOperation(property)) return false;\n\tif (Reflect.getOwnPropertyDescriptor(target, property)) {\n\t\tconst set = Reflect.set(target, property, value, receiver);\n\t\tif (set) state.methodCache.delete(property);\n\t\treturn set;\n\t}\n\tif (!Reflect.isExtensible(target)) return false;\n\tconst set = Reflect.set(state.source, property, value, state.source);\n\tconst descriptor = Reflect.getOwnPropertyDescriptor(state.source, property);\n\tif (set && descriptor) {\n\t\tdefineForwardedRepositoryProperty(state, property, descriptor);\n\t}\n\t// Every successful set invalidates the guarded-method cache, matching the\n\t// own-descriptor and delete paths: a cached wrapper closed over the\n\t// replaced function must not outlive the override (test spies, strategy\n\t// swaps).\n\tif (set) state.methodCache.delete(property);\n\treturn set;\n}\n\nfunction defineRepositoryFacadeProperty<Evt extends AnyDomainEvent>(\n\tstate: RepositoryFacadeState<Evt>,\n\ttarget: object,\n\tproperty: PropertyKey,\n\tdescriptor: PropertyDescriptor,\n): boolean {\n\tstate.session.assertOpen(repositoryOperationName(property));\n\tif (\n\t\tisRepositoryLifecycleOperation(property) &&\n\t\t!Reflect.getOwnPropertyDescriptor(target, property)\n\t) {\n\t\treturn false;\n\t}\n\tconst current = Reflect.getOwnPropertyDescriptor(target, property);\n\tif (!Reflect.defineProperty(target, property, descriptor)) return false;\n\tconst next = Reflect.getOwnPropertyDescriptor(target, property);\n\tif (\n\t\tstate.forwardedOwnProperties.has(property) &&\n\t\t(current?.get !== next?.get || current?.set !== next?.set)\n\t) {\n\t\tstate.forwardedOwnProperties.delete(property);\n\t}\n\treturn true;\n}\n\nfunction deleteRepositoryFacadeProperty<Evt extends AnyDomainEvent>(\n\tstate: RepositoryFacadeState<Evt>,\n\ttarget: object,\n\tproperty: PropertyKey,\n): boolean {\n\tstate.session.assertOpen(repositoryOperationName(property));\n\tif (isRepositoryLifecycleOperation(property)) return false;\n\tconst targetDescriptor = Reflect.getOwnPropertyDescriptor(target, property);\n\tif (targetDescriptor && !state.forwardedOwnProperties.has(property)) {\n\t\treturn Reflect.deleteProperty(target, property);\n\t}\n\tconst sourceDescriptor = Reflect.getOwnPropertyDescriptor(\n\t\tstate.source,\n\t\tproperty,\n\t);\n\tif (\n\t\ttargetDescriptor?.configurable === false ||\n\t\tsourceDescriptor?.configurable === false\n\t) {\n\t\treturn false;\n\t}\n\tif (!Reflect.deleteProperty(state.source, property)) return false;\n\tif (targetDescriptor && !Reflect.deleteProperty(target, property))\n\t\treturn false;\n\tstate.forwardedOwnProperties.delete(property);\n\tstate.methodCache.delete(property);\n\treturn true;\n}\n","import { pendingEventLifecycleReadViewFor } from \"../../domain/aggregate/pending-event-lifecycle\";\nimport type { Id } from \"../../domain/identity/id\";\nimport { AggregateDeletedError } from \"../../errors/kit-errors\";\n\n/**\n * A class reference used as the type key of the identity map. Keying\n * on the CLASS (not a name string) makes collisions impossible by\n * construction: `Restaurant` and `Booking` are different keys even if\n * someone names two aggregates identically across modules, and there\n * is no string-discipline to maintain.\n *\n * `Function & { prototype: TAgg }` carries this alone. The kit's aggregate\n * convention is a **protected constructor** plus static factories, and\n * TypeScript rejects assigning such a class to a construct-signature type, so\n * the prototype witness is what accepts them. It infers `TAgg` as well.\n * Measured: a construct signature beside it changes neither what the type\n * accepts nor what it infers, and it was the last `any` in the published\n * types.\n */\nexport type AggregateClass<TAgg> =\n\t// biome-ignore lint/complexity/noBannedTypes: Function is deliberate; a construct signature cannot accept protected-constructor classes (the kit's aggregate convention); the prototype witness keeps TAgg inference.\n\tFunction & { prototype: TAgg };\n\n/**\n * Per-unit-of-work Identity Map (Fowler, PoEAA): within one operation,\n * one aggregate type+id maps to exactly ONE in-memory instance.\n *\n * This is the shipped implementation of the contract the\n * Repository guide (`docs/guide/repository.md`) places on\n * `AggregatePersistence` implementations: two `findById(id)` calls in the same\n * unit of work MUST return the same instance, because commit-token\n * write registration dedupes by JavaScript object identity. Two instances for\n * one logical aggregate can otherwise produce two tokens, two harvests,\n * and two post-commit lifecycle calls.\n *\n * Storage is two-level (per-type stores created lazily), so\n * `Restaurant:123` and `Booking:123` can never collide: the type key\n * is the aggregate CLASS, not the id alone and not a name string.\n *\n * Repository read-path contract:\n *\n * ```ts\n * async findById(id: OrderId): Promise<Order | undefined> {\n * const cached = this.tracking.identityMap.get(Order, id);\n * if (cached) return cached;\n * // Deleted in this unit of work = gone, even if the physical\n * // delete is deferred and the row is still visible in the tx.\n * if (this.tracking.identityMap.isDeleted(Order, id)) return undefined;\n *\n * const row = await this.loadRow(id);\n * if (!row) return undefined;\n * const order = Order.reconstitute(row.id, row.state, row.version);\n * return this.tracking.trackLoaded(order);\n * }\n * ```\n *\n * Deletion is final within an operation: {@link delete} removes the\n * entry AND records a tombstone, so a later {@link set} of the same\n * type+id throws `AggregateDeletedError`: a second instance of a\n * deleted aggregate can never sneak back into the unit of work, even\n * through a repository whose row delete is deferred.\n *\n * Lifetime is ONE unit of work: the `UnitOfWork` creates a fresh map\n * per `run()` and clears it on close. Never cache across operations;\n * that would silently bypass optimistic concurrency control.\n */\nexport class IdentityMap {\n\tprivate readonly _stores = new Map<\n\t\tAggregateClass<unknown>,\n\t\tMap<string, unknown>\n\t>();\n\tprivate readonly _deleted = new Map<AggregateClass<unknown>, Set<string>>();\n\t// pendingEvents length captured when an instance was first registered\n\t// (load time), so the unit of work can tell events RECORDED AFTER load\n\t// apart from a \"dirty\" reconstitution that already carried events.\n\tprivate _pendingAtRegistration = new WeakMap<object, number>();\n\n\t/** The cached instance for type+id, or `undefined` (also after {@link delete}). */\n\tpublic get<TAgg>(\n\t\ttype: AggregateClass<TAgg>,\n\t\tid: Id<string>,\n\t): TAgg | undefined {\n\t\treturn this._stores.get(type)?.get(id) as TAgg | undefined;\n\t}\n\n\t/** Whether an instance is registered for type+id (false after {@link delete}). */\n\tpublic has<TAgg>(type: AggregateClass<TAgg>, id: Id<string>): boolean {\n\t\treturn this._stores.get(type)?.has(id) ?? false;\n\t}\n\n\t/**\n\t * Whether type+id was {@link delete}d in this unit of work. The\n\t * read path checks this BEFORE hydrating and returns `null`, so\n\t * \"deleted in this operation\" reads uniformly as not-found,\n\t * regardless of whether the repository's physical delete already\n\t * removed the row or is deferred within the transaction. Without\n\t * the check, a read-only probe of a deleted aggregate would crash\n\t * in {@link set} for deferred-write repositories and return `null`\n\t * for immediate-write ones.\n\t */\n\tpublic isDeleted<TAgg>(type: AggregateClass<TAgg>, id: Id<string>): boolean {\n\t\treturn this._deleted.get(type)?.has(id) ?? false;\n\t}\n\n\t/**\n\t * Registers the hydrated instance for type+id.\n\t *\n\t * - Re-registering the SAME instance is a no-op (idempotent).\n\t * - Registering a DIFFERENT instance for an occupied type+id throws:\n\t * that is precisely the identity-map violation this class exists\n\t * to prevent (the repository hydrated twice instead of checking\n\t * {@link get} first), and letting it pass would double-harvest\n\t * events downstream.\n\t * - Registering a type+id that was {@link delete}d in this unit of\n\t * work throws `AggregateDeletedError`: deletion is final within\n\t * the operation.\n\t */\n\tpublic set<TAgg>(\n\t\ttype: AggregateClass<TAgg>,\n\t\tid: Id<string>,\n\t\taggregate: TAgg,\n\t): void {\n\t\tif (this._deleted.get(type)?.has(id)) {\n\t\t\tthrow new AggregateDeletedError(String(id));\n\t\t}\n\t\tlet store = this._stores.get(type);\n\t\tif (store === undefined) {\n\t\t\tstore = new Map<string, unknown>();\n\t\t\tthis._stores.set(type, store);\n\t\t}\n\t\tconst existing = store.get(id);\n\t\tif (existing !== undefined && existing !== aggregate) {\n\t\t\tthrow new Error(\n\t\t\t\t`IdentityMap: a different instance is already registered for ` +\n\t\t\t\t\t`${type.name}(${String(id)}). Check get() before hydrating - ` +\n\t\t\t\t\t`two live instances of one aggregate break the one-instance-per-` +\n\t\t\t\t\t`unit-of-work contract that exactly-once event harvest relies on.`,\n\t\t\t);\n\t\t}\n\t\tstore.set(id, aggregate);\n\t\t// Capture the load-time pending count once (idempotent re-set keeps\n\t\t// the first value), so the unit of work can later tell events\n\t\t// RECORDED AFTER load apart from a reconstitution that already\n\t\t// carried events. Assumes pendingEvents is append-only between load\n\t\t// and commit (the kit's recording model); only the internal\n\t\t// post-commit capability shrinks it.\n\t\tif (\n\t\t\taggregate !== null &&\n\t\t\ttypeof aggregate === \"object\" &&\n\t\t\t!this._pendingAtRegistration.has(aggregate as object)\n\t\t) {\n\t\t\tconst pending = pendingEventCountOf(aggregate);\n\t\t\tif (pending !== undefined) {\n\t\t\t\tthis._pendingAtRegistration.set(aggregate as object, pending);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Registered instances that have recorded MORE pending events than they\n\t * carried when first registered (loaded). Used by the unit of work's\n\t * end-of-run guard: an aggregate that gained events after load but was\n\t * never enrolled would silently drop them. A read-only load, or a\n\t * reconstitution that already carried events, shows no increase and is\n\t * not reported.\n\t */\n\tpublic instancesWithNewPendingEvents(): unknown[] {\n\t\tconst result: unknown[] = [];\n\t\tfor (const store of this._stores.values()) {\n\t\t\tfor (const instance of store.values()) {\n\t\t\t\tconst pending = pendingEventCountOf(instance);\n\t\t\t\tif (pending === undefined) continue;\n\t\t\t\tconst atRegistration =\n\t\t\t\t\tthis._pendingAtRegistration.get(instance as object) ?? 0;\n\t\t\t\tif (pending > atRegistration) {\n\t\t\t\t\tresult.push(instance);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\t/**\n\t * Takes back a registration WITHOUT a tombstone: the entry is removed\n\t * only when the stored instance IS the given one, and a later\n\t * {@link set} of the same type+id stays legal. The Unit of Work calls\n\t * this when a registration step fails after {@link set} already ran, so\n\t * the failed instance cannot be served by `findById` as a phantom.\n\t * This is rollback, not deletion; deletion finality belongs to\n\t * {@link delete}.\n\t */\n\tpublic discard<TAgg>(\n\t\ttype: AggregateClass<TAgg>,\n\t\tid: Id<string>,\n\t\taggregate: TAgg,\n\t): void {\n\t\tconst store = this._stores.get(type);\n\t\tif (store?.get(id) === aggregate) {\n\t\t\tstore.delete(id);\n\t\t}\n\t}\n\n\t/**\n\t * Removes the entry for type+id and records a tombstone: subsequent\n\t * {@link get} / {@link has} report absence, and a subsequent\n\t * {@link set} of the same type+id throws `AggregateDeletedError`.\n\t * The Unit of Work calls this as part of `repository.remove(aggregate)`;\n\t * repository adapters receive only the read-only\n\t * identity-map view.\n\t */\n\tpublic delete<TAgg>(type: AggregateClass<TAgg>, id: Id<string>): void {\n\t\tthis._stores.get(type)?.delete(id);\n\t\tlet tombstones = this._deleted.get(type);\n\t\tif (tombstones === undefined) {\n\t\t\ttombstones = new Set<string>();\n\t\t\tthis._deleted.set(type, tombstones);\n\t\t}\n\t\ttombstones.add(id);\n\t}\n\n\t/** Empties all stores and tombstones. Called by the unit of work on close. */\n\tpublic clear(): void {\n\t\tthis._stores.clear();\n\t\tthis._deleted.clear();\n\t\t// A WeakMap cannot be emptied in place; replace it so a reused map\n\t\t// captures FRESH pending-event baselines. A stale (higher) baseline\n\t\t// would make instancesWithNewPendingEvents under-report and defeat\n\t\t// the UnenrolledChangesError safety net.\n\t\tthis._pendingAtRegistration = new WeakMap<object, number>();\n\t}\n}\n\n/**\n * Pending-event count of a stored value, or `undefined` for anything that is\n * not aggregate-shaped. Single source of truth so the load-time capture in\n * {@link IdentityMap.set} and the end-of-run scan in\n * {@link IdentityMap.instancesWithNewPendingEvents} cannot drift apart.\n * The kit-internal lifecycle read view avoids the public `pendingEvents`\n * getter, which allocates and freezes a defensive copy per read; the getter\n * stays as the fallback for structural lookalikes.\n */\nfunction pendingEventCountOf(value: unknown): number | undefined {\n\tif (value === null || typeof value !== \"object\") return undefined;\n\tconst lifecycle = pendingEventLifecycleReadViewFor(value);\n\tif (lifecycle !== undefined) return lifecycle.pendingEventCount();\n\tconst pending = (value as { pendingEvents?: unknown }).pendingEvents;\n\treturn Array.isArray(pending) ? pending.length : undefined;\n}\n","import { UnmanagedInstanceError } from \"../../errors/kit-errors\";\nimport { deepEqual } from \"../../internal/structural/deep-equal\";\n\n/** Whether a baseline represents an existing row or a pending insert. */\nexport type PersistenceLifecycle = \"loaded\" | \"new\";\n\n/**\n * Adapter-owned projection and change derivation for one aggregate type.\n *\n * The domain model does not implement this contract. A repository adapter\n * chooses what it persists, how that projection is captured at load, and\n * whether a change set is a partial diff or a full replacement.\n */\nexport interface PersistenceModel<TAggregate, TBaseline, TChangeSet> {\n\t/**\n\t * Captures the adapter's persistence projection at the current moment.\n\t * Return a detached value or an immutable value object: the Unit of Work\n\t * retains it as a baseline and cannot make an arbitrary adapter type safe.\n\t *\n\t * Capture must be deterministic for an unchanged aggregate: the Unit of\n\t * Work compares successive captures to detect mutation after write\n\t * registration. A capture that embeds ambient values (clock reads,\n\t * random ids) would make every commit look mutated. The default\n\t * comparison is the package's structural deep equality, which matches\n\t * `Set` members and `Map` keys by reference (JS `SameValueZero`\n\t * semantics): a capture that re-materializes object Set members or Map\n\t * keys on every call must supply {@link captureEquals}.\n\t */\n\tcapture(aggregate: TAggregate): TBaseline;\n\n\t/**\n\t * Adapter-owned equality for two captures of the persistence projection.\n\t * Optional: the default is the package's structural deep equality (Set\n\t * members and Map keys by reference). Supply it when the capture shape\n\t * needs domain-specific comparison, for example rebuilt value-object Set\n\t * members compared by value.\n\t */\n\treadonly captureEquals?: (a: TBaseline, b: TBaseline) => boolean;\n\n\t/**\n\t * Derives the adapter's write payload from its own baseline.\n\t *\n\t * `baseline` is absent for a new aggregate. `lifecycle` disambiguates that\n\t * case from an adapter whose loaded baseline type itself admits `undefined`.\n\t * The returned payload must not share mutable references with the aggregate;\n\t * it is the exact value later handed to `flush`.\n\t */\n\tchanges(\n\t\tbaseline: TBaseline | undefined,\n\t\taggregate: TAggregate,\n\t\tlifecycle: PersistenceLifecycle,\n\t): TChangeSet;\n\n\t/** Tells orchestration whether the derived state write is empty. */\n\tisEmpty(changes: TChangeSet): boolean;\n}\n\ndeclare const persistenceBaselineBrand: unique symbol;\n\n/**\n * Opaque, typed receipt for an adapter-owned persistence baseline.\n *\n * It intentionally exposes no data. The Unit of Work may retain the token and\n * ask the owning adapter capability to derive changes, but cannot branch on or\n * couple itself to the baseline's shape.\n */\nexport interface PersistenceBaseline<TAggregate, TChangeSet> {\n\treadonly [persistenceBaselineBrand]: (aggregate: TAggregate) => TChangeSet;\n}\n\n/** A derived adapter change set plus its adapter-defined emptiness result. */\nexport interface PersistenceChanges<TChangeSet> {\n\treadonly value: TChangeSet;\n\treadonly empty: boolean;\n}\n\ninterface BaselineCapability {\n\treadonly baseline: unknown;\n\treadonly lifecycle: PersistenceLifecycle;\n\tcapture(aggregate: unknown): unknown;\n\tcaptureEquals(a: unknown, b: unknown): boolean;\n\tchanges(\n\t\tbaseline: unknown,\n\t\taggregate: unknown,\n\t\tlifecycle: PersistenceLifecycle,\n\t): unknown;\n\tisEmpty(changes: unknown): boolean;\n}\n\nconst capabilities = new WeakMap<object, BaselineCapability>();\n\n/** Captures a baseline for an aggregate restored by a repository adapter. */\nexport function capturePersistenceBaseline<TAggregate, TBaseline, TChangeSet>(\n\tmodel: PersistenceModel<TAggregate, TBaseline, TChangeSet>,\n\taggregate: TAggregate,\n): PersistenceBaseline<TAggregate, TChangeSet> {\n\treturn createBaselineToken(model, model.capture(aggregate), \"loaded\");\n}\n\n/** Creates the explicit no-row baseline for a newly added aggregate. */\nexport function insertPersistenceBaseline<TAggregate, TBaseline, TChangeSet>(\n\tmodel: PersistenceModel<TAggregate, TBaseline, TChangeSet>,\n): PersistenceBaseline<TAggregate, TChangeSet> {\n\treturn createBaselineToken(model, undefined, \"new\");\n}\n\n/**\n * Captures the aggregate's current adapter projection using the capability\n * carried by an existing baseline. Used to seal persistence-last registration.\n */\nexport function recapturePersistenceBaseline<TAggregate, TChangeSet>(\n\tbaseline: PersistenceBaseline<TAggregate, TChangeSet>,\n\taggregate: TAggregate,\n): PersistenceBaseline<TAggregate, TChangeSet> {\n\tconst capability = capabilityFor(baseline, \"recapturePersistenceBaseline\");\n\treturn createErasedBaselineToken({\n\t\t...capability,\n\t\tbaseline: capability.capture(aggregate),\n\t\tlifecycle: \"loaded\",\n\t});\n}\n\n/**\n * Recaptures the adapter projection and reports whether it drifted from the\n * baseline's stored capture, using the model's `captureEquals` when supplied\n * and structural deep equality otherwise.\n *\n * This, not `changes()`/`isEmpty()`, is the mutation detector: the\n * `PersistenceModel` contract explicitly permits a full-replacement change\n * set whose `isEmpty` is never true, so a non-empty change set proves\n * nothing about mutation. Comparing capture to capture asks the honest\n * question independent of the model's diffing strategy. A `\"new\"` lifecycle\n * baseline has no stored capture and never reports drift.\n */\nexport function persistenceProjectionDrifted<TAggregate, TChangeSet>(\n\tbaseline: PersistenceBaseline<TAggregate, TChangeSet>,\n\taggregate: TAggregate,\n): boolean {\n\tconst capability = capabilityFor(baseline, \"persistenceProjectionDrifted\");\n\tif (capability.lifecycle === \"new\") return false;\n\treturn !capability.captureEquals(\n\t\tcapability.baseline,\n\t\tcapability.capture(aggregate),\n\t);\n}\n\n/** Derives a typed adapter change set without exposing the stored baseline. */\nexport function derivePersistenceChanges<TAggregate, TChangeSet>(\n\tbaseline: PersistenceBaseline<TAggregate, TChangeSet>,\n\taggregate: TAggregate,\n): PersistenceChanges<TChangeSet> {\n\tconst capability = capabilityFor(baseline, \"derivePersistenceChanges\");\n\tconst value = capability.changes(\n\t\tcapability.baseline,\n\t\taggregate,\n\t\tcapability.lifecycle,\n\t) as TChangeSet;\n\treturn Object.freeze({ value, empty: capability.isEmpty(value) });\n}\n\nfunction createBaselineToken<TAggregate, TBaseline, TChangeSet>(\n\tmodel: PersistenceModel<TAggregate, TBaseline, TChangeSet>,\n\tbaseline: TBaseline | undefined,\n\tlifecycle: PersistenceLifecycle,\n): PersistenceBaseline<TAggregate, TChangeSet> {\n\treturn createErasedBaselineToken({\n\t\tbaseline,\n\t\tlifecycle,\n\t\tcapture: (aggregate) => model.capture(aggregate as TAggregate),\n\t\tcaptureEquals: (a, b) =>\n\t\t\tmodel.captureEquals\n\t\t\t\t? model.captureEquals(a as TBaseline, b as TBaseline)\n\t\t\t\t: deepEqual(a, b),\n\t\tchanges: (stored, aggregate, currentLifecycle) =>\n\t\t\tmodel.changes(\n\t\t\t\tstored as TBaseline | undefined,\n\t\t\t\taggregate as TAggregate,\n\t\t\t\tcurrentLifecycle,\n\t\t\t),\n\t\tisEmpty: (changes) => model.isEmpty(changes as TChangeSet),\n\t});\n}\n\nfunction createErasedBaselineToken<TAggregate, TChangeSet>(\n\tcapability: BaselineCapability,\n): PersistenceBaseline<TAggregate, TChangeSet> {\n\tconst token = Object.freeze(Object.create(null)) as PersistenceBaseline<\n\t\tTAggregate,\n\t\tTChangeSet\n\t>;\n\tcapabilities.set(token as object, capability);\n\treturn token;\n}\n\nfunction capabilityFor<TAggregate, TChangeSet>(\n\tbaseline: PersistenceBaseline<TAggregate, TChangeSet>,\n\toperation: string,\n): BaselineCapability {\n\tconst capability = capabilities.get(baseline as object);\n\tif (!capability) {\n\t\tthrow new UnmanagedInstanceError(operation, \"the persistence baseline\");\n\t}\n\treturn capability;\n}\n","import type { Aggregate, Version } from \"../../domain/aggregate/aggregate\";\nimport type {\n\tAnyDomainEvent,\n\tPendingDomainEvent,\n} from \"../../domain/event/domain-event\";\nimport type { Id } from \"../../domain/identity/id\";\nimport {\n\tAggregateDeletedError,\n\ttype InfrastructureError,\n\tisInfrastructureErrorLike,\n\tUnenrolledChangesError,\n} from \"../../errors/kit-errors\";\nimport { IdentityMap } from \"../../persistence/repository/identity-map\";\nimport {\n\tcapturePersistenceBaseline,\n\tderivePersistenceChanges,\n\tinsertPersistenceBaseline,\n\ttype PersistenceBaseline,\n\ttype PersistenceChanges,\n\tpersistenceProjectionDrifted,\n\trecapturePersistenceBaseline,\n} from \"../../persistence/repository/persistence-model\";\nimport type { AggregateCommitToken, CommitEnrollment } from \"../cqrs/handler\";\nimport {\n\tAggregateTrackingError,\n\tRepositoryErrorMappingFailedError,\n\tTransactionClosedError,\n} from \"./errors\";\nimport type {\n\tAggregatePersistenceWrite,\n\tAggregateWriteIntent,\n\tRepositoryTracking,\n\tRuntimePersistenceDefinition,\n\tUnitOfWorkIdentityMap,\n} from \"./persistence-contract\";\n\ntype AggregateLifecycle = \"new\" | \"loaded\";\n\n/**\n * The immutable receipt one add/update/remove registration freezes: intent,\n * exact version and event batch, the sealed persistence baseline, and the\n * derived change set. It exists as ONE optional unit so registration,\n * rollback, and flush cannot half-apply it; `registration === undefined`\n * means \"tracked but no write registered\".\n */\ninterface WriteRegistration<Evt extends AnyDomainEvent> {\n\treadonly intent: AggregateWriteIntent;\n\treadonly version: Version;\n\treadonly events: ReadonlyArray<PendingDomainEvent<Evt>>;\n\treadonly baseline: PersistenceBaseline<Aggregate<Id<string>, Evt>, unknown>;\n\treadonly changes: PersistenceChanges<unknown>;\n}\n\ninterface TrackedAggregate<Evt extends AnyDomainEvent> {\n\treadonly aggregate: Aggregate<Id<string>, Evt>;\n\treadonly lifecycle: AggregateLifecycle;\n\treadonly expectedVersion: Version | undefined;\n\treadonly definition: RuntimePersistenceDefinition<Evt>;\n\treadonly baseline: PersistenceBaseline<Aggregate<Id<string>, Evt>, unknown>;\n\tregistration?: WriteRegistration<Evt>;\n}\n\n/**\n * Tracks the aggregates of one `run()`: identity map, write intent and\n * commit registration. Closed by `run()`'s finally.\n *\n * @internal Shared with the unit of work in this package; not part of\n * the public API.\n */\nexport class Session<Evt extends AnyDomainEvent> {\n\t// Read tracking order is independent of write registration order. Flush\n\t// follows this list so adapters observe the same explicit order as the use\n\t// case's add/update/remove calls. Enrollment and removal state are NOT\n\t// separate collections: both derive from each entry's registration, so\n\t// the bookkeeping cannot drift apart.\n\tprivate readonly _registeredWrites: TrackedAggregate<Evt>[] = [];\n\tprivate readonly _commitTokens = new Set<AggregateCommitToken<Evt>>();\n\tprivate readonly _identityMap = new IdentityMap();\n\t// What adapters receive: the typed read-only view, enforced at runtime.\n\t// Handing out the map itself would expose set/delete/clear to JavaScript\n\t// callers, and a stray clear() erases deletion tombstones and the\n\t// pending-event baselines behind UnenrolledChangesError.\n\tprivate readonly _identityMapView = Object.freeze({\n\t\tget: this._identityMap.get.bind(this._identityMap),\n\t\thas: this._identityMap.has.bind(this._identityMap),\n\t\tisDeleted: this._identityMap.isDeleted.bind(this._identityMap),\n\t}) as UnitOfWorkIdentityMap;\n\tprivate readonly _trackingByAggregate = new WeakMap<\n\t\tAggregate<Id<string>, Evt>,\n\t\tTrackedAggregate<Evt>\n\t>();\n\tprivate readonly _trackedAggregates = new Set<TrackedAggregate<Evt>>();\n\tprivate _closed = false;\n\n\tconstructor(private readonly commitEnrollment: CommitEnrollment<Evt>) {}\n\n\tpublic get identityMap(): UnitOfWorkIdentityMap {\n\t\tthis.assertOpen(\"tracking.identityMap\");\n\t\treturn this._identityMapView;\n\t}\n\n\tpublic trackingFor(\n\t\tdefinition: RuntimePersistenceDefinition<Evt>,\n\t): RepositoryTracking<Aggregate<Id<string>, Evt>> {\n\t\tconst session = this;\n\t\treturn Object.freeze({\n\t\t\tget identityMap() {\n\t\t\t\treturn session.identityMap;\n\t\t\t},\n\t\t\ttrackLoaded: (aggregate: Aggregate<Id<string>, Evt>) =>\n\t\t\t\tsession.trackLoaded(aggregate, definition),\n\t\t});\n\t}\n\n\t/** The registration of an instance, or undefined when none is tracked. */\n\tprivate registrationOf(\n\t\taggregate: object,\n\t): WriteRegistration<Evt> | undefined {\n\t\treturn this._trackingByAggregate.get(\n\t\t\taggregate as Aggregate<Id<string>, Evt>,\n\t\t)?.registration;\n\t}\n\n\t/** Whether THIS instance registered a remove in this session. */\n\tprivate isRemovedInstance(aggregate: object): boolean {\n\t\treturn this.registrationOf(aggregate)?.intent === \"remove\";\n\t}\n\n\tprivate trackLoaded<TAggregate extends Aggregate<Id<string>, Evt>>(\n\t\taggregate: TAggregate,\n\t\tdefinition: RuntimePersistenceDefinition<Evt>,\n\t): TAggregate {\n\t\tthis.assertOpen(\"tracking.trackLoaded\");\n\t\t// Ownership is checked BEFORE identity-map registration: a rejected\n\t\t// instance must not stay registered under the second definition's\n\t\t// class key with no tracking entry behind it.\n\t\tconst existing = this._trackingByAggregate.get(aggregate);\n\t\tif (existing && existing.definition !== definition) {\n\t\t\tthrow new AggregateTrackingError(\n\t\t\t\tString(aggregate.id),\n\t\t\t\t\"load\",\n\t\t\t\t\"different_repository\",\n\t\t\t\texisting.registration?.intent,\n\t\t\t);\n\t\t}\n\t\tthis._identityMap.set(definition.aggregate, aggregate.id, aggregate);\n\t\tif (existing) return aggregate;\n\n\t\tconst entry: TrackedAggregate<Evt> = {\n\t\t\taggregate,\n\t\t\tlifecycle: \"loaded\",\n\t\t\texpectedVersion: aggregate.version,\n\t\t\tdefinition,\n\t\t\tbaseline: capturePersistenceBaseline(definition.persistence, aggregate),\n\t\t};\n\t\tthis._trackingByAggregate.set(aggregate, entry);\n\t\tthis._trackedAggregates.add(entry);\n\t\treturn aggregate;\n\t}\n\n\tpublic add(\n\t\taggregate: Aggregate<Id<string>, Evt>,\n\t\tdefinition: RuntimePersistenceDefinition<Evt>,\n\t): void {\n\t\tthis.assertOpen(\"repository.add\");\n\t\tthis.assertNotRemoved(aggregate, definition);\n\t\tconst existing = this._trackingByAggregate.get(aggregate);\n\t\tif (existing && existing.definition !== definition) {\n\t\t\tthrow new AggregateTrackingError(\n\t\t\t\tString(aggregate.id),\n\t\t\t\t\"add\",\n\t\t\t\t\"different_repository\",\n\t\t\t\texisting.registration?.intent,\n\t\t\t);\n\t\t}\n\t\tif (existing?.lifecycle === \"loaded\") {\n\t\t\tthrow new AggregateTrackingError(\n\t\t\t\tString(aggregate.id),\n\t\t\t\t\"add\",\n\t\t\t\t\"loaded_as_new\",\n\t\t\t\texisting.registration?.intent,\n\t\t\t);\n\t\t}\n\n\t\tlet entry = existing;\n\t\tconst newlyTracked = !entry;\n\t\tif (!entry) {\n\t\t\tthis._identityMap.set(definition.aggregate, aggregate.id, aggregate);\n\t\t\tentry = {\n\t\t\t\taggregate,\n\t\t\t\tlifecycle: \"new\",\n\t\t\t\texpectedVersion: undefined,\n\t\t\t\tdefinition,\n\t\t\t\tbaseline: insertPersistenceBaseline(definition.persistence),\n\t\t\t};\n\t\t\tthis._trackingByAggregate.set(aggregate, entry);\n\t\t\tthis._trackedAggregates.add(entry);\n\t\t}\n\n\t\ttry {\n\t\t\tthis.registerWrite(entry, \"add\", definition);\n\t\t} catch (error) {\n\t\t\t// A failed add must not leave a phantom: without this rollback,\n\t\t\t// findById would serve the never-persisted instance from the\n\t\t\t// identity map while the commit-readiness guard ignores \"new\"\n\t\t\t// lifecycle entries, so the transaction would commit without a\n\t\t\t// write for it.\n\t\t\tif (newlyTracked) {\n\t\t\t\tthis._trackingByAggregate.delete(aggregate);\n\t\t\t\tthis._trackedAggregates.delete(entry);\n\t\t\t\tthis._identityMap.discard(\n\t\t\t\t\tdefinition.aggregate,\n\t\t\t\t\taggregate.id,\n\t\t\t\t\taggregate,\n\t\t\t\t);\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tpublic update(\n\t\taggregate: Aggregate<Id<string>, Evt>,\n\t\tdefinition: RuntimePersistenceDefinition<Evt>,\n\t): void {\n\t\tthis.assertOpen(\"repository.update\");\n\t\tconst entry = this.loadedEntryFor(aggregate, \"update\", definition);\n\t\tthis.registerWrite(entry, \"update\", definition);\n\t}\n\n\tpublic remove(\n\t\taggregate: Aggregate<Id<string>, Evt>,\n\t\tdefinition: RuntimePersistenceDefinition<Evt>,\n\t): void {\n\t\tthis.assertOpen(\"repository.remove\");\n\t\t// Idempotent by reference, like add and update: a repeated remove of\n\t\t// the SAME instance re-declares the same final lifecycle outcome\n\t\t// (collection semantics; the enrollment layer already returns the\n\t\t// same token for a repeat enrollDeleted). The deletion-finality gate\n\t\t// stays sharp for everything else: add, update, and trackLoaded\n\t\t// after remove, and any OTHER instance with the same id, still\n\t\t// reject.\n\t\tconst entry = this._trackingByAggregate.get(aggregate);\n\t\tif (this.isRemovedInstance(aggregate) && entry?.definition === definition) {\n\t\t\treturn;\n\t\t}\n\t\tconst loaded = this.loadedEntryFor(aggregate, \"remove\", definition);\n\t\tthis.registerWrite(loaded, \"remove\", definition);\n\t}\n\n\t/** Registers persistence intent and commit enrollment as one operation. */\n\tprivate registerWrite(\n\t\tentry: TrackedAggregate<Evt>,\n\t\tintent: AggregateWriteIntent,\n\t\tdefinition: RuntimePersistenceDefinition<Evt>,\n\t): void {\n\t\tconst newlyRegistered = this.registerIntent(entry, intent);\n\t\ttry {\n\t\t\tif (intent === \"remove\") {\n\t\t\t\tthis.registerRemovedCommit(\n\t\t\t\t\tentry.aggregate,\n\t\t\t\t\tdefinition,\n\t\t\t\t\tentry.expectedVersion,\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tthis.registerSavedCommit(\n\t\t\t\t\tentry.aggregate,\n\t\t\t\t\tdefinition,\n\t\t\t\t\tentry.expectedVersion,\n\t\t\t\t);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tif (newlyRegistered) this.rollbackIntentRegistration(entry);\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tprivate loadedEntryFor(\n\t\taggregate: Aggregate<Id<string>, Evt>,\n\t\toperation: \"update\" | \"remove\",\n\t\tdefinition: RuntimePersistenceDefinition<Evt>,\n\t): TrackedAggregate<Evt> {\n\t\tthis.assertNotRemoved(aggregate, definition);\n\t\tconst entry = this._trackingByAggregate.get(aggregate);\n\t\t// Repository-ownership violations report as such on every operation:\n\t\t// add and trackLoaded already use different_repository, and code\n\t\t// branching on the machine-readable reason must not get not_loaded\n\t\t// for the identical violation on the update/remove path.\n\t\tif (entry && entry.definition !== definition) {\n\t\t\tthrow new AggregateTrackingError(\n\t\t\t\tString(aggregate.id),\n\t\t\t\toperation,\n\t\t\t\t\"different_repository\",\n\t\t\t\tentry.registration?.intent,\n\t\t\t);\n\t\t}\n\t\t// An add()-registered aggregate IS tracked, just not \"loaded\": report\n\t\t// the real conflict with the registered intent. The not_loaded advice\n\t\t// (\"load it through the repository\") is impossible for an aggregate\n\t\t// that has no row yet and would actively mislead.\n\t\tif (entry && entry.lifecycle === \"new\" && entry.definition === definition) {\n\t\t\tthrow new AggregateTrackingError(\n\t\t\t\tString(aggregate.id),\n\t\t\t\toperation,\n\t\t\t\t\"conflicting_intent\",\n\t\t\t\tentry.registration?.intent,\n\t\t\t);\n\t\t}\n\t\tif (entry?.lifecycle !== \"loaded\" || entry.definition !== definition) {\n\t\t\tthrow new AggregateTrackingError(\n\t\t\t\tString(aggregate.id),\n\t\t\t\toperation,\n\t\t\t\t\"not_loaded\",\n\t\t\t\tentry?.registration?.intent,\n\t\t\t);\n\t\t}\n\t\treturn entry;\n\t}\n\n\tprivate assertNotRemoved(\n\t\taggregate: Aggregate<Id<string>, Evt>,\n\t\tdefinition: RuntimePersistenceDefinition<Evt>,\n\t): void {\n\t\tif (this._identityMap.isDeleted(definition.aggregate, aggregate.id)) {\n\t\t\tthrow new AggregateDeletedError(String(aggregate.id));\n\t\t}\n\t}\n\n\tprivate registerIntent(\n\t\tentry: TrackedAggregate<Evt>,\n\t\tintent: AggregateWriteIntent,\n\t): boolean {\n\t\tif (entry.registration !== undefined) {\n\t\t\tif (entry.registration.intent !== intent) {\n\t\t\t\tthrow new AggregateTrackingError(\n\t\t\t\t\tString(entry.aggregate.id),\n\t\t\t\t\tintent,\n\t\t\t\t\t\"conflicting_intent\",\n\t\t\t\t\tentry.registration.intent,\n\t\t\t\t);\n\t\t\t}\n\t\t\tthis.assertUnchangedAfterRegistration(entry);\n\t\t\treturn false;\n\t\t}\n\n\t\tentry.registration = Object.freeze({\n\t\t\tintent,\n\t\t\tversion: entry.aggregate.version,\n\t\t\t// Already a frozen detached copy from the pendingEvents getter.\n\t\t\tevents: entry.aggregate.pendingEvents,\n\t\t\tbaseline: recapturePersistenceBaseline(entry.baseline, entry.aggregate),\n\t\t\tchanges: derivePersistenceChanges(entry.baseline, entry.aggregate),\n\t\t});\n\t\tthis._registeredWrites.push(entry);\n\t\treturn true;\n\t}\n\n\t/** Restores the pre-registration state when commit enrollment rejects. */\n\tprivate rollbackIntentRegistration(entry: TrackedAggregate<Evt>): void {\n\t\tconst index = this._registeredWrites.lastIndexOf(entry);\n\t\tif (index >= 0) this._registeredWrites.splice(index, 1);\n\t\tdelete entry.registration;\n\t}\n\n\tprivate assertUnchangedAfterRegistration(entry: TrackedAggregate<Evt>): void {\n\t\tconst registration = entry.registration;\n\t\tif (registration === undefined) return;\n\t\tconst currentEvents = entry.aggregate.pendingEvents;\n\t\t// Capture-to-capture drift, NOT changes().isEmpty(): the\n\t\t// PersistenceModel contract permits full-replacement change sets that\n\t\t// are never empty, so a non-empty change set proves nothing about\n\t\t// mutation after registration.\n\t\tconst persistenceChanged = persistenceProjectionDrifted(\n\t\t\tregistration.baseline,\n\t\t\tentry.aggregate,\n\t\t);\n\t\tconst sameEvents =\n\t\t\tcurrentEvents.length === registration.events.length &&\n\t\t\tcurrentEvents.every(\n\t\t\t\t(event, index) => event === registration.events[index],\n\t\t\t);\n\t\tif (\n\t\t\tregistration.version !== entry.aggregate.version ||\n\t\t\t!sameEvents ||\n\t\t\tpersistenceChanged\n\t\t) {\n\t\t\tthrow new AggregateTrackingError(\n\t\t\t\tString(entry.aggregate.id),\n\t\t\t\t\"commit\",\n\t\t\t\t\"mutated_after_registration\",\n\t\t\t\tregistration.intent,\n\t\t\t);\n\t\t}\n\t}\n\n\tprivate registerSavedCommit(\n\t\taggregate: Aggregate<Id<string>, Evt>,\n\t\tdefinition: RuntimePersistenceDefinition<Evt>,\n\t\texpectedVersion: Version | undefined,\n\t): AggregateCommitToken<Evt> {\n\t\tthis.assertOpen(\"repository.add/update\");\n\t\t// Two gates, one invariant: the registration check catches the same\n\t\t// reference; the identity-map tombstone (keyed on the instance's\n\t\t// concrete class) catches a DIFFERENT instance with the same\n\t\t// type+id: e.g. one re-created via the static factory after the\n\t\t// delete. Both mean \"deleted is final within this operation\".\n\t\tif (\n\t\t\tthis.isRemovedInstance(aggregate) ||\n\t\t\tthis._identityMap.isDeleted(definition.aggregate, aggregate.id)\n\t\t) {\n\t\t\tthrow new AggregateDeletedError(String(aggregate.id));\n\t\t}\n\t\tconst token = this.commitEnrollment.enrollSaved(aggregate, {\n\t\t\texpectedVersion,\n\t\t});\n\t\tthis._commitTokens.add(token);\n\t\treturn token;\n\t}\n\n\tprivate registerRemovedCommit(\n\t\taggregate: Aggregate<Id<string>, Evt>,\n\t\tdefinition: RuntimePersistenceDefinition<Evt>,\n\t\texpectedVersion: Version | undefined,\n\t): AggregateCommitToken<Evt> {\n\t\tthis.assertOpen(\"repository.remove\");\n\t\tconst token = this.commitEnrollment.enrollDeleted(aggregate, {\n\t\t\texpectedVersion,\n\t\t});\n\t\t// One call does ALL the deletion bookkeeping: the identity-map\n\t\t// entry is removed and tombstoned automatically (keyed on the\n\t\t// instance's concrete class), so repositories do not need a\n\t\t// second manual identityMap.delete() call; a forgotten leg of a\n\t\t// two-call protocol would silently weaken the deletion gate. The\n\t\t// removed state itself derives from the entry's registration.\n\t\t// Assumption (documented on IdentityMap): repositories key the\n\t\t// map with the same concrete class their factories produce.\n\t\t// Deleted aggregates stay in the harvest set: their recorded\n\t\t// deletion events must reach the outbox (repository.md, hard-\n\t\t// delete with event harvest). withCommit receives them in the\n\t\t// deleted token disposition, so the saved-only application observer\n\t\t// never fires for a deletion.\n\t\tthis._identityMap.delete(definition.aggregate, aggregate.id);\n\t\tthis._commitTokens.add(token);\n\t\treturn token;\n\t}\n\n\t/**\n\t * End-of-run safety net. A loaded aggregate whose version or pending event\n\t * batch changed without `update` intent would otherwise be silently lost.\n\t * An aggregate that changed after registration could persist state and\n\t * events from different moments. Both violations reject inside the\n\t * transaction.\n\t */\n\tpublic assertReadyToCommit(): void {\n\t\tfor (const entry of this._trackedAggregates) {\n\t\t\tif (entry.registration !== undefined) {\n\t\t\t\tthis.assertUnchangedAfterRegistration(entry);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t// Capture-to-capture drift against the load-time baseline: a\n\t\t\t// full-replacement model's changes() is never empty, which would\n\t\t\t// misreport every merely-loaded aggregate as unenrolled changes.\n\t\t\tif (\n\t\t\t\tentry.lifecycle === \"loaded\" &&\n\t\t\t\t(entry.aggregate.version !== entry.expectedVersion ||\n\t\t\t\t\tpersistenceProjectionDrifted(entry.baseline, entry.aggregate))\n\t\t\t) {\n\t\t\t\tthrow new UnenrolledChangesError(String(entry.aggregate.id));\n\t\t\t}\n\t\t}\n\n\t\tfor (const instance of this._identityMap.instancesWithNewPendingEvents()) {\n\t\t\t// Any registration (add, update, or remove) means the instance is\n\t\t\t// enrolled and its batch will be harvested.\n\t\t\tif (\n\t\t\t\tinstance !== null &&\n\t\t\t\ttypeof instance === \"object\" &&\n\t\t\t\tthis.registrationOf(instance) !== undefined\n\t\t\t) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t// Events were recorded on a loaded aggregate after it was\n\t\t\t// registered, yet it has no write intent: a forgotten update whose\n\t\t\t// events would be silently dropped.\n\t\t\tconst id = (instance as { id?: unknown }).id;\n\t\t\tthrow new UnenrolledChangesError(String(id));\n\t\t}\n\t}\n\n\t/** Flushes every registered receipt in deterministic registration order. */\n\tpublic async flush(transaction: unknown): Promise<void> {\n\t\tthis.assertOpen(\"unitOfWork.flush\");\n\t\tfor (const entry of this._registeredWrites) {\n\t\t\tconst registration = entry.registration;\n\t\t\tif (registration === undefined) {\n\t\t\t\tthrow new AggregateTrackingError(\n\t\t\t\t\tString(entry.aggregate.id),\n\t\t\t\t\t\"commit\",\n\t\t\t\t\t\"mutated_after_registration\",\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst write = Object.freeze({\n\t\t\t\tintent: registration.intent,\n\t\t\t\taggregateId: entry.aggregate.id,\n\t\t\t\texpectedVersion: entry.expectedVersion,\n\t\t\t\tversion: registration.version,\n\t\t\t\tchanges: registration.changes,\n\t\t\t\tevents: registration.events,\n\t\t\t}) as AggregatePersistenceWrite<Aggregate<Id<string>, Evt>, unknown>;\n\t\t\ttry {\n\t\t\t\tawait entry.definition.flush(transaction, write);\n\t\t\t} catch (error) {\n\t\t\t\tthrow mapRepositoryPersistenceError(entry.definition, error, write);\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic get commitTokens(): ReadonlyArray<AggregateCommitToken<Evt>> {\n\t\treturn [...this._commitTokens];\n\t}\n\n\tpublic close(): void {\n\t\tthis._closed = true;\n\t\t// Defensive: a leaked direct IdentityMap reference must not serve\n\t\t// stale instances into a later operation (that would silently\n\t\t// bypass OCC). The session getter already throws after close;\n\t\t// clearing covers refs captured before.\n\t\tthis._identityMap.clear();\n\t\tthis._trackedAggregates.clear();\n\t\tthis._registeredWrites.length = 0;\n\t\tthis._commitTokens.clear();\n\t}\n\n\tpublic assertOpen(operation: string): void {\n\t\tif (this._closed) {\n\t\t\tthrow new TransactionClosedError(operation);\n\t\t}\n\t}\n}\nfunction mapRepositoryPersistenceError<Evt extends AnyDomainEvent>(\n\tdefinition: RuntimePersistenceDefinition<Evt>,\n\terror: unknown,\n\twrite: AggregatePersistenceWrite<Aggregate<Id<string>, Evt>, unknown>,\n): InfrastructureError {\n\tlet mapped: unknown;\n\ttry {\n\t\tmapped = definition.mapError(error, write);\n\t} catch (mapperError) {\n\t\tthrow new RepositoryErrorMappingFailedError({\n\t\t\taggregateId: String(write.aggregateId),\n\t\t\tintent: write.intent,\n\t\t\tpersistenceError: error,\n\t\t\tmapperError,\n\t\t});\n\t}\n\t// Copy-safe: an adapter package can carry its own copy of the kit, whose\n\t// InfrastructureError fails a plain instanceof here; rejecting it would\n\t// turn every retryable conflict into a non-retryable wiring crash that\n\t// blames a correct mapper.\n\tif (isInfrastructureErrorLike(mapped)) return mapped;\n\tthrow new RepositoryErrorMappingFailedError({\n\t\taggregateId: String(write.aggregateId),\n\t\tintent: write.intent,\n\t\tpersistenceError: error,\n\t\tmapperError: new TypeError(\n\t\t\t\"Repository mapError must return an InfrastructureError instance\",\n\t\t),\n\t});\n}\n","import type { Aggregate, Version } from \"../../domain/aggregate/aggregate\";\nimport type { AnyDomainEvent } from \"../../domain/event/domain-event\";\nimport type { Id } from \"../../domain/identity/id\";\nimport {\n\tAggregateDeletedError,\n\tEventHarvestError,\n\ttype InfrastructureError,\n} from \"../../errors/kit-errors\";\nimport { abortReason } from \"../../internal/async/abort\";\nimport type { ExecutionContext } from \"../../internal/async/execution\";\nimport {\n\thasCooperativeBrand,\n\tstampCooperativeBrand,\n} from \"../../internal/cooperative-brand\";\nimport type { EventBus } from \"../../messaging/event-bus/ports\";\nimport type { OutboxWriter } from \"../../messaging/outbox/ports\";\nimport type { AggregateClass } from \"../../persistence/repository/identity-map\";\nimport type { PersistenceModel } from \"../../persistence/repository/persistence-model\";\nimport type { TransactionScope } from \"../../persistence/repository/scope\";\nimport { withCommit } from \"../cqrs/handler\";\nimport {\n\tCommitError,\n\tInvalidRepositoryDefinitionError,\n\tNestedUnitOfWorkError,\n\tRollbackError,\n\tTransactionClosedError,\n} from \"./errors\";\nimport type {\n\tAggregatePersistenceWrite,\n\tRepositoryTracking,\n\tRuntimePersistenceDefinition,\n} from \"./persistence-contract\";\nimport { bindRepositoryWrites } from \"./repository-facade\";\nimport { Session } from \"./unit-of-work-session\";\n\ninterface RuntimeRepositoryDefinition<Evt extends AnyDomainEvent, TCtx>\n\textends RuntimePersistenceDefinition<Evt> {\n\treadonly create: (\n\t\ttransaction: TCtx,\n\t\ttracking: RepositoryTracking<Aggregate<Id<string>, Evt>>,\n\t) => unknown;\n}\n\n/**\n * What the application work callback receives: repositories already bound to\n * the live Unit of Work plus cooperative cancellation.\n *\n * The adapter-only transaction and tracking capability are deliberately absent.\n * Exposing either would let application code bypass repository lifecycle\n * registration and would leak infrastructure types into the use case.\n */\nexport interface UnitOfWorkContext<TRepos> {\n\treadonly repositories: TRepos;\n\n\t/**\n\t * The cooperative-cancellation signal passed to {@link UnitOfWork.run},\n\t * or `undefined` if none was given. Poll `signal?.aborted` between\n\t * steps of a long operation and throw `signal.reason` to bail out; the\n\t * throw rolls the unit of work back like any other callback error. The\n\t * kit does not interrupt an in-flight query for you: actual query\n\t * cancellation depends on the `TransactionScope` honoring the signal.\n\t */\n\treadonly signal?: AbortSignal;\n}\n\n/** Options for a single {@link UnitOfWork.run} call. */\nexport interface RunOptions {\n\t/**\n\t * Cooperative-cancellation signal. If already aborted, `run()` rejects\n\t * with the signal's `reason` before opening a transaction. Otherwise it\n\t * is exposed on the context (poll `context.signal`) and forwarded to the\n\t * `TransactionScope`. Use `AbortSignal.timeout(ms)` for a deadline.\n\t */\n\treadonly signal?: AbortSignal;\n}\n\n// Shared across package copies like every other kit brand: a definition\n// built by a bundled plugin copy's defineRepository must be accepted by the\n// host copy's UnitOfWork. The key version stamps the definition SHAPE; bump\n// it when the definition contract changes so an incompatible copy fails the\n// generic not-a-definition check instead of half-working.\nconst repositoryDefinitionBrand: unique symbol = Symbol.for(\n\t\"@shirudo/ddd-kit/repository-definition/v1\",\n);\n\n/** Adapter wiring accepted by {@link defineRepository}. */\nexport interface RepositoryDefinitionOptions<\n\tTCtx,\n\tTRepositoryPort extends object,\n\tTAggregate extends Aggregate<Id<string>, AnyDomainEvent>,\n\tTBaseline,\n\tTChangeSet,\n\tTRemoval extends boolean = false,\n> {\n\t/** Concrete aggregate class used as the Identity Map key. */\n\treadonly aggregate: AggregateClass<TAggregate>;\n\t/** Adapter-owned projection, baseline, and change-set policy. */\n\treadonly persistence: PersistenceModel<TAggregate, TBaseline, TChangeSet>;\n\t/**\n\t * Creates the transaction-bound adapter for the port's non-lifecycle\n\t * methods. The Unit of Work supplies `add`, `update`, and optional `remove`.\n\t */\n\treadonly create: (\n\t\ttransaction: TCtx,\n\t\ttracking: RepositoryTracking<TAggregate>,\n\t) => Omit<TRepositoryPort, \"add\" | \"update\" | \"remove\">;\n\t/**\n\t * Performs the registered write during the Unit of Work's commit phase.\n\t *\n\t * The receipt contains adapter-owned changes and immutable persistence\n\t * facts, never the mutable aggregate instance. The transaction remains open\n\t * while this function and the outbox write run.\n\t */\n\treadonly flush: (\n\t\ttransaction: NoInfer<TCtx>,\n\t\twrite: AggregatePersistenceWrite<TAggregate, TChangeSet>,\n\t) => void | Promise<void>;\n\t/**\n\t * Translates every adapter/driver failure from `flush` into an explicit\n\t * application-facing infrastructure error. Returning or throwing a raw\n\t * driver error is a wiring failure and is rejected by the Unit of Work.\n\t */\n\treadonly mapError: (\n\t\terror: unknown,\n\t\twrite: AggregatePersistenceWrite<TAggregate, TChangeSet>,\n\t) => InfrastructureError;\n\t/** Adds Unit-of-Work-owned `remove` to the application-facing repository. */\n\treadonly physicalRemoval?: TRemoval;\n}\n\n/** Complete, helper-created definition for one Unit-of-Work repository. */\nexport interface RepositoryDefinition<\n\tTCtx,\n\tTRepositoryPort extends object,\n\tTAggregate extends Aggregate<Id<string>, AnyDomainEvent>,\n\tTBaseline,\n\tTChangeSet,\n\tTRemoval extends boolean = false,\n> extends RepositoryDefinitionOptions<\n\t\tTCtx,\n\t\tTRepositoryPort,\n\t\tTAggregate,\n\t\tTBaseline,\n\t\tTChangeSet,\n\t\tTRemoval\n\t> {\n\t/** Nominal marker installed by {@link defineRepository}. */\n\treadonly [repositoryDefinitionBrand]: true;\n}\n\n/** @inline */\ntype CallableValue = (...args: never[]) => unknown;\n\n/** @inline */\ntype RepositoryDefinitionBuilder<TRepositoryPort extends object> = <\n\tTAggregate extends Aggregate<Id<string>, AnyDomainEvent>,\n\tTCreate extends (\n\t\ttransaction: never,\n\t\ttracking: RepositoryTracking<TAggregate>,\n\t) => Omit<TRepositoryPort, \"add\" | \"update\" | \"remove\">,\n\tTBaseline,\n\tTChangeSet,\n\tTRemoval extends boolean = false,\n>(\n\tdefinition: RepositoryDefinitionOptions<\n\t\tParameters<TCreate>[0],\n\t\tTRepositoryPort,\n\t\tTAggregate,\n\t\tTBaseline,\n\t\tTChangeSet,\n\t\tTRemoval\n\t> & {\n\t\treadonly create: TCreate;\n\t} & (TRepositoryPort extends AggregateWriteRegistration<TAggregate>\n\t\t\t? TRemoval extends true\n\t\t\t\t? TRepositoryPort extends PhysicalRemovalRegistration<TAggregate>\n\t\t\t\t\t? unknown\n\t\t\t\t\t: never\n\t\t\t\t: TRepositoryPort extends PhysicalRemovalRegistration<TAggregate>\n\t\t\t\t\t? never\n\t\t\t\t\t: unknown\n\t\t\t: never),\n) => RepositoryDefinition<\n\tParameters<TCreate>[0],\n\tTRepositoryPort,\n\tTAggregate,\n\tTBaseline,\n\tTChangeSet,\n\tTRemoval\n>;\n\n/**\n * Defines repository wiring for an application-owned driven port.\n *\n * The first call makes the port explicit; the second infers the transaction,\n * aggregate, persistence, event, and removal types from the adapter wiring.\n * The port must declare `add` and `update`; if it declares `remove`, the\n * definition must set `physicalRemoval: true`. The adapter created by the\n * definition implements only the remaining methods because lifecycle writes\n * are installed by the Unit of Work.\n * The returned definition is the only form accepted by {@link UnitOfWork}; a\n * raw adapter-shaped object cannot silently turn its concrete surface into the\n * application contract.\n */\nfunction assertRepositoryDefinitionMembers(\n\tdefinition: Record<PropertyKey, unknown>,\n): void {\n\tfor (const key of [\"create\", \"flush\", \"mapError\"] as const) {\n\t\tif (typeof definition[key] !== \"function\") {\n\t\t\tthrow new TypeError(\n\t\t\t\t`defineRepository: \"${key}\" is missing or not a function on the ` +\n\t\t\t\t\t\"definition. The builder copies own enumerable properties only; \" +\n\t\t\t\t\t\"prototype methods and non-enumerable members are not carried. \" +\n\t\t\t\t\t\"Pass a plain object literal.\",\n\t\t\t);\n\t\t}\n\t}\n\tif (typeof definition.aggregate !== \"function\") {\n\t\tthrow new TypeError(\n\t\t\t'defineRepository: \"aggregate\" is missing or not a class reference ' +\n\t\t\t\t\"on the definition. Pass a plain object literal with own \" +\n\t\t\t\t\"enumerable properties.\",\n\t\t);\n\t}\n\tif (\n\t\tdefinition.persistence === null ||\n\t\ttypeof definition.persistence !== \"object\"\n\t) {\n\t\tthrow new TypeError(\n\t\t\t'defineRepository: \"persistence\" is missing or not a ' +\n\t\t\t\t\"PersistenceModel on the definition. Pass a plain object literal \" +\n\t\t\t\t\"with own enumerable properties.\",\n\t\t);\n\t}\n}\n\nexport function defineRepository<TRepositoryPort extends object>(): Extract<\n\tTRepositoryPort,\n\tCallableValue\n> extends never\n\t? RepositoryDefinitionBuilder<TRepositoryPort>\n\t: never {\n\tconst builder = (definition: object): object => {\n\t\tconst branded = { ...definition };\n\t\t// Validated AFTER the spread, on what actually survives it: the\n\t\t// spread copies own enumerable properties only, so create/flush/\n\t\t// mapError carried on a prototype (class instance) or as\n\t\t// non-enumerable members vanish silently. Without this check, the\n\t\t// loss surfaces as a bare TypeError deep inside the first run().\n\t\tassertRepositoryDefinitionMembers(branded as Record<PropertyKey, unknown>);\n\t\tstampCooperativeBrand(branded, repositoryDefinitionBrand);\n\t\treturn Object.freeze(branded);\n\t};\n\treturn builder as unknown as Extract<\n\t\tTRepositoryPort,\n\t\tCallableValue\n\t> extends never\n\t\t? RepositoryDefinitionBuilder<TRepositoryPort>\n\t\t: never;\n}\n\n/** Application-facing repositories inferred from their adapter definitions. */\nexport type RepositoriesOf<TDefinitions> = {\n\t[K in keyof TDefinitions]: RepositoryFacadeOf<TDefinitions[K]>;\n};\n\n/**\n * Preserves each concrete repository definition while rejecting incomplete\n * entries, callable adapter results, and definitions whose transaction context\n * or aggregate event family does not belong to the Unit of Work that owns them.\n */\nexport type CompatibleRepositoryDefinitions<\n\tEvt extends AnyDomainEvent,\n\tTCtx,\n\tTDefinitions,\n> = {\n\t[K in keyof TDefinitions]: TDefinitions[K] extends RepositoryDefinition<\n\t\tinfer TDefinitionContext,\n\t\tinfer _TRepositoryPort,\n\t\tinfer TAggregate,\n\t\tinfer _TBaseline,\n\t\tinfer _TChangeSet,\n\t\tinfer _TRemoval\n\t>\n\t\t? TAggregate extends Aggregate<Id<string>, infer TDefinitionEvent>\n\t\t\t? [TDefinitionEvent] extends [Evt]\n\t\t\t\t? TCtx extends TDefinitionContext\n\t\t\t\t\t? TDefinitions[K]\n\t\t\t\t\t: never\n\t\t\t\t: never\n\t\t\t: never\n\t\t: never;\n};\n\n/** @inline */\ntype RepositoryFacadeOf<TDefinition> =\n\tTDefinition extends RepositoryDefinition<\n\t\tinfer _TCtx,\n\t\tinfer TRepositoryPort,\n\t\tinfer _TAggregate,\n\t\tinfer _TBaseline,\n\t\tinfer _TChangeSet,\n\t\tinfer _TRemoval\n\t>\n\t\t? TRepositoryPort\n\t\t: never;\n\n/** Unit-of-Work-owned writes added to every application repository facade. */\nexport interface AggregateWriteRegistration<\n\tTAggregate extends Aggregate<Id<string>, AnyDomainEvent>,\n> {\n\tadd(aggregate: TAggregate): void;\n\tupdate(aggregate: TAggregate): void;\n}\n\n/** Optional physical removal added only by an explicit repository definition. */\nexport interface PhysicalRemovalRegistration<\n\tTAggregate extends Aggregate<Id<string>, AnyDomainEvent>,\n> {\n\tremove(aggregate: TAggregate): void;\n}\n\n/** Dependencies for {@link UnitOfWork}; the app-level singleton part. */\nexport interface UnitOfWorkDeps<\n\tEvt extends AnyDomainEvent,\n\tTCtx,\n\tTDefinitions extends Record<string, unknown>,\n> {\n\tscope: TransactionScope<TCtx>;\n\t/**\n\t * The write half of the outbox; see `WithCommitDeps.outbox` for the\n\t * required-vs-optional-bus asymmetry and the explicit opt-out\n\t * (`outboxWriterAcceptingEventLoss`).\n\t */\n\toutbox: OutboxWriter<Evt>;\n\tbus?: EventBus<Evt>;\n\t/** See `withCommit`: observer for post-commit `bus.publish` failures. */\n\tonPublishError?: (error: unknown, events: ReadonlyArray<Evt>) => void;\n\t/**\n\t * See `withCommit`: application-shell observer after acknowledgement.\n\t * The version argument is captured before any observer runs; the context\n\t * carries the bounded post-commit execution signal and deadline.\n\t */\n\tonPersisted?: (\n\t\taggregate: Aggregate<Id<string>, Evt>,\n\t\tversion: Version,\n\t\tcontext: ExecutionContext,\n\t) => void | Promise<void>;\n\t/**\n\t * See `withCommit`: failure observer for internal post-commit\n\t * acknowledgement/disposal and the application-shell `onPersisted`\n\t * callback. Never rejects the committed write.\n\t */\n\tonPersistError?: (\n\t\terror: unknown,\n\t\taggregate: Aggregate<Id<string>, Evt>,\n\t) => void;\n\t/**\n\t * See `withCommit`: one total budget shared by the complete post-commit\n\t * application phase. Default `30000`ms.\n\t */\n\tpostCommitTimeoutMs?: number;\n\trepositories: CompatibleRepositoryDefinitions<Evt, TCtx, TDefinitions>;\n}\n\n/**\n * Explicit-intent Unit of Work: one `run()` call is one application-level\n * write operation. All repository writes inside the callback share one\n * transaction and either persist completely or not at all.\n *\n * Built ON TOP of `withCommit` - the commit orchestration (event\n * harvest into the outbox inside the transaction, internal acknowledgement\n * after the commit, best-effort in-process publish last) is inherited,\n * not reimplemented. What this layer adds:\n *\n * - **Tx-bound repository adapters via a registry.** The callback receives\n * application-facing repository facades and never sees the raw transaction\n * or tracking capability.\n * - **Unit-of-Work-owned writes.** Standard `add`, `update`, and `remove`\n * methods register lifecycle intent. Adapter implementations with those\n * names are not invoked through the facade.\n * - **Lifecycle errors.** {@link NestedUnitOfWorkError},\n * {@link TransactionClosedError}, {@link CommitError},\n * {@link RollbackError}, {@link AggregateDeletedError}.\n *\n * - **A per-operation Identity Map and expected-version receipt.** Read paths\n * call `trackLoaded` before returning an aggregate. The Unit of Work then\n * owns the one-instance rule and the optimistic-concurrency expectation.\n * - **Persistence-last guard.** Once write intent is registered, a later\n * version or event-batch change rejects the operation before commit.\n *\n * Nested transactions, savepoints, and transaction joining remain outside\n * this boundary. One `run()` is one consistency transaction.\n *\n * **Instance discipline:** one instance owns one logical operation at\n * a time. `run()` while a run is active throws\n * {@link NestedUnitOfWorkError} - that covers genuine nesting AND two\n * concurrent requests sharing one instance, which is the same bug in\n * different clothes. Construct one `UnitOfWork` per operation\n * (construction stores one reference; the shareable singleton is the\n * deps object). Sequential reuse of an instance is fine.\n *\n * **Error pass-through:** an error thrown by the work callback (a\n * repository's `ConcurrencyConflictError`, a `DomainError`, anything)\n * is rethrown UNCHANGED - the unit of work never converts a concurrency\n * conflict into a generic error. Only the two failure modes the\n * callback cannot observe are wrapped: see {@link CommitError} and\n * {@link RollbackError}.\n *\n * @example\n * ```ts\n * const deps = {\n * scope: drizzleScope,\n * outbox: drizzleOutbox,\n * bus: eventBus,\n * repositories: {\n * restaurants: restaurantRepositoryDefinition,\n * },\n * };\n *\n * const uow = new UnitOfWork(deps);\n * const result = await uow.run(async ({ repositories }) => {\n * const restaurant = await repositories.restaurants.getById(id);\n * restaurant.changeOpeningHours(openingHours);\n * repositories.restaurants.update(restaurant);\n * return restaurant.id;\n * });\n * ```\n */\nexport class UnitOfWork<\n\tEvt extends AnyDomainEvent,\n\tTCtx,\n\tTDefinitions extends Record<string, unknown>,\n> {\n\tprivate _active = false;\n\n\tconstructor(private readonly deps: UnitOfWorkDeps<Evt, TCtx, TDefinitions>) {}\n\n\t/**\n\t * Execute one unit of work: open the transaction, hand the callback\n\t * tx-bound repositories, commit on resolve, roll back on throw,\n\t * run the post-commit lifecycle (acknowledge, observe, publish) for every\n\t * enrolled aggregate. Returns the callback's result.\n\t */\n\tpublic async run<R>(\n\t\twork: (\n\t\t\tcontext: UnitOfWorkContext<RepositoriesOf<TDefinitions>>,\n\t\t) => Promise<R>,\n\t\toptions?: RunOptions,\n\t): Promise<R> {\n\t\t// Pre-flight: an already-aborted caller rejects with the signal's\n\t\t// reason before opening a transaction (no callback runs). Placed\n\t\t// before the active-guard so a doubly-bad call (aborted signal on an\n\t\t// already-running instance) is reported as aborted rather than as a\n\t\t// nesting error. The `??` fallback mirrors event-bus.ts and guards a\n\t\t// non-spec polyfill whose `reason` is undefined.\n\t\tif (options?.signal?.aborted) {\n\t\t\tthrow abortReason(\n\t\t\t\toptions.signal,\n\t\t\t\t\"UnitOfWork.run aborted before opening a transaction\",\n\t\t\t);\n\t\t}\n\t\tif (this._active) {\n\t\t\tthrow new NestedUnitOfWorkError();\n\t\t}\n\t\tthis._active = true;\n\n\t\tlet session: Session<Evt> | undefined;\n\t\tlet workCompleted = false;\n\t\tlet workThrew = false;\n\t\tlet workError: unknown;\n\n\t\ttry {\n\t\t\treturn await withCommit<Evt, R, TCtx>(\n\t\t\t\t{\n\t\t\t\t\toutbox: this.deps.outbox,\n\t\t\t\t\tbus: this.deps.bus,\n\t\t\t\t\tscope: this.deps.scope,\n\t\t\t\t\tonPublishError: this.deps.onPublishError,\n\t\t\t\t\tonPersisted: this.deps.onPersisted,\n\t\t\t\t\tonPersistError: this.deps.onPersistError,\n\t\t\t\t\tpostCommitTimeoutMs: this.deps.postCommitTimeoutMs,\n\t\t\t\t\tsignal: options?.signal,\n\t\t\t\t},\n\t\t\t\tasync (tx, enrollment) => {\n\t\t\t\t\t// Fresh state per scope invocation: a TransactionScope that\n\t\t\t\t\t// retries its callback (serialization-failure retry wrappers)\n\t\t\t\t\t// re-runs this fn, and state from the rolled-back attempt\n\t\t\t\t\t// (enrollments, identity-map entries, error flags) must not\n\t\t\t\t\t// leak into the retry. The previous attempt's session is\n\t\t\t\t\t// closed so its leaked contexts turn loud.\n\t\t\t\t\tsession?.close();\n\t\t\t\t\tconst s = new Session<Evt>(enrollment);\n\t\t\t\t\tsession = s;\n\t\t\t\t\tworkCompleted = false;\n\t\t\t\t\tworkThrew = false;\n\t\t\t\t\tworkError = undefined;\n\n\t\t\t\t\tconst repositories = this.buildRepositories(tx, s);\n\t\t\t\t\tconst context = makeContext(repositories, s, options?.signal);\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst result = await work(context);\n\t\t\t\t\t\t// Validate tracking before sealing: a loaded aggregate that\n\t\t\t\t\t\t// changed without update intent would otherwise be lost.\n\t\t\t\t\t\t// Throws inside\n\t\t\t\t\t\t// the transaction, so the unit of work rolls back.\n\t\t\t\t\t\ts.assertReadyToCommit();\n\t\t\t\t\t\tawait s.flush(tx);\n\t\t\t\t\t\t// A flush may yield to the event loop. Re-check before the\n\t\t\t\t\t\t// transaction is allowed to commit so leaked concurrent work\n\t\t\t\t\t\t// cannot mutate an already registered aggregate mid-flush.\n\t\t\t\t\t\ts.assertReadyToCommit();\n\t\t\t\t\t\tworkCompleted = true;\n\t\t\t\t\t\t// Seal immediately: the aggregates snapshot below is what\n\t\t\t\t\t\t// gets harvested. A late registration from work still in\n\t\t\t\t\t\t// flight must throw\n\t\t\t\t\t\t// TransactionClosedError instead of being silently\n\t\t\t\t\t\t// accepted-but-never-harvested.\n\t\t\t\t\t\tconst commits = s.commitTokens;\n\t\t\t\t\t\ts.close();\n\t\t\t\t\t\treturn { result, commits };\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\tworkThrew = true;\n\t\t\t\t\t\tworkError = error;\n\t\t\t\t\t\tthrow error;\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tthrow classifyRunError(error, {\n\t\t\t\tworkThrew,\n\t\t\t\tworkCompleted,\n\t\t\t\tworkError,\n\t\t\t\tsignal: options?.signal,\n\t\t\t});\n\t\t} finally {\n\t\t\tsession?.close();\n\t\t\tthis._active = false;\n\t\t}\n\t}\n\n\tprivate buildRepositories(\n\t\ttx: TCtx,\n\t\tsession: Session<Evt>,\n\t): RepositoriesOf<TDefinitions> {\n\t\tconst repositories = {} as RepositoriesOf<TDefinitions>;\n\t\tfor (const key of Object.keys(this.deps.repositories) as Array<\n\t\t\tkeyof TDefinitions\n\t\t>) {\n\t\t\tconst candidate = this.deps.repositories[key] as unknown;\n\t\t\tif (!isRepositoryDefinition(candidate)) {\n\t\t\t\tthrow new InvalidRepositoryDefinitionError(String(key));\n\t\t\t}\n\t\t\tconst definition = candidate as RuntimeRepositoryDefinition<Evt, TCtx>;\n\t\t\tconst adapter = definition.create(tx, session.trackingFor(definition));\n\t\t\trepositories[key] = bindRepositoryWrites(\n\t\t\t\tadapter,\n\t\t\t\tsession,\n\t\t\t\tdefinition,\n\t\t\t\tString(key),\n\t\t\t) as RepositoriesOf<TDefinitions>[typeof key];\n\t\t}\n\t\treturn repositories;\n\t}\n}\n\nfunction isRepositoryDefinition(value: unknown): value is object {\n\treturn hasCooperativeBrand(value, repositoryDefinitionBrand);\n}\n\nfunction makeContext<TRepos, Evt extends AnyDomainEvent>(\n\trepositories: TRepos,\n\tsession: Session<Evt>,\n\tsignal: AbortSignal | undefined,\n): UnitOfWorkContext<TRepos> {\n\treturn {\n\t\tget repositories(): TRepos {\n\t\t\tsession.assertOpen(\"context.repositories\");\n\t\t\treturn repositories;\n\t\t},\n\t\t// The caller's own signal: exposed directly, not gated by\n\t\t// assertOpen, so polling `aborted` after close stays harmless.\n\t\tsignal,\n\t};\n}\n\n/**\n * Classifies a `withCommit` rejection into the error `run()` should throw,\n * using the flags captured inside the work wrapper. Pure and total: it\n * returns the error to throw rather than throwing itself, so `run()` reads\n * as orchestration and this decision is unit-testable in isolation.\n *\n * - `workThrew`: the work callback (or `assertReadyToCommit`) threw.\n * The scope normally rethrows that error unchanged (rolled back, pass\n * through so a `ConcurrencyConflictError` & co. stay catchable as-is); a\n * scope that WRAPS the original is detected via the cause chain and also\n * passed through. Only a rejection that neither IS nor wraps the\n * callback's error indicates the rollback itself failed, which becomes a\n * {@link RollbackError}.\n * - `workCompleted`: the callback finished; the failure is post-completion.\n * A harvest-guard violation (an event missing aggregateId / aggregateType,\n * or an eventful persisted aggregate that did not advance its version) is a deterministic\n * programming bug, surfaced as its {@link EventHarvestError} (which does\n * NOT extend `InfrastructureError`, so a retry-on-Infrastructure handler\n * skips it). It is thrown inside `scope.transactional()`, so a wrapping\n * scope can nest it: walk the chain rather than a bare `instanceof`. Only\n * genuinely unforeseeable post-completion failures (outbox write, the\n * commit itself) become {@link CommitError}.\n * - Neither flag set: `withCommit` rejected before the callback ran (the\n * scope failed to even open a transaction); pass the error through.\n */\nfunction classifyRunError(\n\terror: unknown,\n\tstate: {\n\t\treadonly workThrew: boolean;\n\t\treadonly workCompleted: boolean;\n\t\treadonly workError: unknown;\n\t\treadonly signal: AbortSignal | undefined;\n\t},\n): unknown {\n\t// Cancellation wins over the attempt flags: a scope that rejects with\n\t// the caller's abort reason between retry attempts never re-enters the\n\t// work callback, so workThrew/workError still describe the PREVIOUS\n\t// attempt. Classifying by those stale flags would mislabel the abort as\n\t// a RollbackError carrying a retryable cause, inviting a retry of an\n\t// explicitly cancelled operation.\n\tif (\n\t\tstate.signal?.aborted &&\n\t\tstate.signal.reason !== undefined &&\n\t\t(error === state.signal.reason ||\n\t\t\tcauseChainContains(error, state.signal.reason))\n\t) {\n\t\treturn error;\n\t}\n\tif (state.workThrew) {\n\t\tif (\n\t\t\terror === state.workError ||\n\t\t\tcauseChainContains(error, state.workError)\n\t\t) {\n\t\t\treturn error;\n\t\t}\n\t\treturn new RollbackError(state.workError, error);\n\t}\n\tif (state.workCompleted) {\n\t\tconst harvestError = findHarvestErrorInChain(error);\n\t\tif (harvestError) {\n\t\t\treturn harvestError;\n\t\t}\n\t\treturn new CommitError(error);\n\t}\n\treturn error;\n}\n\n/**\n * Cycle-safe, getter-throw-safe walk over `error`'s standard `cause`\n * chain. `visit` runs for every object link (the top error included) and\n * receives the link plus its lazily read `cause`; a non-undefined return\n * stops the walk. A throwing `cause` getter (lazy deserialization, revoked\n * Proxy) ends the walk as no-match instead of replacing the real failure\n * with the getter's exception.\n */\nfunction findInCauseChain<T>(\n\terror: unknown,\n\tvisit: (link: object, cause: unknown) => T | undefined,\n): T | undefined {\n\tconst seen = new Set<unknown>();\n\tlet current: unknown = error;\n\twhile (\n\t\tcurrent !== null &&\n\t\ttypeof current === \"object\" &&\n\t\t!seen.has(current)\n\t) {\n\t\tseen.add(current);\n\t\tlet cause: unknown;\n\t\ttry {\n\t\t\tcause = (current as { cause?: unknown }).cause;\n\t\t} catch {\n\t\t\treturn undefined;\n\t\t}\n\t\tconst found = visit(current, cause);\n\t\tif (found !== undefined) return found;\n\t\tcurrent = cause;\n\t}\n\treturn undefined;\n}\n\n/**\n * Walks `error`'s `cause` chain and returns the first `EventHarvestError`,\n * or `undefined`. `withCommit` throws the harvest-guard error INSIDE\n * `scope.transactional`, so a wrapping scope can nest it; matching\n * only the top-level error would let the wrapper mask the non-retryable\n * type. `withCommit` and `run()` share this module, so the local\n * `instanceof` is reliable for the un-wrapped link.\n */\nfunction findHarvestErrorInChain(\n\terror: unknown,\n): EventHarvestError | undefined {\n\treturn findInCauseChain(error, (link) =>\n\t\tlink instanceof EventHarvestError ? link : undefined,\n\t);\n}\n\n/**\n * Whether `error`'s `cause` chain contains `target` by reference. A\n * `target` of `undefined`/`null` never matches: every error without a\n * `cause` property would otherwise \"contain\" a thrown `undefined`.\n */\nfunction causeChainContains(error: unknown, target: unknown): boolean {\n\tif (target === undefined || target === null) {\n\t\treturn false;\n\t}\n\treturn (\n\t\tfindInCauseChain(error, (_link, cause) =>\n\t\t\tcause === target ? true : undefined,\n\t\t) ?? false\n\t);\n}\n","import type { Result } from \"@shirudo/result\";\nimport { type DomainError, InvalidVersionError } from \"../../errors/kit-errors\";\nimport type { AnyDomainEvent, PendingDomainEvent } from \"../event/domain-event\";\nimport type { Id } from \"../identity/id\";\n\n// --- Aggregate types ---\n\nexport type Version = number & { readonly __v: true };\n\n/**\n * Brands a stored number as an aggregate {@link Version}. A version is a\n * safe integer of at least zero. Use it in repository adapters instead of\n * a cast, so a corrupt row value fails here with {@link InvalidVersionError}\n * and never reaches the optimistic-concurrency cursor.\n */\nexport function toVersion(value: number): Version {\n\tif (!Number.isSafeInteger(value) || value < 0) {\n\t\tthrow new InvalidVersionError(\n\t\t\tvalue,\n\t\t\t\"is not a safe integer of at least zero\",\n\t\t);\n\t}\n\treturn value as Version;\n}\n\n/**\n * Snapshot of an aggregate state at a specific point in time.\n * Used for optimizing event replay by starting from a snapshot\n * instead of replaying all events from the beginning.\n *\n * @template TState - The type of the aggregate state\n */\nexport interface AggregateSnapshot<TState> {\n\t/**\n\t * The state of the aggregate at the time of the snapshot.\n\t */\n\treadonly state: TState;\n\n\t/**\n\t * The version of the aggregate when the snapshot was taken.\n\t */\n\treadonly version: Version;\n\n\t/**\n\t * Timestamp when the snapshot was created.\n\t */\n\treadonly snapshotAt: Date;\n\n\t/**\n\t * Schema version of the stored `state` shape, declared and stamped by\n\t * the persistence adapter that captures the snapshot. Distinct from\n\t * {@link version}, which counts mutations: this field says \"which\n\t * shape does the stored state have\", so a restore can detect a\n\t * snapshot written against an older DTO shape and migrate or\n\t * discard it instead of crashing later. Optional: a snapshot without\n\t * this field restores as schema `1`. Distinct also from\n\t * `DomainEvent.schemaVersion`, which versions one event payload shape.\n\t * A payload change and a snapshot state change bump their own field.\n\t */\n\treadonly schemaVersion?: number;\n}\n\n/**\n * Public contract every Aggregate Root satisfies. Implemented by\n * `BaseAggregate` and inherited by both `StateStoredAggregate` and\n * `EventSourcedAggregate`. Repository ports use this interface as their\n * aggregate type rather than depending on concrete base classes, so persistence\n * orchestration does not take a compile-time\n * dependency on the aggregate hierarchy.\n *\n * Full per-member documentation lives on the concrete `BaseAggregate`\n * class; the interface is intentionally terse to avoid drift. Persistence\n * facts are readable, but acknowledgement and pending-event disposal are not\n * part of this surface. The application shell holds that authority.\n *\n * @template TId - The aggregate root identifier (branded via `Id<Tag>`)\n * @template TEvent - The domain-event union, defaults to `never`\n */\nexport interface Aggregate<\n\tTId extends Id<string>,\n\tTEvent extends AnyDomainEvent = never,\n> {\n\treadonly id: TId;\n\treadonly version: Version;\n\treadonly pendingEvents: ReadonlyArray<PendingDomainEvent<TEvent>>;\n}\n\n/**\n * Public contract for Event-Sourced Aggregate Roots. Extends\n * `Aggregate` with the replay-from-history boundary.\n *\n * @template TId - The aggregate root identifier\n * @template TEvent - The union type of all domain events\n */\nexport interface ReplayableAggregate<\n\tTId extends Id<string>,\n\tTEvent extends AnyDomainEvent,\n> extends Aggregate<TId, TEvent> {\n\t/**\n\t * Reconstitutes the aggregate from an event history. Returns\n\t * `Result` because event-stream corruption is an expected\n\t * recoverable failure at the infrastructure boundary: a `DomainError`\n\t * thrown by a fold arrives as `Err`. Every other failure propagates\n\t * after the all-or-nothing rollback.\n\t *\n\t * @throws ForeignEventError when a history event names another aggregate\n\t * @throws UnreplayableAggregateError when the target carries pending\n\t * decisions, or a fold records one\n\t * @throws MissingFoldError when no fold is declared for an event type\n\t * @throws FoldReturnedNoStateError when a fold returns `undefined`\n\t * @throws HostileStateKeyError when the folded state carries an own\n\t * `__proto__` key\n\t */\n\treplayHistory(history: ReadonlyArray<TEvent>): Result<void, DomainError>;\n}\n\n/**\n * Checks if two aggregates are at the same version (same ID and version).\n * Useful for optimistic concurrency control checks.\n *\n * Note: Two aggregates with the same ID ARE the same aggregate (identity).\n * This function checks if they are at the same version: i.e., no concurrent modification.\n *\n * @example\n * ```typescript\n * const before = await repository.findById(id);\n * // ... some operations ...\n * const after = await repository.findById(id);\n *\n * if (!sameVersion(before, after)) {\n * throw new Error(\"Aggregate was modified by another process\");\n * }\n * ```\n */\nexport function sameVersion<TId extends Id<string>>(\n\ta: { id: TId; version: Version },\n\tb: { id: TId; version: Version },\n): boolean {\n\treturn a.id === b.id && a.version === b.version;\n}\n","/**\n * Entity utilities and interfaces for Domain-Driven Design.\n *\n * In Domain-Driven Design, there are two types of entities:\n *\n * 1. **Aggregate Root Entity**: The parent Entity of an aggregate.\n * - Has identity (id), state, and version\n * - Implemented by classes extending `StateStoredAggregate` or `EventSourcedAggregate`\n * - Represents the aggregate externally\n * - Loaded/saved through repositories\n *\n * 2. **Child Entities**: Entities within an aggregate.\n * - Have identity (id) and state, but no own version\n * - Can extend `Entity<TState, TId>` for class-based entities\n * - Or use functional style with `Identifiable<TId> & TProps`\n * - Exist only within the aggregate boundary\n * - Versioned through the Aggregate Root\n * - Cannot be referenced directly from outside the aggregate\n *\n * This module provides:\n * - `Entity<TState, TId>` - Base class for entities with state\n * - `EntityConfig` - Construction options (validation and opt-in deep freeze)\n * - `Identifiable<TId>` - Minimal interface for objects with id\n * - Helper functions for working with collections of entities\n *\n * @example\n * ```typescript\n * // Class-based child entity with logic\n * const validateOrderItemState = (state: OrderItemState): void => {\n * if (state.quantity < 1) throw new Error(\"quantity must be positive\");\n * };\n *\n * class OrderItem extends Entity<OrderItemState, ItemId> {\n * constructor(id: ItemId, initialState: OrderItemState) {\n * super(id, initialState, { validateState: validateOrderItemState });\n * }\n *\n * updateQuantity(quantity: number): void {\n * // setState validates the next state and freezes it.\n * this.setState({ ...this.state, quantity });\n * }\n *\n * calculateSubtotal(): number {\n * return this.state.price * this.state.quantity;\n * }\n * }\n *\n * // Functional-style child entity (simpler, no logic)\n * type OrderItem = Identifiable<ItemId> & {\n * productId: string;\n * quantity: number;\n * price: number;\n * };\n *\n * // Aggregate Root (Entity with version)\n * class Order extends StateStoredAggregate<OrderState, OrderId> {\n * // Order is an Aggregate Root Entity\n * // OrderState contains OrderItem child entities\n * }\n * ```\n */\nimport {\n\tassertNoHostileOwnProtoKey,\n\tMissingEntityIdError,\n\tUnmanagedInstanceError,\n} from \"../../errors/kit-errors\";\nimport type { Id } from \"../identity/id\";\nimport { deepFreeze } from \"../value-object/value-object\";\n\n/** A pure invariant check that throws when a candidate state is invalid. */\nexport type StateValidator<TState> = (state: TState) => void;\n\n/**\n * Construction options shared by `Entity` and (via `AggregateConfig`) the\n * aggregate base classes.\n */\nexport interface EntityConfig<TState = unknown> {\n\t/**\n\t * Pure state-invariant validator captured by the entity instance. It runs\n\t * against the exact frozen copy the entity stores, during construction,\n\t * every {@link Entity.setState} call, and the event-sourced apply path.\n\t * Throw to reject the candidate state. A validator that tries to mutate\n\t * the candidate fails loudly, because the candidate is already frozen.\n\t *\n\t * Passing validation as data avoids virtual dispatch from the base\n\t * constructor: the function cannot observe partly initialised subclass\n\t * fields through `this`. Close over immutable policy supplied to the\n\t * concrete constructor when validation needs instance-specific inputs.\n\t */\n\treadonly validateState?: StateValidator<TState>;\n\n\t/**\n\t * Opt-in: freeze the WHOLE state graph (via `deepFreeze`) instead of\n\t * the default shallow freeze. This protects against nested aliases\n\t * retained by constructor callers and against accidental in-place\n\t * writes inside the entity; live state itself is never public.\n\t *\n\t * Defaults to `false` (the documented shallow contract). A deep freeze\n\t * walks the part of the graph the write changed: subtrees the kit\n\t * already deep-froze are skipped, so `{ ...state, status }` costs the\n\t * root object. A write that replaces a large subtree walks that subtree.\n\t *\n\t * **Only for plain-data states.** The deep freeze walks the entire\n\t * graph: a class-based child entity inside the state would be frozen\n\t * too, and its own mutation methods would start throwing. States\n\t * carrying class-based children must keep the default shallow freeze.\n\t * Note that the ownership transfer widens accordingly: nested objects\n\t * passed into the constructor or `setState` are frozen IN PLACE (the\n\t * shallow copy protects only the top-level input object).\n\t *\n\t * Under the shallow freeze a nested object of the state stays open. A\n\t * fold or a validator that writes into it in place changes the state\n\t * the entity already holds, and no gate sees the write. The\n\t * event-sourced replay rollback restores the previous state object by\n\t * reference, so such a write survives the rollback. The deep freeze\n\t * makes the write throw at the write site.\n\t */\n\tdeepFreezeState?: boolean;\n\n\t/**\n\t * For reconstitution factories only: the initial state is a persisted\n\t * fact, like an event history, so {@link validateState} does not run\n\t * on it. Every later {@link Entity.setState} call and every\n\t * event-sourced apply still runs the validator. Without this option a\n\t * rule that tightened after a snapshot was taken makes every restore of\n\t * that snapshot throw. Never pass it for a new aggregate: a factory\n\t * yields valid objects only. The structural gates (frozen copy, hostile\n\t * own-key check) run regardless.\n\t */\n\ttrustInitialState?: boolean;\n}\n\n/**\n * Functional definition of an Entity via its capability: an object is\n * identifiable if it has an `id`.\n *\n * `TId` is constrained to `Id<string>` so the brand discipline that\n * `Id<Tag>` enforces is preserved end-to-end: an `Identifiable<UserId>`\n * cannot accidentally be paired with an `Identifiable<OrderId>` or with\n * a plain `string`.\n */\nexport type Identifiable<TId extends Id<string>> = {\n\treadonly id: TId;\n};\n\n/**\n * Interface for Entities with state.\n *\n * In Domain-Driven Design, Entities have:\n * - Identity (id): Distinguishes one entity from another\n * - State: The attributes/properties of the entity\n *\n * Unlike Value Objects (which are immutable and compared by value),\n * Entities are compared by identity and can have mutable state.\n *\n * @template TId - The type of the entity identifier\n */\nexport interface IEntity<TId extends Id<string>> extends Identifiable<TId> {\n\t/**\n\t * Unique identifier of the entity.\n\t */\n\treadonly id: TId;\n}\n\n/**\n * Freezes `value` by the entity's configured mode. The default is a\n * shallow freeze. When {@link EntityConfig.deepFreezeState} was enabled\n * at construction, the mode is `deepFreeze`. It does not store the value.\n * The event-sourced `apply` freezes the fold result first, then validates\n * it. So the object that passed validation is the object that\n * {@link storeTrustedState} stores.\n *\n * @internal Shared by the kit's own entity subclasses; not part of the\n * public API.\n */\nexport let freezeEntityState: <TState>(\n\tentity: Entity<TState, Id<string>>,\n\tvalue: TState,\n) => TState;\n\n/**\n * Stores a state that is accepted fact. The event-sourced replay stores\n * history through it. The event-sourced `apply` stores a state that it\n * validated on its own path. The instance-bound\n * {@link EntityConfig.validateState} does not run. The value is frozen by\n * the configured mode and becomes the entity's own state without a copy.\n * A value that is frozen already is stored as is. So the write cannot\n * throw, and a caller may write the version first and store second.\n *\n * Bound in the static block of {@link Entity}, so it reaches the private\n * fields. A subclass cannot redirect it, unlike a protected method.\n *\n * @internal Shared by the kit's own entity subclasses; not part of the\n * public API.\n */\nexport let storeTrustedState: <TState>(\n\tentity: Entity<TState, Id<string>>,\n\ttrusted: TState,\n) => void;\n\n/**\n * Abstract base class for Entities with state.\n *\n * Provides:\n * - Identity management (id)\n * - State management\n * - Instance-bound pure state validation\n * - Protected state access for domain behavior\n *\n * This is the foundation for all Entities in DDD:\n * - Child Entities within aggregates can extend this\n * - Aggregate Roots extend this and add version + events\n *\n * @template TState - The type of the entity state\n * @template TId - The type of the entity identifier\n *\n * @example\n * ```typescript\n * // Child Entity within an aggregate\n * const validateOrderItemState = (state: OrderItemState): void => {\n * if (state.quantity < 1) throw new Error(\"quantity must be positive\");\n * };\n *\n * class OrderItem extends Entity<OrderItemState, ItemId> {\n * constructor(id: ItemId, initialState: OrderItemState) {\n * super(id, initialState, { validateState: validateOrderItemState });\n * }\n *\n * updateQuantity(quantity: number): void {\n * // setState validates the next state and freezes it.\n * this.setState({ ...this.state, quantity });\n * }\n * }\n * ```\n */\nexport abstract class Entity<TState, TId extends Id<string>>\n\timplements IEntity<TId>\n{\n\tpublic readonly id: TId;\n\n\t/**\n\t * Returns the live state to subclass domain behavior.\n\t *\n\t * This accessor is deliberately protected: returning the generic\n\t * `TState` publicly would expose the aggregate's live object graph and\n\t * let nested mutation bypass behavior, validation, versioning, and\n\t * dirty tracking. Concrete entities should expose business-meaningful queries or\n\t * detached immutable DTOs (`deepFreeze(detachState(this.state))` for a\n\t * plain-data state). Snapshot projection belongs to the persistence\n\t * adapter, which captures the aggregate from outside through those\n\t * queries and DTOs rather than asking the entity to create its own\n\t * persistence memento.\n\t */\n\tprotected get state(): TState {\n\t\treturn this._state;\n\t}\n\n\t/**\n\t * Private, so a subclass writes only through {@link setState}. The\n\t * kit's own replay path stores accepted history through\n\t * {@link storeTrustedState}, which skips the validator.\n\t */\n\tprivate _state: TState;\n\n\tprivate readonly _stateFreezeMode: StateFreezeMode;\n\n\t// The kit-internal writers reach the private fields from here. A\n\t// subclass cannot override or observe them, unlike a protected method.\n\tstatic {\n\t\tfreezeEntityState = (entity, value) =>\n\t\t\tfreezeStateByMode(value, entity._stateFreezeMode);\n\t\tstoreTrustedState = (entity, trusted) => {\n\t\t\tentity._state = freezeStateByMode(trusted, entity._stateFreezeMode);\n\t\t};\n\t}\n\n\t/**\n\t * Declared and never assigned: a subclass that declares a member named\n\t * `validateState` (a method or a field) fails to compile against this\n\t * private member. The validator itself lives in a module-level map, so\n\t * the runtime ignores such a member anyway; this declaration turns the\n\t * silent no-op into a compile error.\n\t */\n\tprivate declare readonly validateState: never;\n\n\t/**\n\t * **State ownership.** Plain-object and array states are shallow-copied\n\t * before the freeze, so the caller's own object stays mutable. A CLASS\n\t * INSTANCE passed as state is an ownership transfer: it is frozen\n\t * in place (a copy would strip its prototype). Do not keep mutating\n\t * the instance after handing it to the entity. The same contract\n\t * applies to {@link setState}. With\n\t * {@link EntityConfig.deepFreezeState} enabled, the ownership transfer\n\t * widens to the whole graph: NESTED objects are frozen in place too.\n\t *\n\t * @throws MissingEntityIdError when `id` is not a non-blank string.\n\t * @throws HostileStateKeyError when a plain-object, null-prototype,\n\t * or array state carries an own `\"__proto__\"` data key; validate and\n\t * strip untrusted input at the boundary.\n\t */\n\tprotected constructor(\n\t\tid: TId,\n\t\tinitialState: TState,\n\t\tconfig?: EntityConfig<TState>,\n\t) {\n\t\tif (typeof id !== \"string\" || id.trim() === \"\") {\n\t\t\tthrow new MissingEntityIdError(id);\n\t\t}\n\t\tthis.id = id;\n\t\tthis._stateFreezeMode =\n\t\t\t(config?.deepFreezeState ?? false) ? \"deep\" : \"shallow\";\n\t\tstateValidators.set(\n\t\t\tthis,\n\t\t\t(config?.validateState ?? noStateValidation) as StateValidator<unknown>,\n\t\t);\n\t\t// Copy, freeze, validate, assign: the object validated IS the frozen\n\t\t// object stored, so a validator that tries to mutate it fails loudly.\n\t\t// The validator lives in a module-level map keyed by instance, and\n\t\t// the freeze helper is a module function, so a same-named member in a\n\t\t// JavaScript subclass cannot turn this constructor call into virtual\n\t\t// dispatch.\n\t\tconst initial = freezeStateByMode(\n\t\t\tshallowCopyOwned(initialState),\n\t\t\tthis._stateFreezeMode,\n\t\t);\n\t\tif (!(config?.trustInitialState ?? false)) {\n\t\t\tassertStateInvariant(this, initial);\n\t\t}\n\t\tthis._state = initial;\n\t}\n\n\t/**\n\t * Sets the state of the entity.\n\t * This is a convenience method for state mutations.\n\t * Automatically validates `newState` with the instance-bound\n\t * {@link EntityConfig.validateState} function.\n\t *\n\t * Plain-object and array states are shallow-copied before the freeze\n\t * (the caller's object stays mutable); a class-instance state is an\n\t * ownership transfer and is frozen in place; see the constructor.\n\t *\n\t * @param newState - The new state\n\t * @throws HostileStateKeyError when the state carries an own\n\t * `\"__proto__\"` data key; the previous state is kept.\n\t */\n\tprotected setState(newState: TState): void {\n\t\t// Same copy-freeze-validate-assign order as the constructor: the\n\t\t// object validated IS the frozen object stored, and a validation\n\t\t// throw leaves the previous state untouched.\n\t\tconst next = freezeStateByMode(\n\t\t\tshallowCopyOwned(newState),\n\t\t\tthis._stateFreezeMode,\n\t\t);\n\t\tassertStateInvariant(this, next);\n\t\tthis._state = next;\n\t}\n}\n\nconst noStateValidation: StateValidator<unknown> = () => {};\n\n/** The instance-bound validator of every constructed entity, keyed by instance. */\nconst stateValidators = new WeakMap<object, StateValidator<unknown>>();\n\n/**\n * Runs the entity's instance-bound {@link EntityConfig.validateState}\n * against a candidate state. The constructor, {@link Entity.setState}, and\n * the event-sourced apply path all use it. Replay skips it because history\n * is accepted fact. Call it with the exact frozen object that will be\n * stored, so a validator that tries to mutate it fails loudly.\n *\n * Deliberately a module-level function with a per-instance lookup. A\n * method could be overridden. A property could be shadowed by a subclass\n * field initializer that runs after `super()`. Neither can redirect this\n * lookup.\n *\n * @internal Shared by the kit's own entity subclasses; not part of the\n * public API.\n */\nexport function assertStateInvariant<TState>(\n\tentity: Entity<TState, Id<string>>,\n\tcandidate: TState,\n): void {\n\tconst validateState = stateValidators.get(entity);\n\tif (validateState === undefined) {\n\t\tthrow new UnmanagedInstanceError(\n\t\t\t\"assertStateInvariant\",\n\t\t\t\"entity\",\n\t\t\t(entity as { id?: unknown } | null)?.id,\n\t\t);\n\t}\n\tvalidateState(candidate);\n}\n\n/** The entity's configured freeze depth, fixed once at construction. */\ntype StateFreezeMode = \"shallow\" | \"deep\";\n\nfunction freezeStateByMode<TState>(\n\tvalue: TState,\n\tmode: StateFreezeMode,\n): TState {\n\treturn mode === \"deep\" ? (deepFreeze(value) as TState) : freezeShallow(value);\n}\n\n/**\n * Shallow-freezes `value` when it's a non-null object or array, so that\n * direct property writes throw in strict mode. Returns the value as-is for\n * primitives. `Entity` picks this or {@link deepFreeze} per the\n * `deepFreezeState` config, so state read through the `state` getter\n * cannot be mutated from outside, without a deep clone on every read.\n *\n * Subclass code stores state through `setState`, which freezes by the\n * configured mode. The export remains for consumers using it as a\n * standalone utility.\n */\nexport function freezeShallow<T>(value: T): T {\n\tif (value !== null && typeof value === \"object\") {\n\t\treturn Object.freeze(value);\n\t}\n\treturn value;\n}\n\n/**\n * The hostile own-key guard for a state value that is about to be stored.\n * It checks the root object only, and only the shapes a JSON row can\n * produce: a plain object, a null-prototype object, or an array. A class\n * instance is an ownership transfer and passes. The constructor,\n * {@link Entity.setState}, and the event-sourced fold all use it, so the\n * depth and the shape rule cannot drift between the paths.\n *\n * @internal Shared by the kit's own entity subclasses; not part of the\n * public API.\n */\nexport function assertStateHasNoHostileOwnKey(\n\tstate: unknown,\n\tsubject: string,\n): void {\n\tif (state === null || typeof state !== \"object\") return;\n\tif (Array.isArray(state)) {\n\t\tassertNoHostileOwnProtoKey(state, subject);\n\t\treturn;\n\t}\n\tconst proto = Object.getPrototypeOf(state);\n\tif (proto !== Object.prototype && proto !== null) return;\n\tassertNoHostileOwnProtoKey(state, subject);\n}\n\n/**\n * Returns a shallow copy for plain objects and arrays so the subsequent\n * `freezeShallow` never locks the caller's own object in place (their later\n * writes to it would throw in strict mode). Class instances and primitives\n * pass through unchanged: a spread would strip an instance's prototype,\n * and handing a class instance as state is an ownership transfer. Nested\n * objects stay shared by design (shallow-freeze, no deep clone).\n */\nfunction shallowCopyOwned<T>(value: T): T {\n\tif (value === null || typeof value !== \"object\") return value;\n\tassertStateHasNoHostileOwnKey(value, \"Entity state\");\n\tif (Array.isArray(value)) {\n\t\t// Spread copies only iterated index elements; transfer own\n\t\t// enumerable NON-INDEX keys (items.total = 5 style annotations) as\n\t\t// data properties too, mirroring the plain-object branch, so the\n\t\t// copy never silently loses caller state.\n\t\tconst copy = [...value];\n\t\tfor (const key of Reflect.ownKeys(value)) {\n\t\t\tif (key === \"length\" || Object.hasOwn(copy, key)) continue;\n\t\t\tconst descriptor = Object.getOwnPropertyDescriptor(value, key);\n\t\t\tif (!descriptor?.enumerable) continue;\n\t\t\tObject.defineProperty(copy, key, {\n\t\t\t\tvalue: (value as Record<PropertyKey, unknown>)[key],\n\t\t\t\twritable: true,\n\t\t\t\tenumerable: true,\n\t\t\t\tconfigurable: true,\n\t\t\t});\n\t\t}\n\t\treturn copy as T;\n\t}\n\tconst proto = Object.getPrototypeOf(value);\n\tif (proto !== Object.prototype && proto !== null) return value;\n\t// Copy as data properties, never through [[Set]]: object spread uses\n\t// CreateDataProperty, so even without the guard above no key could\n\t// reach the `__proto__` setter the way Object.assign onto an\n\t// Object.prototype-based target would. On a null-prototype target no\n\t// setter exists in the chain, so Object.assign is safe there.\n\treturn (\n\t\tproto === null ? Object.assign(Object.create(null), value) : { ...value }\n\t) as T;\n}\n\n/**\n * Checks if two entities have the same ID.\n * Works with any object that has an 'id' property.\n *\n * @param a - First entity\n * @param b - Second entity\n * @returns true if both entities have the same ID, false otherwise\n *\n * @example\n * ```typescript\n * const item1: OrderItem = { id: itemId1, productId: \"prod-1\", quantity: 2 };\n * const item2: OrderItem = { id: itemId2, productId: \"prod-2\", quantity: 1 };\n *\n * sameEntity(item1, item2); // false\n * sameEntity(item1, item1); // true\n * ```\n */\nexport function sameEntity<TId extends Id<string>>(\n\ta: Identifiable<TId>,\n\tb: Identifiable<TId>,\n): boolean {\n\treturn a.id === b.id;\n}\n\n/**\n * Finds an entity by ID in a collection.\n * Returns undefined if not found.\n *\n * @param entities - Array of entities to search\n * @param id - The ID to search for\n * @returns The entity if found, undefined otherwise\n *\n * @example\n * ```typescript\n * const items: OrderItem[] = [\n * { id: itemId1, productId: \"prod-1\", quantity: 2 },\n * { id: itemId2, productId: \"prod-2\", quantity: 1 }\n * ];\n *\n * const item = findEntityById(items, itemId1);\n * // item is { id: itemId1, productId: \"prod-1\", quantity: 2 }\n * ```\n */\nexport function findEntityById<\n\tTId extends Id<string>,\n\tT extends Identifiable<TId>,\n>(entities: ReadonlyArray<T>, id: TId): T | undefined {\n\treturn entities.find((entity) => entity.id === id);\n}\n\n/**\n * Checks if an entity with the given ID exists in the collection.\n *\n * @param entities - Array of entities to search\n * @param id - The ID to check for\n * @returns true if an entity with the ID exists, false otherwise\n *\n * @example\n * ```typescript\n * const items: OrderItem[] = [\n * { id: itemId1, productId: \"prod-1\", quantity: 2 }\n * ];\n *\n * hasEntityId(items, itemId1); // true\n * hasEntityId(items, itemId2); // false\n * ```\n */\nexport function hasEntityId<\n\tTId extends Id<string>,\n\tT extends Identifiable<TId>,\n>(entities: ReadonlyArray<T>, id: TId): boolean {\n\treturn entities.some((entity) => entity.id === id);\n}\n\n/**\n * Removes an entity with the given ID from the collection. Returns the\n * ORIGINAL array when the id is absent (structural sharing for the\n * reference-based dirty tracking; see `updateEntityById`), otherwise a\n * new array without the entity.\n *\n * @param entities - Array of entities\n * @param id - The ID of the entity to remove\n * @returns A new array without the entity with the given ID\n *\n * @example\n * ```typescript\n * const items: OrderItem[] = [\n * { id: itemId1, productId: \"prod-1\", quantity: 2 },\n * { id: itemId2, productId: \"prod-2\", quantity: 1 }\n * ];\n *\n * const updated = removeEntityById(items, itemId1);\n * // updated is [{ id: itemId2, productId: \"prod-2\", quantity: 1 }]\n * ```\n */\nexport function removeEntityById<\n\tTId extends Id<string>,\n\tT extends Identifiable<TId>,\n>(entities: ReadonlyArray<T>, id: TId): ReadonlyArray<T> {\n\tconst filtered = entities.filter((entity) => entity.id !== id);\n\treturn filtered.length === entities.length ? entities : filtered;\n}\n\n/**\n * Updates an entity with the given ID in the collection.\n * Returns a new array with the updated entity.\n * Structural sharing for adapter-owned persistence projections: returns\n * the ORIGINAL array when nothing changed (no match, or the element kept\n * its reference), so a partial-write adapter can skip the untouched\n * collection; a new array only when an\n * element reference actually changed. The result is `ReadonlyArray<T>`:\n * it may BE the (possibly frozen) input; spread it if you need a mutable\n * copy.\n *\n * @param entities - Array of entities\n * @param id - The ID of the entity to update\n * @param updater - Function that takes the entity and returns the updated entity\n * @returns A new array with the updated entity\n *\n * @example\n * ```typescript\n * const items: OrderItem[] = [\n * { id: itemId1, productId: \"prod-1\", quantity: 2 }\n * ];\n *\n * const updated = updateEntityById(items, itemId1, (item) => ({\n * ...item,\n * quantity: item.quantity + 1\n * }));\n * // updated is [{ id: itemId1, productId: \"prod-1\", quantity: 3 }]\n * ```\n */\nexport function updateEntityById<\n\tTId extends Id<string>,\n\tT extends Identifiable<TId>,\n>(\n\tentities: ReadonlyArray<T>,\n\tid: TId,\n\tupdater: (entity: T) => T,\n): ReadonlyArray<T> {\n\tlet changed = false;\n\tconst mapped = entities.map((entity) => {\n\t\tif (entity.id !== id) return entity;\n\t\tconst next = updater(entity);\n\t\tif (next !== entity) changed = true;\n\t\treturn next;\n\t});\n\treturn changed ? mapped : entities;\n}\n\n/**\n * Replaces an entity with the given ID in the collection.\n * Returns a new array with the replaced entity.\n * Structural sharing for adapter-owned persistence projections: returns\n * the ORIGINAL array when nothing changed (no match, or the element kept\n * its reference), so a partial-write adapter can skip the untouched\n * collection; a new array only when an\n * element reference actually changed. The result is `ReadonlyArray<T>`:\n * it may BE the (possibly frozen) input; spread it if you need a mutable\n * copy.\n *\n * @param entities - Array of entities\n * @param id - The ID of the entity to replace\n * @param replacement - The replacement entity\n * @returns A new array with the replaced entity\n *\n * @example\n * ```typescript\n * const items: OrderItem[] = [\n * { id: itemId1, productId: \"prod-1\", quantity: 2 }\n * ];\n *\n * const updated = replaceEntityById(items, itemId1, {\n * id: itemId1,\n * productId: \"prod-1\",\n * quantity: 5\n * });\n * ```\n */\nexport function replaceEntityById<\n\tTId extends Id<string>,\n\tT extends Identifiable<TId>,\n>(entities: ReadonlyArray<T>, id: TId, replacement: T): ReadonlyArray<T> {\n\tlet changed = false;\n\tconst mapped = entities.map((entity) => {\n\t\tif (entity.id !== id) return entity;\n\t\tif (replacement !== entity) changed = true;\n\t\treturn replacement;\n\t});\n\treturn changed ? mapped : entities;\n}\n\n/**\n * Extracts all IDs from a collection of entities.\n *\n * @param entities - Array of entities\n * @returns Array of entity IDs\n *\n * @example\n * ```typescript\n * const items: OrderItem[] = [\n * { id: itemId1, productId: \"prod-1\", quantity: 2 },\n * { id: itemId2, productId: \"prod-2\", quantity: 1 }\n * ];\n *\n * const ids = entityIds(items);\n * // ids is [itemId1, itemId2]\n * ```\n */\nexport function entityIds<TId extends Id<string>, T extends Identifiable<TId>>(\n\tentities: ReadonlyArray<T>,\n): TId[] {\n\treturn entities.map((entity) => entity.id);\n}\n","import {\n\tDuplicateEventIdError,\n\tInvalidVersionError,\n\tMisaddressedEventError,\n\tPendingEventBatchMismatchError,\n\tPendingEventLimitExceededError,\n\tReentrantEventRecordingError,\n\tUnmintedEventError,\n\tUnreplayableAggregateError,\n} from \"../../errors/kit-errors\";\nimport { assertPositiveSafeInteger } from \"../../internal/validate\";\nimport { Entity, type EntityConfig } from \"../entity/entity\";\nimport {\n\ttype AnyDomainEvent,\n\ttype AnyUncommittedDomainEvent,\n\tadoptRecordedDomainEvent,\n\tadoptUncommittedDomainEvent,\n\ttype CreateUncommittedDomainEventOptions,\n\tcreateUncommittedDomainEvent,\n\tisRecordedDomainEvent,\n\tisUncommittedDomainEvent,\n\ttype PendingDomainEvent,\n\trecordDomainEvent,\n\ttype UncommittedDomainEventOf,\n} from \"../event/domain-event\";\nimport type { Id } from \"../identity/id\";\nimport { type Aggregate, toVersion, type Version } from \"./aggregate\";\nimport { registerPendingEventLifecycleCapability } from \"./pending-event-lifecycle\";\nimport {\n\ttype PendingEventStampFactory,\n\tregisterPendingEventRecordingCapability,\n} from \"./pending-event-recording\";\n\n/** Construction options shared by state-stored and event-sourced aggregates. */\nexport interface AggregateConfig<TState = unknown>\n\textends EntityConfig<TState> {\n\t/**\n\t * Limit on the pending list. A recording that would grow the list\n\t * past it throws {@link PendingEventLimitExceededError} before the\n\t * state moves, so the rejected decision records nothing and moves\n\t * nothing. Defaults to unlimited. The limit is a modelling signal: a\n\t * decision that emits hundreds of facts points at a missing aggregate\n\t * boundary, not at a limit that is too low. Must be a positive safe\n\t * integer when given.\n\t */\n\treadonly maxPendingEvents?: number;\n}\n\n/**\n * Shared base for both `StateStoredAggregate` (state-stored) and\n * `EventSourcedAggregate`. Carries the lifecycle machinery that's\n * identical across the two flavours: current version, pending-event\n * tracking, the kit-internal post-commit acknowledgement capability,\n * the `markReconstituted` post-load marker, and the `createEvent` helper\n * that auto-injects `aggregateId` + `aggregateType` on every event the\n * aggregate emits. The application shell records the pending decisions\n * with `recordPendingEvents` before persistence.\n *\n * Consumers do NOT extend this class directly; extend\n * `StateStoredAggregate` for state-stored aggregates or\n * `EventSourcedAggregate` for event-sourced ones. The split between\n * those two reflects the canonical Vernon §8 (state-stored) /\n * Vernon §11 + Greg Young (event-sourced) distinction in how state\n * is represented; the lifecycle machinery is the same for both.\n *\n * @template TState - The type of the aggregate state\n * @template TId - The aggregate root identifier\n * @template TEvent - The domain-event union. Defaults to `never` so\n * aggregates without a declared event type cannot emit events\n * (emitting any event becomes a compile error).\n */\nexport abstract class BaseAggregate<\n\t\tTState,\n\t\tTId extends Id<string>,\n\t\tTEvent extends AnyDomainEvent = never,\n\t>\n\textends Entity<TState, TId>\n\timplements Aggregate<TId, TEvent>\n{\n\t/**\n\t * The aggregate's domain type as a string, used to populate\n\t * `aggregateType` on events created via {@link createEvent}.\n\t *\n\t * Subclasses MUST declare this as a string literal:\n\t *\n\t * ```ts\n\t * class Order extends StateStoredAggregate<OrderState, OrderId, OrderEvent> {\n\t * protected readonly aggregateType = \"Order\";\n\t * }\n\t * ```\n\t *\n\t * The string is *the* identifier downstream consumers (outbox\n\t * dispatchers, projection handlers, audit logs) use to route by\n\t * aggregate kind. Use the same canonical name across your system;\n\t * matching the class name is the obvious choice, but the value\n\t * comes from this explicit declaration, not `constructor.name`\n\t * (which is fragile under minification, bundler transforms, and\n\t * subclass renaming).\n\t */\n\tprotected abstract readonly aggregateType: string;\n\n\tprivate _version: Version = 0 as Version;\n\n\t/**\n\t * Version the persistence layer last confirmed for this instance:\n\t * `undefined` until the aggregate is reconstituted (`markReconstituted`) or a\n\t * commit is acknowledged. Kit-internal via the lifecycle capability; it\n\t * grounds the application shell's unique-cursor guard, so an eventful\n\t * commit that did not advance beyond the persisted row is rejected\n\t * deterministically.\n\t */\n\tprivate _persistedVersion: Version | undefined;\n\n\tprivate _pendingEvents: PendingDomainEvent<TEvent>[] = [];\n\n\tprivate readonly _maxPendingEvents: number | undefined;\n\n\tprotected constructor(\n\t\tid: TId,\n\t\tinitialState: TState,\n\t\tconfig?: AggregateConfig<TState>,\n\t) {\n\t\t// The entity constructor freezes the initial state in place under\n\t\t// deepFreezeState. The config check runs before super(), so a\n\t\t// rejected config leaves the caller's state graph open.\n\t\tif (config?.maxPendingEvents !== undefined) {\n\t\t\tassertPositiveSafeInteger(\n\t\t\t\t\"Aggregate\",\n\t\t\t\t\"maxPendingEvents\",\n\t\t\t\tconfig.maxPendingEvents,\n\t\t\t);\n\t\t}\n\t\tsuper(id, initialState, config);\n\t\tthis._maxPendingEvents = config?.maxPendingEvents;\n\t\tregisterPendingEventLifecycleCapability(this, {\n\t\t\tacknowledge: (events, committedVersion) => {\n\t\t\t\tthis.acknowledgePendingEvents(events, committedVersion);\n\t\t\t},\n\t\t\tdiscardPendingEvents: (events) => {\n\t\t\t\tthis.discardPendingEventsAfterDeletion(events);\n\t\t\t},\n\t\t\tpersistedVersion: () => this._persistedVersion,\n\t\t\tpendingEventCount: () => this._pendingEvents.length,\n\t\t\taggregateType: () => this.aggregateType,\n\t\t});\n\t\tregisterPendingEventRecordingCapability(this, {\n\t\t\trecord: (createStamp) => this.recordPendingDecisions(createStamp),\n\t\t});\n\t}\n\n\t/**\n\t * Stamps every uncommitted decision in the pending list with identity\n\t * and time from `createStamp`, passes an already recorded event through,\n\t * and replaces the list atomically. Three guards run before the\n\t * assignment: an event that no kit constructor minted is rejected\n\t * ({@link UnmintedEventError}); a stamp provider that recorded a new\n\t * decision on this aggregate mid-map is rejected\n\t * ({@link ReentrantEventRecordingError}); and two decisions that\n\t * received one eventId are rejected ({@link DuplicateEventIdError}).\n\t * When a guard fires, every decision stays unrecorded.\n\t */\n\tprivate recordPendingDecisions(\n\t\tcreateStamp: PendingEventStampFactory,\n\t): ReadonlyArray<AnyDomainEvent> {\n\t\tconst stamped = this._pendingEvents;\n\t\tconst stampedCount = stamped.length;\n\t\tconst recorded: TEvent[] = stamped.map((event, index) => {\n\t\t\tconst candidate = event as AnyDomainEvent | AnyUncommittedDomainEvent;\n\t\t\tif (isRecordedDomainEvent(candidate)) return candidate as TEvent;\n\t\t\tif (!isUncommittedDomainEvent(candidate)) {\n\t\t\t\tthrow new UnmintedEventError((event as { readonly type: string }).type);\n\t\t\t}\n\t\t\treturn recordDomainEvent(\n\t\t\t\tcandidate,\n\t\t\t\tcreateStamp(candidate, index),\n\t\t\t) as TEvent;\n\t\t});\n\t\t// A stamp provider that triggers a new decision on this aggregate\n\t\t// grows or replaces the pending list mid-map; assigning `recorded`\n\t\t// would silently discard that decision.\n\t\tif (\n\t\t\tthis._pendingEvents !== stamped ||\n\t\t\tthis._pendingEvents.length !== stampedCount\n\t\t) {\n\t\t\tthrow new ReentrantEventRecordingError(String(this.id));\n\t\t}\n\t\t// One identity per decision: a reused stamp would mint two facts\n\t\t// sharing one eventId, and idempotent consumers keyed on it would\n\t\t// silently drop one.\n\t\tconst seenEventIds = new Set<string>();\n\t\tfor (const event of recorded) {\n\t\t\tconst eventId = (event as AnyDomainEvent).eventId;\n\t\t\tif (seenEventIds.has(eventId)) {\n\t\t\t\tthrow new DuplicateEventIdError(String(this.id), eventId);\n\t\t\t}\n\t\t\tseenEventIds.add(eventId);\n\t\t}\n\t\tthis._pendingEvents = recorded;\n\t\treturn Object.freeze(recorded.slice()) as ReadonlyArray<AnyDomainEvent>;\n\t}\n\n\tprivate acknowledgePendingEvents(\n\t\tevents: ReadonlyArray<unknown>,\n\t\tcommittedVersion: Version,\n\t): void {\n\t\t// Validate before anything moves: a rejected version leaves the\n\t\t// pending list and the marker untouched.\n\t\tconst persisted = toVersion(committedVersion);\n\t\tthis.stripAcknowledgedPrefix(events);\n\t\t// The next eventful commit needs a cursor beyond the version this\n\t\t// commit persisted. The caller passes the enrollment-time version:\n\t\t// syncing from the live version instead would let un-awaited\n\t\t// concurrent work that mutates the instance in the post-commit window\n\t\t// desync the marker.\n\t\tthis._persistedVersion = persisted;\n\t}\n\n\t/**\n\t * Post-commit cleanup for the deleted disposition. The row is gone, so\n\t * there is no persisted version to advance: stamping the marker from the\n\t * live instance would make a later legitimate re-enrollment of this\n\t * instance trip the unique-cursor guard for a row that does not exist.\n\t */\n\tprivate discardPendingEventsAfterDeletion(\n\t\tevents: ReadonlyArray<unknown>,\n\t): void {\n\t\tthis.stripAcknowledgedPrefix(events);\n\t}\n\n\tprivate stripAcknowledgedPrefix(events: ReadonlyArray<unknown>): void {\n\t\tif (\n\t\t\tevents.length > this._pendingEvents.length ||\n\t\t\tevents.some((event, index) => event !== this._pendingEvents[index])\n\t\t) {\n\t\t\tthrow new PendingEventBatchMismatchError(\n\t\t\t\tString(this.id),\n\t\t\t\tevents.length,\n\t\t\t\tthis._pendingEvents.length,\n\t\t\t);\n\t\t}\n\t\tthis._pendingEvents = this._pendingEvents.slice(events.length);\n\t}\n\n\tpublic get version(): Version {\n\t\treturn this._version;\n\t}\n\n\t/**\n\t * Read-only list of domain events recorded on this aggregate that\n\t * have not yet been flushed to the outbox / persistence layer.\n\t */\n\tpublic get pendingEvents(): ReadonlyArray<PendingDomainEvent<TEvent>> {\n\t\treturn Object.freeze(this._pendingEvents.slice());\n\t}\n\n\t/**\n\t * The one write path of the version: every bump and every\n\t * reconstitution goes through here, so a subclass that overrides it\n\t * observes every write. Rejects anything but a safe integer of at least\n\t * zero. An override must not throw: the callers write the version after\n\t * they validated the change, and a throw then leaves a state-stored\n\t * state already moved. The event-sourced `apply()` writes the version\n\t * before it moves state, so a throw there leaves nothing changed.\n\t */\n\tprotected setVersion(version: Version): void {\n\t\tthis._version = toVersion(version);\n\t}\n\n\t/**\n\t * Advances the version by one. Used by the state-stored `setState()`\n\t * path and by the event-sourced `apply()` path.\n\t */\n\tprotected bumpVersion(): void {\n\t\tthis.setVersion(this.nextVersion());\n\t}\n\n\t/** The version the next change writes; throws before anything moves. */\n\tprotected nextVersion(): Version {\n\t\treturn toVersion(this._version + 1);\n\t}\n\n\t/**\n\t * **Lifecycle marker, Post-Load.** Sets the current version and the\n\t * persisted-version marker to the stored version. Used by\n\t * `reconstitute(...)` factories to assemble an in-memory aggregate\n\t * from a persisted row.\n\t *\n\t * Three guards keep the marker honest. The instance must carry no\n\t * pending decisions, because a restore on a dirty instance would later\n\t * commit facts against a baseline they were never part of\n\t * ({@link UnreplayableAggregateError}). The version must be a safe\n\t * integer of at least zero, and it must not lie below the current\n\t * version ({@link InvalidVersionError}); a catch-up replay only moves\n\t * forward.\n\t *\n\t * The Factory-vs-Reconstitution distinction (Vernon §11) is honoured\n\t * structurally: reconstitution stays inside the aggregate factory while\n\t * post-commit acknowledgement belongs to application commit orchestration.\n\t *\n\t * If you override this, call `super.markReconstituted(version)` so the current\n\t * domain version remains aligned with the reconstituted facts.\n\t *\n\t * @param version - The version the row currently holds in the DB\n\t *\n\t * @example\n\t * ```ts\n\t * static reconstitute(id: OrderId, state: OrderState, version: Version): Order {\n\t * const order = new Order(id, state);\n\t * order.markReconstituted(version);\n\t * return order;\n\t * }\n\t * ```\n\t */\n\tprotected markReconstituted(version: Version): void {\n\t\tassertReplayTargetHasNoPendingEvents(this.id, this._pendingEvents.length);\n\t\tconst restored = toVersion(version);\n\t\tif (restored < this._version) {\n\t\t\tthrow new InvalidVersionError(\n\t\t\t\tversion,\n\t\t\t\t`is below the current version ${this._version}`,\n\t\t\t);\n\t\t}\n\t\tthis.setVersion(restored);\n\t\tthis._persistedVersion = restored;\n\t}\n\n\t/**\n\t * Appends a domain event to the pending list. The event must be minted\n\t * by a kit constructor; a missing `aggregateId` or `aggregateType` is\n\t * stamped from this aggregate, and an address that names another\n\t * aggregate throws {@link MisaddressedEventError} before anything is\n\t * recorded. Each append is one fact. A decision appended twice becomes\n\t * two facts with distinct ids. A recorded event that is already pending\n\t * throws {@link DuplicateEventIdError}, and a list at `maxPendingEvents`\n\t * throws {@link PendingEventLimitExceededError}, before anything is\n\t * recorded. Prefer the higher-level `StateStoredAggregate.setState()`\n\t * (state-stored) or `EventSourcedAggregate.apply()` (event-sourced) call\n\t * sites, both of which wrap `addDomainEvent` in the canonical\n\t * record-AFTER-mutation order (Vernon §8). Calling `addDomainEvent`\n\t * directly is appropriate only after a version-advancing state mutation,\n\t * or while constructing a never-persisted aggregate. An event-only commit\n\t * on an already-persisted aggregate has no unique cursor and the\n\t * application shell rejects it; use `setState(currentState, event)`.\n\t */\n\tprotected addDomainEvent(event: PendingDomainEvent<TEvent>): void {\n\t\tconst stamped = this.addressNewEvent(event);\n\t\tthis.assertEventIdsNotPending([stamped]);\n\t\tthis.assertPendingEventLimit(1);\n\t\tthis.appendStampedEvent(stamped);\n\t}\n\n\t/**\n\t * One identity per fact, checked before the change becomes observable:\n\t * a recorded event whose `eventId` is already pending, or appears twice\n\t * in one batch, throws {@link DuplicateEventIdError}. A decision has no\n\t * `eventId` yet, so a stamp provider that reuses one is caught at\n\t * recording instead.\n\t */\n\tprotected assertEventIdsNotPending(\n\t\tbatch: readonly PendingDomainEvent<TEvent>[],\n\t): void {\n\t\tconst pendingIds = new Set<string>();\n\t\tfor (const pending of this._pendingEvents) {\n\t\t\tif (isRecordedDomainEvent(pending)) pendingIds.add(pending.eventId);\n\t\t}\n\t\tfor (const event of batch) {\n\t\t\tif (!isRecordedDomainEvent(event)) continue;\n\t\t\tif (pendingIds.has(event.eventId)) {\n\t\t\t\tthrow new DuplicateEventIdError(String(this.id), event.eventId);\n\t\t\t}\n\t\t\tpendingIds.add(event.eventId);\n\t\t}\n\t}\n\n\t/**\n\t * The pending list stays within `maxPendingEvents`, checked before the\n\t * change becomes observable: a batch that would grow the list past the\n\t * limit throws {@link PendingEventLimitExceededError}. Without a limit\n\t * the check is a no-op.\n\t */\n\tprotected assertPendingEventLimit(added: number): void {\n\t\tconst limit = this._maxPendingEvents;\n\t\tif (limit === undefined) return;\n\t\tconst pending = this._pendingEvents.length;\n\t\tif (pending + added <= limit) return;\n\t\tthrow new PendingEventLimitExceededError({\n\t\t\taggregateType: this.aggregateType,\n\t\t\taggregateId: String(this.id),\n\t\t\tlimit,\n\t\t\tpending,\n\t\t\tadded,\n\t\t});\n\t}\n\n\t/**\n\t * Appends an event that the caller already passed through\n\t * {@link addressNewEvent}, {@link assertEventIdsNotPending} and\n\t * {@link assertPendingEventLimit}. `setState()` and `apply()` run the\n\t * three before the state moves and append afterwards, so each gate\n\t * runs once per event.\n\t */\n\tprotected appendStampedEvent(event: PendingDomainEvent<TEvent>): void {\n\t\tthis._pendingEvents.push(event);\n\t}\n\n\t/**\n\t * Drops every pending decision. Only the event-sourced replay rollback\n\t * uses it, after its guard proved the list empty before the replay\n\t * began; anything present at rollback time came from the failed replay.\n\t */\n\tprotected discardPendingDecisions(): void {\n\t\tthis._pendingEvents = [];\n\t}\n\n\t/**\n\t * Address discipline for NEW facts, shared by both flavours: a\n\t * present-but-foreign `aggregateId` / `aggregateType` is a wiring bug and\n\t * throws {@link MisaddressedEventError}; missing fields are filled in\n\t * from the aggregate, so a recorded event is always fully addressed and\n\t * can never fail the harvest or the replay guard later. The mint gate\n\t * runs first, so an unminted event fails before anything else. The\n\t * stamped copy is frozen like the original (payload and metadata are\n\t * shared, already deep-frozen by the constructors); a fully addressed\n\t * event is returned as is.\n\t */\n\tprotected addressNewEvent<E extends PendingDomainEvent<TEvent>>(event: E): E {\n\t\tthis.assertMintedEvent(event);\n\t\tconst { aggregateId, aggregateType } = event;\n\t\tconst idForeign = aggregateId !== undefined && aggregateId !== this.id;\n\t\tconst typeForeign =\n\t\t\taggregateType !== undefined && aggregateType !== this.aggregateType;\n\t\tif (idForeign || typeForeign) {\n\t\t\tthrow new MisaddressedEventError({\n\t\t\t\texpected: { aggregateType: this.aggregateType, aggregateId: this.id },\n\t\t\t\tactual: { aggregateType, aggregateId },\n\t\t\t\teventType: event.type,\n\t\t\t});\n\t\t}\n\t\tif (aggregateId !== undefined && aggregateType !== undefined) {\n\t\t\treturn event;\n\t\t}\n\t\t// The spread preserves the event's structural shape; TS cannot\n\t\t// prove it against the generic, so the copy goes through the\n\t\t// event's own wider type. `aggregateId`/`aggregateType` are\n\t\t// `string | undefined` on DomainEvent; filling them in cannot\n\t\t// leave the declared shape.\n\t\tconst copy = {\n\t\t\t...event,\n\t\t\taggregateId: this.id,\n\t\t\taggregateType: this.aggregateType,\n\t\t};\n\t\tconst stamped: AnyDomainEvent | AnyUncommittedDomainEvent =\n\t\t\tisRecordedDomainEvent(event)\n\t\t\t\t? adoptRecordedDomainEvent(copy)\n\t\t\t\t: adoptUncommittedDomainEvent(copy);\n\t\treturn stamped as E;\n\t}\n\n\t/**\n\t * Mint gate for every recording path: only an event that a kit\n\t * constructor produced passes. The kit marks two shapes: a recorded\n\t * event carries the recorded brand (`createDomainEvent`,\n\t * `createDomainEventFromFacts`) and a decision carries the uncommitted\n\t * brand (`createUncommittedDomainEvent`, the aggregate `createEvent`\n\t * helper). Either brand implies deeply frozen with defensively copied\n\t * payload and metadata, a guarantee no frozen-ness probe can establish\n\t * (a shallow-frozen literal with mutable nested data would fool it).\n\t * O(1): one brand check per shape.\n\t */\n\tprotected assertMintedEvent(event: PendingDomainEvent<TEvent>): void {\n\t\tif (!isRecordedDomainEvent(event) && !isUncommittedDomainEvent(event)) {\n\t\t\tthrow new UnmintedEventError(\n\t\t\t\t(event as AnyDomainEvent | AnyUncommittedDomainEvent).type,\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Creates the immutable business fact accepted by this aggregate without\n\t * reading a clock, generating an id, or attaching tracing metadata.\n\t *\n\t * The application shell records pending events after the domain operation\n\t * and before persistence. Payload schema version stays here, next to the\n\t * concrete event producer, rather than in shell-owned recording data.\n\t */\n\tprotected createEvent<E extends TEvent>(\n\t\ttype: E[\"type\"],\n\t\tpayload: E[\"payload\"],\n\t\toptions?: Omit<\n\t\t\tCreateUncommittedDomainEventOptions,\n\t\t\t\"aggregateId\" | \"aggregateType\"\n\t\t>,\n\t): UncommittedDomainEventOf<E> {\n\t\treturn createUncommittedDomainEvent(type, payload, {\n\t\t\t...options,\n\t\t\taggregateId: this.id,\n\t\t\taggregateType: this.aggregateType,\n\t\t}) as UncommittedDomainEventOf<E>;\n\t}\n}\n\n/**\n * Restore-target guard used by `markReconstituted` and by\n * `EventSourcedAggregate.replayHistory`: a target carrying unflushed\n * `pendingEvents` throws {@link UnreplayableAggregateError} BEFORE anything\n * moves. A restore advances the aggregate's current version, so unflushed\n * events recorded against the old version would later be harvested claiming\n * a version baseline they were never part of. When the discard is\n * deliberate, discard this dirty instance and reconstitute a fresh aggregate\n * instead of mutating persistence lifecycle state publicly.\n *\n * Deliberately a module-level function, not a class method: it MUST not be\n * overridable by consumer subclasses (a no-op override would silently\n * disable the guard at every call site). The callers pass the count of\n * the private list; the commit harvest reads the public `pendingEvents`\n * getter, so a subclass that overrides the getter changes the harvest,\n * not this guard.\n *\n * @internal Shared by the aggregate flavours in this package; not part of\n * the public API.\n */\nexport function assertReplayTargetHasNoPendingEvents(\n\tid: unknown,\n\tpending: number,\n): void {\n\tif (pending > 0) {\n\t\tthrow new UnreplayableAggregateError(\n\t\t\tString(id),\n\t\t\t`it carries ${pending} unflushed pending event(s) that are not ` +\n\t\t\t\t\"part of the persisted stream; discard this dirty instance and \" +\n\t\t\t\t\"reconstitute a fresh aggregate before restoring persisted history\",\n\t\t);\n\t}\n}\n","import { err, ok, type Result } from \"@shirudo/result\";\nimport {\n\tDirectStateMutationError,\n\ttype DomainError,\n\tFoldReturnedNoStateError,\n\tForeignEventError,\n\tisDomainErrorLike,\n\tMissingFoldError,\n} from \"../../errors/kit-errors\";\nimport {\n\tassertStateHasNoHostileOwnKey,\n\tassertStateInvariant,\n\tfreezeEntityState,\n\tstoreTrustedState,\n} from \"../entity/entity\";\nimport type {\n\tAnyDomainEvent,\n\tPendingDomainEvent,\n\tUncommittedDomainEventOf,\n} from \"../event/domain-event\";\nimport type { Id } from \"../identity/id\";\nimport type { ReplayableAggregate, Version } from \"./aggregate\";\nimport {\n\tassertReplayTargetHasNoPendingEvents,\n\tBaseAggregate,\n} from \"./base-aggregate\";\nimport { requirePendingEventLifecycleReadView } from \"./pending-event-lifecycle\";\n\ntype Fold<TState, TEvent> = (state: TState, event: TEvent) => TState;\n\n/**\n * Base class for Event-Sourced Aggregate Roots (Vernon, IDDD Chapter 8).\n *\n * Like `StateStoredAggregate`, this is both the root entity and the aggregate\n * boundary. The difference is persistence: state is derived from events,\n * not stored directly. Events are the single source of truth: all state\n * changes go through `apply()` and a fold.\n *\n * Extends `BaseAggregate` (the shared lifecycle machinery) but offers no\n * `setState()`, and the inherited `setState()` throws\n * `DirectStateMutationError`: the only way to change state is an event\n * folded through `apply()`, so the instance never runs ahead\n * of its stream.\n *\n * `apply()` and `validateEvent()` throw `DomainError`-derived exceptions\n * on invariant violations. Subclasses override `validateEvent()` to\n * throw their own concrete subclasses (e.g. `OrderAlreadyConfirmedError`).\n * Two gates guard a NEW fact: `validateEvent` checks the decision against\n * the current state before the fold, and the `validateState` function\n * from `AggregateConfig` checks the folded state after it, exactly as it\n * does for a state-stored `setState`. Replay through `replayHistory`\n * runs neither, because history is already accepted fact and rules change\n * over time; a stream that was valid when written must stay loadable under\n * tomorrow's rules. The infrastructure-boundary method `replayHistory`\n * returns `Result`: it catches `DomainError` during replay so callers can\n * react to corrupted event streams without try/catch.\n *\n * @template TState - The aggregate state (contains child entities and value objects)\n * @template TId - The aggregate root identifier\n * @template TEvent - The union type of all domain events\n *\n * @example\n * ```typescript\n * class OrderAlreadyConfirmedError extends DomainError<\"ORDER_ALREADY_CONFIRMED\"> {\n * constructor(id: OrderId) {\n * super({ code: \"ORDER_ALREADY_CONFIRMED\", message: `Order ${id} is already confirmed` });\n * }\n * }\n *\n * class Order extends EventSourcedAggregate<OrderState, OrderId, OrderEvent> {\n * protected readonly aggregateType = \"Order\";\n *\n * confirm(): void {\n * this.apply(\n * this.createEvent(\"OrderConfirmed\", { orderId: this.id }),\n * );\n * }\n *\n * protected validateEvent(event: OrderEvent): void {\n * if (event.type === \"OrderConfirmed\" && this.state.status === \"confirmed\") {\n * throw new OrderAlreadyConfirmedError(this.id);\n * }\n * }\n *\n * protected readonly folds = {\n * OrderConfirmed: (state: OrderState): OrderState => ({\n * ...state,\n * status: \"confirmed\",\n * }),\n * };\n * }\n * ```\n */\nexport abstract class EventSourcedAggregate<\n\t\tTState,\n\t\tTId extends Id<string>,\n\t\tTEvent extends AnyDomainEvent,\n\t>\n\textends BaseAggregate<TState, TId, TEvent>\n\timplements ReplayableAggregate<TId, TEvent>\n{\n\t/**\n\t * Validates a NEW event before `apply()` records it. Default is\n\t * no-op. Subclasses override to throw a concrete `DomainError`\n\t * subclass when the event violates an invariant in the current\n\t * state: the second net behind the command method's own guards.\n\t *\n\t * Replay never invokes this method. History is already accepted\n\t * fact, and decision rules evolve; re-checking yesterday's events\n\t * against today's rules would make legitimately persisted streams\n\t * unloadable after a rule change. Old storage shapes are not a\n\t * validation concern either: decode and upcast persisted events at\n\t * the read boundary (see the event-upcasting guide) so the folds\n\t * always receive the current event shape.\n\t */\n\tprotected validateEvent(_event: UncommittedDomainEventOf<TEvent>): void {}\n\n\t/**\n\t * Always throws {@link DirectStateMutationError}. An event-sourced\n\t * aggregate changes state only through `apply()`, where the fact is\n\t * recorded and the version advances with it.\n\t */\n\tprotected override setState(_newState: TState): void {\n\t\tthrow new DirectStateMutationError(String(this.id));\n\t}\n\n\t/**\n\t * Applies an event: validates the decision, locates the fold, computes\n\t * the next state, validates that state, then commits state + pending\n\t * event + version bump atomically.\n\t *\n\t * Throws `DomainError` (or a subclass) when `validateEvent` rejects the\n\t * decision. Throws whatever the `validateState` function throws when it\n\t * rejects the folded state.\n\t * Throws `MissingFoldError` if no fold is declared for `event.type`.\n\t * Throws `FoldReturnedNoStateError` (wiring) when the fold returns\n\t * `undefined`, the signature of a fold without a `return`.\n\t * Throws `MisaddressedEventError` (wiring) when the event carries an\n\t * `aggregateId` or `aggregateType` naming a different aggregate;\n\t * missing address fields are stamped from the aggregate instead.\n\t *\n\t * State is not mutated if any step throws: the fold is invoked into\n\t * a local and only stored once all checks pass.\n\t *\n\t * The method is generic in the event tag `K`, so concrete callers\n\t * (`this.apply(orderCreated)`) narrow to the literal tag and the\n\t * fold is typed as `Fold<TState, Extract<TEvent, { type: K }>>`,\n\t * with no `as` cast required at the call site.\n\t *\n\t * `apply()` is exclusively for NEW facts: it always records the event\n\t * and bumps the version. Replaying history is a different operation\n\t * with its own entry point, `replayHistory`.\n\t *\n\t * @param event - The domain event to apply\n\t */\n\tprotected apply<K extends TEvent[\"type\"]>(\n\t\tevent: PendingDomainEvent<Extract<TEvent, { type: K }>>,\n\t): void {\n\t\t// New facts get their address here, by construction: missing\n\t\t// fields are stamped from the aggregate (the createEvent\n\t\t// guarantee), a present-but-foreign address throws\n\t\t// MisaddressedEventError before anything is recorded. Without\n\t\t// this, a mis-addressed event would mutate state, version, and\n\t\t// pendingEvents and only fail later at harvest or on the next\n\t\t// load, poisoning the own stream.\n\t\tconst stamped = this.addressNewEvent(event);\n\t\tthis.assertEventIdsNotPending([stamped]);\n\t\tthis.assertPendingEventLimit(1);\n\t\t// Both gates run here, not in fold: apply checks only new facts\n\t\t// against the current rules, and replay trusts history. The order\n\t\t// is the one Entity.setState keeps: freeze, validate, store. The\n\t\t// object that passed validation is the object stored, and no step\n\t\t// below stores until both gates passed. Unlike setState there is\n\t\t// no defensive copy: the fold result is the aggregate's own next\n\t\t// state, so a rejected result stays frozen. The hostile own-key\n\t\t// guard runs on every new fact; replay runs it once on the final\n\t\t// state. The event was stamped above, so it is appended as is.\n\t\tthis.validateEvent(stamped as UncommittedDomainEventOf<TEvent>);\n\t\tconst next = freezeEntityState(this, this.fold(stamped));\n\t\t// A hostile row can reach the fold through the payload or its own\n\t\t// construction; the guard runs at the same depth and on the same\n\t\t// shapes as setState, on the state that is about to be stored.\n\t\tassertStateHasNoHostileOwnKey(next, \"Aggregate state\");\n\t\tassertStateInvariant(this, next);\n\t\t// The version write is the last step that can throw (an override of\n\t\t// setVersion). The store and the append run after it and cannot\n\t\t// throw.\n\t\tthis.bumpVersion();\n\t\tstoreTrustedState(this, next);\n\t\tthis.appendStampedEvent(stamped);\n\t}\n\n\t/**\n\t * Internal fold shared by `apply()` and `replayHistory`: locate the\n\t * fold and compute the next state. It deliberately does NOT assign\n\t * the state, record the event, bump the version, or run `validateEvent`\n\t * and `validateState`; `apply()` layers all of that on for new facts,\n\t * while replay assigns the fold result as is (the history is already\n\t * persisted, and validating it against current rules would reject\n\t * streams that were valid when written).\n\t * The replay loop iterates over `TEvent[]` and therefore cannot\n\t * supply a narrowed `K` generic, so this helper accepts `TEvent`\n\t * and the discriminator is resolved via the (statically-sound)\n\t * `folds` map.\n\t *\n\t * Replay address check: a history event that names a DIFFERENT\n\t * aggregate id or type is a persisted row that belongs to someone\n\t * else (a miswired stream read, colliding ids across types, a\n\t * corrupted store). Throws `ForeignEventError`, an\n\t * `InfrastructureError`, which PROPAGATES through the replay\n\t * methods (their `Result` channel is reserved for `DomainError`\n\t * stream corruption) after the all-or-nothing rollback. History\n\t * events without the optional address fields pass unchecked (the\n\t * fields are optional on the event shape); NEW events are covered\n\t * by the stricter `addressNewEvent` on the apply path.\n\t */\n\tprivate assertReplayedEventBelongsHere(event: TEvent): void {\n\t\tconst idMismatch =\n\t\t\tevent.aggregateId !== undefined && event.aggregateId !== this.id;\n\t\tconst typeMismatch =\n\t\t\tevent.aggregateType !== undefined &&\n\t\t\tevent.aggregateType !== this.aggregateType;\n\t\tif (idMismatch || typeMismatch) {\n\t\t\tthrow new ForeignEventError({\n\t\t\t\texpected: { aggregateType: this.aggregateType, aggregateId: this.id },\n\t\t\t\tactual: {\n\t\t\t\t\taggregateType: event.aggregateType,\n\t\t\t\t\taggregateId: event.aggregateId,\n\t\t\t\t},\n\t\t\t\teventType: event.type,\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate fold(event: TEvent | UncommittedDomainEventOf<TEvent>): TState {\n\t\t// Own-key guard: the folds map is an object literal, so a plain\n\t\t// property get for event.type === \"toString\" / \"constructor\" /\n\t\t// \"__proto__\" (a corrupt or adversarial stream row) would resolve\n\t\t// through Object.prototype and invoke a non-fold.\n\t\tconst fold = Object.hasOwn(this.folds, event.type)\n\t\t\t? (this.folds[event.type as keyof typeof this.folds] as Fold<\n\t\t\t\t\tTState,\n\t\t\t\t\tTEvent | UncommittedDomainEventOf<TEvent>\n\t\t\t\t>)\n\t\t\t: undefined;\n\t\tif (!fold) {\n\t\t\tthrow new MissingFoldError(event.type);\n\t\t}\n\n\t\tconst nextState = fold(this.state, event);\n\t\t// Only `undefined` is rejected: a primitive or `null` state is a\n\t\t// legal TState, a missing `return` is not.\n\t\tif (nextState === undefined) {\n\t\t\tthrow new FoldReturnedNoStateError(event.type);\n\t\t}\n\t\treturn nextState;\n\t}\n\n\t/**\n\t * Reconstitutes the aggregate from an event history. Catches `DomainError`\n\t * thrown during replay and returns it as an `Err`: this is the\n\t * infrastructure boundary, where event-stream corruption is an expected\n\t * recoverable failure. Unexpected (non-DomainError) throws propagate.\n\t *\n\t * All-or-nothing: if any event mid-stream throws, or the final restore\n\t * marker is rejected, the aggregate's state, version, and pending list\n\t * are rolled back to their pre-call values. Partial replay is never\n\t * observable. A fold that records a decision is the one way to make\n\t * the marker throw. The rollback restores the previous state object by\n\t * reference. Under the default shallow freeze a fold that writes into a\n\t * nested object of that state in place is not detected, and the write\n\t * survives the rollback; see `AggregateConfig.deepFreezeState`.\n\t *\n\t * Version advances additively: the aggregate's pre-existing version plus\n\t * `history.length`. A fresh aggregate (v=0) loading 3 events ends at v=3;\n\t * a reconstituted aggregate at v=P catching up on M newer events ends at\n\t * v=P+M. Events carry no stream position, so an overlap with the current\n\t * version is invisible here: the caller passes only the events after\n\t * that version and checks the final version against the pinned stream\n\t * head ({@link ReplayHeadMismatchError}).\n\t *\n\t * The replay target must not carry pending decisions. Factory-vs-load\n\t * lifecycle is owned by the Unit of Work rather than inferred from an\n\t * aggregate persistence flag.\n\t */\n\tpublic replayHistory(\n\t\thistory: ReadonlyArray<TEvent>,\n\t): Result<void, DomainError> {\n\t\tassertReplayTargetHasNoPendingEvents(\n\t\t\tthis.id,\n\t\t\trequirePendingEventLifecycleReadView(\n\t\t\t\tthis,\n\t\t\t\t\"replayHistory\",\n\t\t\t).pendingEventCount(),\n\t\t);\n\t\t// Empty stream: nothing was loaded, so preserve current state and version.\n\t\tif (history.length === 0) return ok();\n\n\t\tconst previousState = this.state;\n\t\tconst startVersion = this.version;\n\t\ttry {\n\t\t\tfor (const event of history) {\n\t\t\t\tthis.assertReplayedEventBelongsHere(event);\n\t\t\t\tstoreTrustedState(this, this.fold(event));\n\t\t\t}\n\t\t\t// Only the final fold result is stored, so the hostile own-key\n\t\t\t// guard runs once here instead of once per replayed event; a\n\t\t\t// rejection rolls back below like any other replay failure.\n\t\t\tassertStateHasNoHostileOwnKey(this.state, \"Aggregate state\");\n\t\t\t// Inside the try on purpose: a fold that records a decision\n\t\t\t// makes this throw, and the rollback below must cover that case\n\t\t\t// too.\n\t\t\tthis.markReconstituted((startVersion + history.length) as Version);\n\t\t} catch (e) {\n\t\t\tstoreTrustedState(this, previousState);\n\t\t\t// The fold itself never writes the version, but a fold that\n\t\t\t// records a decision bumps it through apply(); the rollback\n\t\t\t// writes the start version back through the same path.\n\t\t\tthis.setVersion(startVersion);\n\t\t\t// The guard above proved the pending list empty before the loop,\n\t\t\t// so anything in it now came from a fold that recorded a\n\t\t\t// decision; the rollback drops it too.\n\t\t\tthis.discardPendingDecisions();\n\t\t\t// Copy-safe: a fold may run in another loaded copy of the kit,\n\t\t\t// whose DomainError fails a plain instanceof; the Result channel\n\t\t\t// must carry it regardless.\n\t\t\tif (isDomainErrorLike(e)) return err(e);\n\t\t\tthrow e;\n\t\t}\n\t\treturn ok();\n\t}\n\n\t/**\n\t * One fold per event type: a pure function from the current state and\n\t * the event to the next state. Subclasses MUST implement this property.\n\t *\n\t * A fold returns the next state. `undefined` is rejected on both the\n\t * apply and the replay path as a missing `return`, so model an absent\n\t * state as `null` or as a status field, never as `undefined`.\n\t *\n\t * A fold MUST derive state from `type` and `payload` only. The\n\t * parameter is typed as the uncommitted shape because a live `apply()`\n\t * folds the event BEFORE the shell records it: `eventId` and\n\t * `occurredAt` do not exist yet. Replay folds recorded events\n\t * through the same map, so those fields ARE present at runtime\n\t * there. A fold that reads them through an escape hatch (`as any`,\n\t * plain JavaScript) sees `undefined` live and a value on replay,\n\t * producing silently divergent state. When a time or identity changes a\n\t * business decision, pass it in the payload.\n\t */\n\tprotected abstract readonly folds: {\n\t\t[K in TEvent[\"type\"]]: Fold<\n\t\t\tTState,\n\t\t\tUncommittedDomainEventOf<Extract<TEvent, { type: K }>>\n\t\t>;\n\t};\n}\n\n/**\n * Reconstitutes an event-sourced aggregate from one page of history and\n * yields it only on success. `createReplayTarget` builds the instance: a\n * fresh one, or one restored from a snapshot. The instance exists only\n * inside this call. A rejected replay therefore leaves the caller with\n * nothing to return by mistake. Later catch-up pages go through\n * `replayHistory` on the value. A `DomainError` from a fold rides the\n * `Result`; wiring errors and a foreign row throw, as in `replayHistory`.\n * The creator runs outside the `Result`: what it throws propagates.\n */\nexport function reconstituteAggregateFromHistory<\n\tTAggregate extends ReplayableAggregate<Id<string>, AnyDomainEvent>,\n>(\n\tcreateReplayTarget: () => TAggregate,\n\thistory: Parameters<TAggregate[\"replayHistory\"]>[0],\n): Result<TAggregate, DomainError> {\n\tconst aggregate = createReplayTarget();\n\tconst replayed = aggregate.replayHistory(history);\n\tif (replayed.isErr()) return err(replayed.error);\n\treturn ok(aggregate);\n}\n","import type { AnyDomainEvent, PendingDomainEvent } from \"../event/domain-event\";\nimport type { Id } from \"../identity/id\";\nimport { BaseAggregate } from \"./base-aggregate\";\n\n/**\n * OO-first Aggregate Root for state-stored domain models.\n *\n * The aggregate owns identity, valid domain state, behavior, its current\n * domain version, and pending domain events. It deliberately does not own a\n * database baseline or dirty-key bookkeeping. A repository adapter defines\n * its own persistence projection; the application shell retains that opaque\n * baseline and derives the adapter's change set at flush.\n */\nexport abstract class StateStoredAggregate<\n\tTState,\n\tTId extends Id<string>,\n\tTEvent extends AnyDomainEvent = never,\n> extends BaseAggregate<TState, TId, TEvent> {\n\t/**\n\t * Replaces the state, advances the OCC version, and records the events\n\t * of the change, in that order. State validation, the event mint gate,\n\t * the event address check, the pending-identity check, and the pending\n\t * event limit check run before the change becomes observable, so a\n\t * rejected decision records nothing and moves nothing. Without events the call is a plain versioned state\n\t * change.\n\t */\n\tprotected override setState(\n\t\tnewState: TState,\n\t\tevents:\n\t\t\t| PendingDomainEvent<TEvent>\n\t\t\t| readonly PendingDomainEvent<TEvent>[] = [],\n\t): void {\n\t\tconst eventBatch: readonly PendingDomainEvent<TEvent>[] = Array.isArray(\n\t\t\tevents,\n\t\t)\n\t\t\t? events\n\t\t\t: [events as PendingDomainEvent<TEvent>];\n\t\tconst stamped = eventBatch.map((event) => this.addressNewEvent(event));\n\t\tthis.assertEventIdsNotPending(stamped);\n\t\tthis.assertPendingEventLimit(stamped.length);\n\t\t// The version number is validated before the state moves; the write\n\t\t// itself comes after the state gates, so a rejected state leaves the\n\t\t// version untouched.\n\t\tconst next = this.nextVersion();\n\n\t\tsuper.setState(newState);\n\t\tthis.setVersion(next);\n\t\tfor (const event of stamped) this.appendStampedEvent(event);\n\t}\n\n\t/**\n\t * Replaces loss-tolerant derived state without advancing the domain version.\n\t *\n\t * This is intentionally loud: concurrent writers may overwrite such a\n\t * change. Keep business facts on the normal `setState` path.\n\t */\n\tprotected setStateWithoutVersionBump(newState: TState): void {\n\t\tsuper.setState(newState);\n\t}\n}\n","/**\n * The composite structure of a combinator-built specification, exposed\n * for adapters that translate specifications into storage queries. An\n * adapter walks `composite` recursively down to the named leaves and\n * translates each one. This is deliberately not an expression tree:\n * predicates stay opaque functions, and only the boolean structure and\n * the leaf names are visible from outside.\n */\nexport type SpecificationComposite<T> =\n\t| {\n\t\t\treadonly operator: \"and\";\n\t\t\treadonly left: Specification<T>;\n\t\t\treadonly right: Specification<T>;\n\t }\n\t| {\n\t\t\treadonly operator: \"or\";\n\t\t\treadonly left: Specification<T>;\n\t\t\treadonly right: Specification<T>;\n\t }\n\t| { readonly operator: \"not\"; readonly inner: Specification<T> };\n\n/**\n * Specification: a named, executable domain criterion (Evans/Fowler).\n * \"Which candidates qualify?\" becomes an object in the ubiquitous\n * language instead of an inline predicate or a leaked query builder:\n * `overdueInvoices.and(highValue.not())` reads like the business rule\n * it encodes, evaluates in memory via {@link isSatisfiedBy}, and can be\n * translated by a repository adapter into its storage's query language.\n *\n * The same object serves three places. Domain logic calls\n * `spec.isSatisfiedBy(candidate)` directly. An in-memory repository or\n * test fake implements its lookup as a plain filter,\n * `rows.filter((r) => spec.isSatisfiedBy(r))`, with no translation\n * layer. And a storage adapter translates leaf specifications\n * explicitly (matching on {@link name}, or narrowing to the class for\n * parameterized leaves) while recursing through {@link composite} for\n * combinator nodes; the repository guide walks through it. The kit\n * ships this convention and deliberately no translation machinery:\n * no expression trees, no LINQ-style providers.\n *\n * The class is deliberately left open: the combinators can be\n * overridden and `composite` can be set by subclasses. That is what\n * makes a classic visitor/double-dispatch layer buildable on top,\n * for consumers who want the compiler to enforce translation\n * completeness across several targets; the repository guide's\n * \"A visitor layer on top\" section shows the full construction.\n *\n * Take the name from the ubiquitous language. It is what an adapter\n * matches on, what diagnostics print, and what ties the object back to\n * the rule as the domain expert stated it. If no expert would\n * recognize the name, what you have is a code predicate, not a\n * specification.\n *\n * Subclass for parameterized specifications, or use the\n * {@link specification} factory for flat ones:\n *\n * @example\n * ```typescript\n * class OverdueInvoice extends Specification<Invoice> {\n * readonly name = \"overdue invoice\";\n * constructor(private readonly today: Date) { super(); }\n * isSatisfiedBy(invoice: Invoice): boolean {\n * return invoice.dueDate < this.today && invoice.status === \"open\";\n * }\n * }\n *\n * const dunningCandidates = new OverdueInvoice(today)\n * .and(specification(\"in dunning grace period\", (i: Invoice) =>\n * i.remindersSent < 3,\n * ));\n * ```\n */\nexport abstract class Specification<T> {\n\t/**\n\t * The ubiquitous-language name of the criterion. Leaf names are what\n\t * adapters translate and diagnostics print; combinator nodes derive\n\t * theirs (`\"(a and b)\"`, `\"(not a)\"`).\n\t */\n\tabstract readonly name: string;\n\n\t/**\n\t * The composite structure for combinator-built specifications;\n\t * `undefined` on leaves. See {@link SpecificationComposite}.\n\t */\n\treadonly composite?: SpecificationComposite<T>;\n\n\t/** In-memory evaluation: does `candidate` meet the criterion? */\n\tabstract isSatisfiedBy(candidate: T): boolean;\n\n\t/** Both criteria must hold (short-circuits like `&&`). */\n\tand(other: Specification<T>): Specification<T> {\n\t\treturn new BinaryCompositeSpecification(\"and\", this, other);\n\t}\n\n\t/** Either criterion suffices (short-circuits like `||`). */\n\tor(other: Specification<T>): Specification<T> {\n\t\treturn new BinaryCompositeSpecification(\"or\", this, other);\n\t}\n\n\t/** The criterion must not hold. */\n\tnot(): Specification<T> {\n\t\treturn new NotSpecification(this);\n\t}\n\n\t/** The name, so diagnostics and test output read in domain language. */\n\ttoString(): string {\n\t\treturn this.name;\n\t}\n}\n\n/**\n * Builds a leaf specification from a name and a predicate: the\n * lightweight alternative to subclassing for criteria without\n * parameters worth a class of their own. The predicate must be pure\n * (no side effects, no mutation of the candidate): specifications are\n * evaluated freely and repeatedly, in tests, combinators, and\n * in-memory repositories.\n */\nexport function specification<T>(\n\tname: string,\n\tpredicate: (candidate: T) => boolean,\n): Specification<T> {\n\tif (name.trim().length === 0 || name !== name.trim()) {\n\t\tthrow new Error(\n\t\t\t\"specification: the name must be a non-empty ubiquitous-language term \" +\n\t\t\t\t\"without leading or trailing whitespace; adapters match it as an \" +\n\t\t\t\t\"exact string, and padding is invisible in every diagnostic\",\n\t\t);\n\t}\n\treturn new PredicateSpecification(name, predicate);\n}\n\nclass PredicateSpecification<T> extends Specification<T> {\n\tconstructor(\n\t\treadonly name: string,\n\t\tprivate readonly predicate: (candidate: T) => boolean,\n\t) {\n\t\tsuper();\n\t}\n\n\tisSatisfiedBy(candidate: T): boolean {\n\t\treturn this.predicate(candidate);\n\t}\n}\n\nclass BinaryCompositeSpecification<T> extends Specification<T> {\n\toverride readonly composite: {\n\t\treadonly operator: \"and\" | \"or\";\n\t\treadonly left: Specification<T>;\n\t\treadonly right: Specification<T>;\n\t};\n\tprivate cachedName?: string;\n\n\tconstructor(\n\t\toperator: \"and\" | \"or\",\n\t\tleft: Specification<T>,\n\t\tright: Specification<T>,\n\t) {\n\t\tsuper();\n\t\t// Frozen like every plain object the kit hands out: readonly is\n\t\t// compile-time only, and an adapter mutating the structure would\n\t\t// silently diverge from name and evaluation.\n\t\tthis.composite = Object.freeze({ operator, left, right });\n\t}\n\n\t// Lazy with a cache: deep chains would otherwise pay quadratic\n\t// string work at construction for names only diagnostics read.\n\tget name(): string {\n\t\tthis.cachedName ??= `(${this.composite.left.name} ${this.composite.operator} ${this.composite.right.name})`;\n\t\treturn this.cachedName;\n\t}\n\n\tisSatisfiedBy(candidate: T): boolean {\n\t\tconst { operator, left, right } = this.composite;\n\t\treturn operator === \"and\"\n\t\t\t? left.isSatisfiedBy(candidate) && right.isSatisfiedBy(candidate)\n\t\t\t: left.isSatisfiedBy(candidate) || right.isSatisfiedBy(candidate);\n\t}\n}\n\nclass NotSpecification<T> extends Specification<T> {\n\toverride readonly composite: {\n\t\treadonly operator: \"not\";\n\t\treadonly inner: Specification<T>;\n\t};\n\tprivate cachedName?: string;\n\n\tconstructor(inner: Specification<T>) {\n\t\tsuper();\n\t\tthis.composite = Object.freeze({ operator: \"not\", inner });\n\t}\n\n\tget name(): string {\n\t\tthis.cachedName ??= `(not ${this.composite.inner.name})`;\n\t\treturn this.cachedName;\n\t}\n\n\tisSatisfiedBy(candidate: T): boolean {\n\t\treturn !this.composite.inner.isSatisfiedBy(candidate);\n\t}\n}\n","import { DomainError, KitWiringError } from \"../../errors/kit-errors\";\n\n/** No transition is defined for the input in the current state. */\nexport class InvalidDomainTransitionError extends DomainError<\"INVALID_DOMAIN_TRANSITION\"> {\n\tconstructor(\n\t\tpublic readonly state: string,\n\t\tpublic readonly inputType: string,\n\t) {\n\t\tsuper({\n\t\t\tcode: \"INVALID_DOMAIN_TRANSITION\",\n\t\t\tmessage: `No domain transition from \"${state}\" on \"${inputType}\".`,\n\t\t});\n\t}\n}\n\n/** A defined transition was rejected by its domain guard. */\nexport class DomainTransitionGuardRejectedError extends DomainError<\"DOMAIN_TRANSITION_GUARD_REJECTED\"> {\n\tconstructor(\n\t\tpublic readonly state: string,\n\t\tpublic readonly inputType: string,\n\t) {\n\t\tsuper({\n\t\t\tcode: \"DOMAIN_TRANSITION_GUARD_REJECTED\",\n\t\t\tmessage: `Domain transition guard rejected \"${inputType}\" from \"${state}\".`,\n\t\t});\n\t}\n}\n\n/** The machine definition violates its runtime contract. */\nexport class InvalidDomainMachineDefinitionError extends KitWiringError<\"INVALID_DOMAIN_MACHINE_DEFINITION\"> {\n\tconstructor(message: string, cause?: unknown) {\n\t\tsuper(\"INVALID_DOMAIN_MACHINE_DEFINITION\", message, cause);\n\t}\n}\n\n/** Context contains unsupported or unsafe runtime data. */\nexport class InvalidDomainMachineContextError extends KitWiringError<\"INVALID_DOMAIN_MACHINE_CONTEXT\"> {\n\tconstructor(message: string, cause?: unknown) {\n\t\tsuper(\"INVALID_DOMAIN_MACHINE_CONTEXT\", message, cause);\n\t}\n}\n\n/** A supplied or produced snapshot is malformed or violates invariants. */\nexport class InvalidDomainMachineSnapshotError extends KitWiringError<\"INVALID_DOMAIN_MACHINE_SNAPSHOT\"> {\n\tconstructor(message: string, cause?: unknown) {\n\t\tsuper(\"INVALID_DOMAIN_MACHINE_SNAPSHOT\", message, cause);\n\t}\n}\n\n/** An input is malformed or contains unsupported runtime data. */\nexport class InvalidDomainMachineInputError extends KitWiringError<\"INVALID_DOMAIN_MACHINE_INPUT\"> {\n\tconstructor(message: string, cause?: unknown) {\n\t\tsuper(\"INVALID_DOMAIN_MACHINE_INPUT\", message, cause);\n\t}\n}\n\n/** A guard returned a value other than `boolean` or `DomainError`. */\nexport class InvalidDomainTransitionGuardResultError extends KitWiringError<\"INVALID_DOMAIN_TRANSITION_GUARD_RESULT\"> {\n\tconstructor(message: string, cause?: unknown) {\n\t\tsuper(\"INVALID_DOMAIN_TRANSITION_GUARD_RESULT\", message, cause);\n\t}\n}\n\n/** A reducer returned a malformed result or unsupported output data. */\nexport class InvalidDomainTransitionResultError extends KitWiringError<\"INVALID_DOMAIN_TRANSITION_RESULT\"> {\n\tconstructor(message: string, cause?: unknown) {\n\t\tsuper(\"INVALID_DOMAIN_TRANSITION_RESULT\", message, cause);\n\t}\n}\n\n/** A callback attempted to evaluate the same stateful machine recursively. */\nexport class ReentrantDomainStateMachineEvaluationError extends KitWiringError<\"REENTRANT_DOMAIN_STATE_MACHINE_EVALUATION\"> {\n\tconstructor() {\n\t\tsuper(\n\t\t\t\"REENTRANT_DOMAIN_STATE_MACHINE_EVALUATION\",\n\t\t\t\"Domain state machine callbacks cannot evaluate the same machine.\",\n\t\t);\n\t}\n}\n","import {\n\tfindPropertyDescriptor,\n\tisBuiltInObject,\n\tisIntrinsicConstructorPrototype,\n} from \"../../internal/structural/is-built-in\";\nimport { deepFreeze } from \"../value-object/value-object\";\nimport type { DomainMachineInput, DomainMachineReadonly } from \"./contracts\";\nimport {\n\tInvalidDomainMachineContextError,\n\tInvalidDomainMachineInputError,\n\tInvalidDomainTransitionResultError,\n} from \"./errors\";\n\ntype DomainMachineDataErrorFactory = (\n\tmessage: string,\n\tcause?: unknown,\n) =>\n\t| InvalidDomainMachineContextError\n\t| InvalidDomainMachineInputError\n\t| InvalidDomainTransitionResultError;\n\nconst DOMAIN_MACHINE_DATA_MAX_DEPTH = 256;\nconst DOMAIN_MACHINE_DATA_MAX_NODES = 10_000;\nconst DOMAIN_MACHINE_DATA_MAX_PROPERTIES = 100_000;\n\ntype DomainMachineDataTraversal = {\n\tnodes: number;\n\tproperties: number;\n};\n\nexport function copyDomainMachineOutputs<TOutput>(\n\toutputs: readonly (TOutput | DomainMachineReadonly<TOutput>)[] | undefined,\n): readonly DomainMachineReadonly<TOutput>[] {\n\ttry {\n\t\tconst copiedOutputs = cloneDomainMachineDataValue(\n\t\t\toutputs ?? [],\n\t\t\tcreateDomainTransitionOutputError,\n\t\t);\n\t\treturn deepFreeze(\n\t\t\tcopiedOutputs,\n\t\t) as readonly DomainMachineReadonly<TOutput>[];\n\t} catch (cause) {\n\t\tif (cause instanceof InvalidDomainTransitionResultError) {\n\t\t\tthrow cause;\n\t\t}\n\t\tthrow new InvalidDomainTransitionResultError(\n\t\t\t\"Domain transition result outputs must contain cloneable, deeply immutable data.\",\n\t\t\tcause,\n\t\t);\n\t}\n}\n\nexport function copyDomainMachineInput<TInput extends DomainMachineInput>(\n\tinput: TInput,\n): DomainMachineReadonly<TInput> {\n\ttry {\n\t\treturn deepFreeze(\n\t\t\tcloneDomainMachineDataValue(input, createDomainMachineInputError),\n\t\t) as DomainMachineReadonly<TInput>;\n\t} catch (cause) {\n\t\tif (cause instanceof InvalidDomainMachineInputError) {\n\t\t\tthrow cause;\n\t\t}\n\t\tthrow new InvalidDomainMachineInputError(\n\t\t\t\"Domain machine input must contain cloneable, deeply immutable data.\",\n\t\t\tcause,\n\t\t);\n\t}\n}\n\nexport function copyDomainMachineContext<TContext>(\n\tcontext: TContext | DomainMachineReadonly<TContext>,\n): DomainMachineReadonly<TContext> {\n\ttry {\n\t\treturn deepFreeze(\n\t\t\tcloneDomainMachineDataValue(context, createDomainMachineContextError),\n\t\t) as DomainMachineReadonly<TContext>;\n\t} catch (cause) {\n\t\tif (cause instanceof InvalidDomainMachineContextError) {\n\t\t\tthrow cause;\n\t\t}\n\t\tthrow new InvalidDomainMachineContextError(\n\t\t\t\"Domain machine context must contain cloneable, deeply immutable data.\",\n\t\t\tcause,\n\t\t);\n\t}\n}\n\nfunction createDomainMachineContextError(\n\tmessage: string,\n\tcause?: unknown,\n): InvalidDomainMachineContextError {\n\treturn new InvalidDomainMachineContextError(message, cause);\n}\n\nfunction createDomainMachineInputError(\n\tmessage: string,\n\tcause?: unknown,\n): InvalidDomainMachineInputError {\n\treturn new InvalidDomainMachineInputError(message, cause);\n}\n\nfunction createDomainTransitionOutputError(\n\tmessage: string,\n\tcause?: unknown,\n): InvalidDomainTransitionResultError {\n\treturn new InvalidDomainTransitionResultError(message, cause);\n}\n\nfunction cloneDomainMachineDataValue<TValue>(\n\tvalue: TValue,\n\terrorFactory: DomainMachineDataErrorFactory,\n\tseen = new WeakMap<object, unknown>(),\n\ttraversal: DomainMachineDataTraversal = { nodes: 0, properties: 0 },\n\tdepth = 0,\n): TValue {\n\tif (typeof value === \"function\") {\n\t\tthrow errorFactory(\"Domain machine data cannot contain function values.\");\n\t}\n\tif (value === null || typeof value !== \"object\") return value;\n\n\tconst source = value as object;\n\tif (depth > DOMAIN_MACHINE_DATA_MAX_DEPTH) {\n\t\tthrow errorFactory(\n\t\t\t`Domain machine data exceeds the maximum depth of ${DOMAIN_MACHINE_DATA_MAX_DEPTH}.`,\n\t\t);\n\t}\n\tconst existing = seen.get(source);\n\tif (existing !== undefined) return existing as TValue;\n\ttraversal.nodes += 1;\n\tif (traversal.nodes > DOMAIN_MACHINE_DATA_MAX_NODES) {\n\t\tthrow errorFactory(\n\t\t\t`Domain machine data contains more than ${DOMAIN_MACHINE_DATA_MAX_NODES.toLocaleString(\"en-US\")} object nodes.`,\n\t\t);\n\t}\n\tconst toStringTagDescriptor = findPropertyDescriptor(\n\t\tsource,\n\t\tSymbol.toStringTag,\n\t);\n\tif (\n\t\ttoStringTagDescriptor !== undefined &&\n\t\t!(\"value\" in toStringTagDescriptor)\n\t) {\n\t\tthrow errorFactory(\n\t\t\t\"Domain machine data cannot contain accessor properties.\",\n\t\t);\n\t}\n\n\tif (Array.isArray(value)) {\n\t\tif (!isIntrinsicArrayPrototype(Object.getPrototypeOf(value))) {\n\t\t\tthrow errorFactory(\n\t\t\t\t\"Domain machine data cannot contain custom Array instances.\",\n\t\t\t);\n\t\t}\n\t\tconst cloned: unknown[] = new Array(value.length);\n\t\tseen.set(source, cloned);\n\n\t\tfor (const key of readDomainMachineDataKeys(\n\t\t\tsource,\n\t\t\terrorFactory,\n\t\t\ttraversal,\n\t\t)) {\n\t\t\tconst descriptor = Object.getOwnPropertyDescriptor(source, key);\n\t\t\tif (!descriptor) continue;\n\n\t\t\tif (!(\"value\" in descriptor)) {\n\t\t\t\tthrow errorFactory(\n\t\t\t\t\t\"Domain machine data cannot contain accessor properties.\",\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif (key === \"length\") continue;\n\n\t\t\tdescriptor.value = cloneDomainMachineDataValue(\n\t\t\t\tdescriptor.value,\n\t\t\t\terrorFactory,\n\t\t\t\tseen,\n\t\t\t\ttraversal,\n\t\t\t\tdepth + 1,\n\t\t\t);\n\t\t\tObject.defineProperty(cloned, key, descriptor);\n\t\t}\n\t\treturn cloned as TValue;\n\t}\n\n\tconst prototype = Object.getPrototypeOf(source);\n\tif (prototype !== null && !isIntrinsicObjectPrototype(prototype)) {\n\t\tthrow errorFactory(\n\t\t\t\"Domain machine data cannot contain custom class instances.\",\n\t\t);\n\t}\n\n\tconst tag = Object.prototype.toString.call(source);\n\tif (isBuiltInObject(source, tag) || ArrayBuffer.isView(source)) {\n\t\tthrow errorFactory(\n\t\t\t`Domain machine data cannot contain ${tag.slice(8, -1)} object values.`,\n\t\t);\n\t}\n\n\tconst cloned = Object.create(prototype === null ? null : Object.prototype);\n\tseen.set(source, cloned);\n\n\tfor (const key of readDomainMachineDataKeys(\n\t\tsource,\n\t\terrorFactory,\n\t\ttraversal,\n\t)) {\n\t\tconst descriptor = Object.getOwnPropertyDescriptor(source, key);\n\t\tif (!descriptor) continue;\n\n\t\tif (!(\"value\" in descriptor)) {\n\t\t\tthrow errorFactory(\n\t\t\t\t\"Domain machine data cannot contain accessor properties.\",\n\t\t\t);\n\t\t}\n\n\t\tdescriptor.value = cloneDomainMachineDataValue(\n\t\t\tdescriptor.value,\n\t\t\terrorFactory,\n\t\t\tseen,\n\t\t\ttraversal,\n\t\t\tdepth + 1,\n\t\t);\n\t\tObject.defineProperty(cloned, key, descriptor);\n\t}\n\n\treturn cloned as TValue;\n}\n\nfunction readDomainMachineDataKeys(\n\tvalue: object,\n\terrorFactory: DomainMachineDataErrorFactory,\n\ttraversal: DomainMachineDataTraversal,\n): readonly PropertyKey[] {\n\tconst keys = Reflect.ownKeys(value);\n\ttraversal.properties += keys.length;\n\tif (traversal.properties > DOMAIN_MACHINE_DATA_MAX_PROPERTIES) {\n\t\tthrow errorFactory(\n\t\t\t`Domain machine data contains more than ${DOMAIN_MACHINE_DATA_MAX_PROPERTIES.toLocaleString(\"en-US\")} own properties.`,\n\t\t);\n\t}\n\treturn keys;\n}\n\nexport function isRecord(\n\tvalue: unknown,\n): value is Record<PropertyKey, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nexport function isPlainRecord(\n\tvalue: unknown,\n): value is Record<PropertyKey, unknown> {\n\tif (!isRecord(value)) return false;\n\n\tconst prototype = Object.getPrototypeOf(value);\n\treturn prototype === null || isIntrinsicObjectPrototype(prototype);\n}\n\nfunction isIntrinsicArrayPrototype(prototype: object | null): boolean {\n\tif (prototype === null || !Array.isArray(prototype)) return false;\n\tif (!isIntrinsicConstructorPrototype(prototype, \"Array\")) return false;\n\n\tconst parentPrototype = Object.getPrototypeOf(prototype);\n\treturn (\n\t\tparentPrototype !== null && isIntrinsicObjectPrototype(parentPrototype)\n\t);\n}\n\nfunction isIntrinsicObjectPrototype(prototype: object): boolean {\n\treturn (\n\t\tObject.getPrototypeOf(prototype) === null &&\n\t\tisIntrinsicConstructorPrototype(prototype, \"Object\")\n\t);\n}\n\nexport function hasOwn<T extends object>(\n\tvalue: T,\n\tkey: PropertyKey,\n): key is keyof T {\n\treturn Object.hasOwn(value, key);\n}\n","import type {\n\tDomainMachineDefinition,\n\tDomainMachineInput,\n\tDomainMachineSnapshot,\n\tDomainStateNode,\n\tDomainTransition,\n} from \"./contracts\";\nimport { InvalidDomainMachineDefinitionError } from \"./errors\";\nimport { hasOwn, isPlainRecord } from \"./machine-data\";\n\nconst DOMAIN_MACHINE_DEFINITION_KEYS: ReadonlySet<PropertyKey> = new Set([\n\t\"initial\",\n\t\"initialContext\",\n\t\"validateSnapshot\",\n\t\"states\",\n]);\nconst DOMAIN_MACHINE_STATE_NODE_KEYS: ReadonlySet<PropertyKey> = new Set([\n\t\"terminal\",\n\t\"validateContext\",\n\t\"on\",\n]);\nconst DOMAIN_MACHINE_TRANSITION_KEYS: ReadonlySet<PropertyKey> = new Set([\n\t\"target\",\n\t\"guard\",\n\t\"reduce\",\n]);\n\nexport function copyDomainMachineDefinition<\n\tTState extends string,\n\tTContext,\n\tTInput extends DomainMachineInput,\n\tTOutput,\n>(\n\tdefinition: DomainMachineDefinition<TState, TContext, TInput, TOutput>,\n): DomainMachineDefinition<TState, TContext, TInput, TOutput> {\n\tconst states = readDomainMachineDefinitionProperty(\n\t\tdefinition,\n\t\t\"states\",\n\t) as DomainMachineDefinition<TState, TContext, TInput, TOutput>[\"states\"];\n\tconst copiedStates = Object.create(null) as {\n\t\t[TName in TState]: DomainStateNode<TState, TContext, TInput, TOutput>;\n\t};\n\n\tfor (const state of Object.keys(states) as TState[]) {\n\t\tconst node = readDomainMachineDefinitionProperty(\n\t\t\tstates,\n\t\t\tstate,\n\t\t) as DomainStateNode<TState, TContext, TInput, TOutput>;\n\t\tconst transitions = readOptionalDomainMachineDefinitionProperty(\n\t\t\tnode,\n\t\t\t\"on\",\n\t\t) as DomainStateNode<TState, TContext, TInput, TOutput>[\"on\"] | undefined;\n\t\tconst copiedTransitions = Object.create(null) as {\n\t\t\t[TType in TInput[\"type\"]]?: DomainTransition<\n\t\t\t\tTState,\n\t\t\t\tTContext,\n\t\t\t\tExtract<TInput, { readonly type: TType }>,\n\t\t\t\tTOutput\n\t\t\t>;\n\t\t};\n\n\t\tfor (const inputType of Object.keys(\n\t\t\ttransitions ?? {},\n\t\t) as TInput[\"type\"][]) {\n\t\t\tconst transition = readDomainMachineDefinitionProperty(\n\t\t\t\ttransitions as object,\n\t\t\t\tinputType,\n\t\t\t) as\n\t\t\t\t| DomainTransition<\n\t\t\t\t\t\tTState,\n\t\t\t\t\t\tTContext,\n\t\t\t\t\t\tExtract<TInput, { readonly type: typeof inputType }>,\n\t\t\t\t\t\tTOutput\n\t\t\t\t >\n\t\t\t\t| undefined;\n\t\t\tif (transition) {\n\t\t\t\tconst copiedTransition = Object.freeze({\n\t\t\t\t\ttarget: readDomainMachineDefinitionProperty(transition, \"target\"),\n\t\t\t\t\tguard: readOptionalDomainMachineDefinitionProperty(\n\t\t\t\t\t\ttransition,\n\t\t\t\t\t\t\"guard\",\n\t\t\t\t\t),\n\t\t\t\t\treduce: readOptionalDomainMachineDefinitionProperty(\n\t\t\t\t\t\ttransition,\n\t\t\t\t\t\t\"reduce\",\n\t\t\t\t\t),\n\t\t\t\t}) as DomainTransition<\n\t\t\t\t\tTState,\n\t\t\t\t\tTContext,\n\t\t\t\t\tExtract<TInput, { readonly type: typeof inputType }>,\n\t\t\t\t\tTOutput\n\t\t\t\t>;\n\t\t\t\tObject.defineProperty(copiedTransitions, inputType, {\n\t\t\t\t\tvalue: copiedTransition,\n\t\t\t\t\tenumerable: true,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tObject.defineProperty(copiedStates, state, {\n\t\t\tvalue: Object.freeze({\n\t\t\t\tterminal: readOptionalDomainMachineDefinitionProperty(node, \"terminal\"),\n\t\t\t\tvalidateContext: readOptionalDomainMachineDefinitionProperty(\n\t\t\t\t\tnode,\n\t\t\t\t\t\"validateContext\",\n\t\t\t\t),\n\t\t\t\ton: Object.freeze(copiedTransitions),\n\t\t\t}),\n\t\t\tenumerable: true,\n\t\t});\n\t}\n\n\treturn Object.freeze({\n\t\tinitial: readDomainMachineDefinitionProperty(\n\t\t\tdefinition,\n\t\t\t\"initial\",\n\t\t) as TState,\n\t\tinitialContext: readDomainMachineDefinitionProperty(\n\t\t\tdefinition,\n\t\t\t\"initialContext\",\n\t\t) as () => TContext,\n\t\tvalidateSnapshot: readOptionalDomainMachineDefinitionProperty(\n\t\t\tdefinition,\n\t\t\t\"validateSnapshot\",\n\t\t) as\n\t\t\t| ((snapshot: DomainMachineSnapshot<TState, TContext>) => boolean)\n\t\t\t| undefined,\n\t\tstates: Object.freeze(copiedStates),\n\t});\n}\n\n/**\n * Registry of definitions produced by `prepareDomainMachineDefinition`:\n * validated, defensively copied, deeply frozen. The runtime membership\n * proof lives in this module-private WeakSet (the stable copies are\n * frozen and must stay pure data, so no runtime brand property); the\n * compile-time proof is the required type brand on\n * {@link PreparedDomainMachineDefinition}. Only\n * `prepareDomainMachineDefinition` below adds to the set, so membership\n * always implies validated + copied + frozen.\n */\nconst preparedDefinitions = new WeakSet<object>();\n\ndeclare const preparedDefinitionBrand: unique symbol;\n\n/**\n * A machine definition that `prepareDomainMachineDefinition` has\n * validated, defensively copied, and deeply frozen. Assignable wherever\n * a plain `DomainMachineDefinition` is accepted; the reverse does NOT\n * hold (the brand is required), so an API that demands a prepared\n * definition rejects raw ones at compile time. The pure functions and\n * the `DomainStateMachine` constructor recognize prepared definitions\n * at runtime and skip their per-call validate-and-copy.\n */\nexport type PreparedDomainMachineDefinition<\n\tTState extends string,\n\tTContext,\n\tTInput extends DomainMachineInput,\n\tTOutput = never,\n> = DomainMachineDefinition<TState, TContext, TInput, TOutput> & {\n\treadonly [preparedDefinitionBrand]: true;\n};\n\n/**\n * The entry-point normalization every pure function and the\n * `DomainStateMachine` constructor share: a prepared definition passes\n * through untouched (already validated, copied, frozen); anything else\n * pays the documented per-call validate-and-copy.\n */\nexport function ensureStableDomainMachineDefinition<\n\tTState extends string,\n\tTContext,\n\tTInput extends DomainMachineInput,\n\tTOutput,\n>(\n\tdefinition: DomainMachineDefinition<TState, TContext, TInput, TOutput>,\n): DomainMachineDefinition<TState, TContext, TInput, TOutput> {\n\tif (preparedDefinitions.has(definition)) return definition;\n\tvalidateDomainMachineDefinition(definition);\n\tconst stable = copyDomainMachineDefinition(definition);\n\t// Re-validate the COPY: a Proxy can legally answer the copy's reads\n\t// differently from validation's (TOCTOU), so the object that will\n\t// actually be dispatched against must itself pass validation. Costs a\n\t// second pass on the raw path only; prepared definitions skip all of\n\t// this.\n\tvalidateDomainMachineDefinition(stable);\n\treturn stable;\n}\n\n/**\n * Validates and stabilizes a machine definition ONCE, for repeated use\n * with the pure functions. Without it, `transitionDomainState` and\n * `canTransitionDomainState` re-validate and defensively re-copy the\n * WHOLE definition on every call (the documented safety of the raw\n * path); on a hot dispatch path that is avoidable O(definition) work.\n * The `DomainStateMachine` class does the equivalent once in its\n * constructor; this export brings the same amortization to pure-API\n * users:\n *\n * ```ts\n * const prepared = prepareDomainMachineDefinition(orderLifecycle);\n * // per dispatch: no re-validation, no definition copy\n * const outcome = transitionDomainState(prepared, snapshot, input);\n * ```\n *\n * The returned definition is a deeply frozen copy, isolated from later\n * mutation of the input object. Preparing an already-prepared\n * definition returns it unchanged.\n */\nexport function prepareDomainMachineDefinition<\n\tTState extends string,\n\tTContext,\n\tTInput extends DomainMachineInput,\n\tTOutput,\n>(\n\tdefinition: DomainMachineDefinition<TState, TContext, TInput, TOutput>,\n): PreparedDomainMachineDefinition<TState, TContext, TInput, TOutput> {\n\tconst stable = ensureStableDomainMachineDefinition(definition);\n\tpreparedDefinitions.add(stable);\n\treturn stable as PreparedDomainMachineDefinition<\n\t\tTState,\n\t\tTContext,\n\t\tTInput,\n\t\tTOutput\n\t>;\n}\n\nexport function getTransition<\n\tTState extends string,\n\tTContext,\n\tTInput extends DomainMachineInput,\n\tTOutput,\n>(\n\tdefinition: DomainMachineDefinition<TState, TContext, TInput, TOutput>,\n\tstate: TState,\n\tinput: TInput,\n): DomainTransition<TState, TContext, TInput, TOutput> | undefined {\n\tconst transitions = definition.states[state].on;\n\tif (!transitions || !hasOwn(transitions, input.type)) return undefined;\n\n\treturn transitions[input.type as TInput[\"type\"]] as\n\t\t| DomainTransition<TState, TContext, TInput, TOutput>\n\t\t| undefined;\n}\n\nexport function validateDomainMachineDefinition<\n\tTState extends string,\n\tTContext,\n\tTInput extends DomainMachineInput,\n\tTOutput,\n>(\n\tdefinition: DomainMachineDefinition<TState, TContext, TInput, TOutput>,\n): void {\n\tconst candidate = definition as unknown;\n\tif (!isPlainRecord(candidate)) {\n\t\tthrow new InvalidDomainMachineDefinitionError(\n\t\t\t\"Domain machine definition must be a plain object.\",\n\t\t);\n\t}\n\tassertDomainMachineDefinitionDataProperties(\n\t\tcandidate,\n\t\tDOMAIN_MACHINE_DEFINITION_KEYS,\n\t);\n\n\tconst initial = readDomainMachineDefinitionProperty(candidate, \"initial\");\n\tif (typeof initial !== \"string\") {\n\t\tthrow new InvalidDomainMachineDefinitionError(\n\t\t\t\"Domain machine initial state must be a string data property.\",\n\t\t);\n\t}\n\n\tif (\n\t\ttypeof readDomainMachineDefinitionProperty(candidate, \"initialContext\") !==\n\t\t\"function\"\n\t) {\n\t\tthrow new InvalidDomainMachineDefinitionError(\n\t\t\t\"Domain machine initialContext must be a function data property.\",\n\t\t);\n\t}\n\n\tconst validateSnapshot = readOptionalDomainMachineDefinitionProperty(\n\t\tcandidate,\n\t\t\"validateSnapshot\",\n\t);\n\tif (\n\t\tvalidateSnapshot !== undefined &&\n\t\ttypeof validateSnapshot !== \"function\"\n\t) {\n\t\tthrow new InvalidDomainMachineDefinitionError(\n\t\t\t\"Domain machine validateSnapshot must be a function data property.\",\n\t\t);\n\t}\n\n\tconst statesCandidate = readDomainMachineDefinitionProperty(\n\t\tcandidate,\n\t\t\"states\",\n\t);\n\tif (!isPlainRecord(statesCandidate)) {\n\t\tthrow new InvalidDomainMachineDefinitionError(\n\t\t\t\"Domain machine states must be a plain object data property.\",\n\t\t);\n\t}\n\tconst states: Record<PropertyKey, unknown> = statesCandidate;\n\tassertDomainMachineDefinitionEntryMap(states, \"state\");\n\n\tif (!hasOwn(states, initial)) {\n\t\tthrow new InvalidDomainMachineDefinitionError(\n\t\t\t`Initial domain machine state \"${initial}\" is not defined.`,\n\t\t);\n\t}\n\n\tfor (const state of Object.keys(states)) {\n\t\tconst node: unknown = readDomainMachineDefinitionProperty(states, state);\n\t\tif (!isPlainRecord(node)) {\n\t\t\tthrow new InvalidDomainMachineDefinitionError(\n\t\t\t\t`Domain machine state \"${state}\" must be a plain object data property.`,\n\t\t\t);\n\t\t}\n\t\tassertDomainMachineDefinitionDataProperties(\n\t\t\tnode,\n\t\t\tDOMAIN_MACHINE_STATE_NODE_KEYS,\n\t\t);\n\n\t\tconst terminal: unknown = readOptionalDomainMachineDefinitionProperty(\n\t\t\tnode,\n\t\t\t\"terminal\",\n\t\t);\n\t\tif (terminal !== undefined && typeof terminal !== \"boolean\") {\n\t\t\tthrow new InvalidDomainMachineDefinitionError(\n\t\t\t\t`Domain machine state \"${state}\" terminal flag must be a boolean.`,\n\t\t\t);\n\t\t}\n\n\t\tconst validateContext: unknown =\n\t\t\treadOptionalDomainMachineDefinitionProperty(node, \"validateContext\");\n\t\tif (\n\t\t\tvalidateContext !== undefined &&\n\t\t\ttypeof validateContext !== \"function\"\n\t\t) {\n\t\t\tthrow new InvalidDomainMachineDefinitionError(\n\t\t\t\t`Domain machine state \"${state}\" validateContext must be a function.`,\n\t\t\t);\n\t\t}\n\n\t\tconst transitions: unknown = readOptionalDomainMachineDefinitionProperty(\n\t\t\tnode,\n\t\t\t\"on\",\n\t\t);\n\t\tif (transitions !== undefined && !isPlainRecord(transitions)) {\n\t\t\tthrow new InvalidDomainMachineDefinitionError(\n\t\t\t\t`Domain machine state \"${state}\" transitions must be a plain object.`,\n\t\t\t);\n\t\t}\n\t\tif (isPlainRecord(transitions)) {\n\t\t\tassertDomainMachineDefinitionEntryMap(transitions, \"input\");\n\t\t}\n\n\t\tconst inputTypes = Object.keys(transitions ?? {});\n\t\tif (terminal === true && inputTypes.length > 0) {\n\t\t\tthrow new InvalidDomainMachineDefinitionError(\n\t\t\t\t`Terminal domain machine state \"${state}\" cannot declare transitions.`,\n\t\t\t);\n\t\t}\n\n\t\tfor (const inputType of inputTypes) {\n\t\t\tconst transition: unknown = readDomainMachineDefinitionProperty(\n\t\t\t\ttransitions as object,\n\t\t\t\tinputType,\n\t\t\t);\n\t\t\tif (!isPlainRecord(transition)) {\n\t\t\t\tthrow new InvalidDomainMachineDefinitionError(\n\t\t\t\t\t`Domain transition from \"${state}\" on \"${inputType}\" must be a plain object.`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tassertDomainMachineDefinitionDataProperties(\n\t\t\t\ttransition,\n\t\t\t\tDOMAIN_MACHINE_TRANSITION_KEYS,\n\t\t\t);\n\n\t\t\tconst target: unknown = readDomainMachineDefinitionProperty(\n\t\t\t\ttransition,\n\t\t\t\t\"target\",\n\t\t\t);\n\t\t\tif (typeof target !== \"string\") {\n\t\t\t\tthrow new InvalidDomainMachineDefinitionError(\n\t\t\t\t\t`Domain transition from \"${state}\" on \"${inputType}\" must target a string state.`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif (!hasOwn(states, target)) {\n\t\t\t\tthrow new InvalidDomainMachineDefinitionError(\n\t\t\t\t\t`Domain transition from \"${state}\" on \"${inputType}\" targets unknown state \"${target}\".`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst guard: unknown = readOptionalDomainMachineDefinitionProperty(\n\t\t\t\ttransition,\n\t\t\t\t\"guard\",\n\t\t\t);\n\t\t\tif (guard !== undefined && typeof guard !== \"function\") {\n\t\t\t\tthrow new InvalidDomainMachineDefinitionError(\n\t\t\t\t\t`Domain transition from \"${state}\" on \"${inputType}\" guard must be a function.`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst reduce: unknown = readOptionalDomainMachineDefinitionProperty(\n\t\t\t\ttransition,\n\t\t\t\t\"reduce\",\n\t\t\t);\n\t\t\tif (reduce !== undefined && typeof reduce !== \"function\") {\n\t\t\t\tthrow new InvalidDomainMachineDefinitionError(\n\t\t\t\t\t`Domain transition from \"${state}\" on \"${inputType}\" reduce must be a function.`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunction assertDomainMachineDefinitionDataProperties(\n\tvalue: object,\n\tallowedKeys?: ReadonlySet<PropertyKey>,\n): void {\n\tfor (const key of Reflect.ownKeys(value)) {\n\t\tconst descriptor = Object.getOwnPropertyDescriptor(value, key);\n\t\tif (descriptor !== undefined && !(\"value\" in descriptor)) {\n\t\t\tthrow new InvalidDomainMachineDefinitionError(\n\t\t\t\t\"Domain machine definition must contain data properties only.\",\n\t\t\t);\n\t\t}\n\t\tif (allowedKeys !== undefined && !allowedKeys.has(key)) {\n\t\t\tthrow new InvalidDomainMachineDefinitionError(\n\t\t\t\t`Domain machine definition contains unknown property \"${String(key)}\".`,\n\t\t\t);\n\t\t}\n\t}\n}\n\nfunction assertDomainMachineDefinitionEntryMap(\n\tvalue: object,\n\tentryName: \"state\" | \"input\",\n): void {\n\tassertDomainMachineDefinitionDataProperties(value);\n\n\tfor (const key of Reflect.ownKeys(value)) {\n\t\tconst descriptor = Object.getOwnPropertyDescriptor(value, key);\n\t\tif (typeof key !== \"string\" || descriptor?.enumerable !== true) {\n\t\t\tthrow new InvalidDomainMachineDefinitionError(\n\t\t\t\t`Domain machine ${entryName} names must be enumerable string properties.`,\n\t\t\t);\n\t\t}\n\t}\n}\n\nfunction readDomainMachineDefinitionProperty(\n\tvalue: object,\n\tkey: PropertyKey,\n): unknown {\n\tconst descriptor = Object.getOwnPropertyDescriptor(value, key);\n\tif (descriptor === undefined || !(\"value\" in descriptor)) {\n\t\tthrow new InvalidDomainMachineDefinitionError(\n\t\t\t\"Domain machine definition must contain data properties only.\",\n\t\t);\n\t}\n\n\treturn descriptor.value;\n}\n\nfunction readOptionalDomainMachineDefinitionProperty(\n\tvalue: object,\n\tkey: PropertyKey,\n): unknown {\n\tconst descriptor = Object.getOwnPropertyDescriptor(value, key);\n\tif (descriptor === undefined) return undefined;\n\tif (!(\"value\" in descriptor)) {\n\t\tthrow new InvalidDomainMachineDefinitionError(\n\t\t\t\"Domain machine definition must contain data properties only.\",\n\t\t);\n\t}\n\n\treturn descriptor.value;\n}\n","import { DomainError } from \"../../errors/kit-errors\";\nimport type {\n\tDomainMachineDefinition,\n\tDomainMachineInput,\n\tDomainMachineReadonly,\n\tDomainMachineSnapshot,\n\tDomainTransitionResult,\n} from \"./contracts\";\nimport {\n\tInvalidDomainMachineDefinitionError,\n\tInvalidDomainMachineInputError,\n\tInvalidDomainMachineSnapshotError,\n\tInvalidDomainTransitionGuardResultError,\n\tInvalidDomainTransitionResultError,\n} from \"./errors\";\nimport {\n\tcopyDomainMachineContext,\n\thasOwn,\n\tisPlainRecord,\n\tisRecord,\n} from \"./machine-data\";\n\nconst DOMAIN_TRANSITION_RESULT_KEYS: ReadonlySet<PropertyKey> = new Set([\n\t\"context\",\n\t\"outputs\",\n]);\n\nexport function prepareDomainMachineSnapshot<\n\tTState extends string,\n\tTContext,\n\tTInput extends DomainMachineInput,\n\tTOutput,\n>(\n\tdefinition: DomainMachineDefinition<TState, TContext, TInput, TOutput>,\n\tsnapshot: DomainMachineSnapshot<TState, TContext>,\n): DomainMachineSnapshot<TState, TContext> {\n\tvalidateDomainMachineSnapshot(definition, snapshot);\n\tconst preparedSnapshot = createDomainMachineSnapshot<TState, TContext>(\n\t\tsnapshot,\n\t);\n\t// Re-validate the COPY: a Proxy can answer the copy's reads differently\n\t// from validation's (TOCTOU), and the copy is what the machine runs on.\n\tvalidateDomainMachineSnapshot(definition, preparedSnapshot);\n\tvalidateDomainMachineSnapshotInvariant(definition, preparedSnapshot);\n\treturn preparedSnapshot;\n}\n\nexport function createDomainMachineSnapshotFromPreparedContext<\n\tTState extends string,\n\tTContext,\n>(\n\tstate: TState,\n\tcontext: DomainMachineReadonly<TContext>,\n): DomainMachineSnapshot<TState, TContext> {\n\treturn Object.freeze({ state, context });\n}\n\nexport function createDomainMachineSnapshot<\n\tTState extends string,\n\tTContext,\n>(snapshot: {\n\treadonly state: TState;\n\treadonly context: TContext | DomainMachineReadonly<TContext>;\n}): DomainMachineSnapshot<TState, TContext> {\n\treturn Object.freeze({\n\t\tstate: readDomainMachineSnapshotState(snapshot),\n\t\tcontext: copyDomainMachineContext<TContext>(\n\t\t\treadDomainMachineSnapshotContext(snapshot),\n\t\t),\n\t}) as DomainMachineSnapshot<TState, TContext>;\n}\n\nexport function validateDomainMachineSnapshot<\n\tTState extends string,\n\tTContext,\n\tTInput extends DomainMachineInput,\n\tTOutput,\n>(\n\tdefinition: DomainMachineDefinition<TState, TContext, TInput, TOutput>,\n\tsnapshot: DomainMachineSnapshot<TState, TContext>,\n): void {\n\tif (!isRecord(snapshot)) {\n\t\tthrow new InvalidDomainMachineSnapshotError(\n\t\t\t\"Domain machine snapshot must be an object.\",\n\t\t);\n\t}\n\n\tconst state = readDomainMachineSnapshotState(snapshot);\n\treadDomainMachineSnapshotContext(snapshot);\n\n\tif (!hasOwn(definition.states, state)) {\n\t\tthrow new InvalidDomainMachineSnapshotError(\n\t\t\t`Domain machine snapshot state \"${state}\" is not defined.`,\n\t\t);\n\t}\n}\n\nexport function validateDomainMachineSnapshotInvariant<\n\tTState extends string,\n\tTContext,\n\tTInput extends DomainMachineInput,\n\tTOutput,\n>(\n\tdefinition: DomainMachineDefinition<TState, TContext, TInput, TOutput>,\n\tsnapshot: DomainMachineSnapshot<TState, TContext>,\n): void {\n\tconst stateNode = definition.states[snapshot.state];\n\tif (stateNode.validateContext !== undefined) {\n\t\tconst validContext = stateNode.validateContext({\n\t\t\tstate: snapshot.state,\n\t\t\tcontext: snapshot.context,\n\t\t});\n\t\tif (typeof validContext !== \"boolean\") {\n\t\t\tthrow new InvalidDomainMachineDefinitionError(\n\t\t\t\t`Domain machine state \"${snapshot.state}\" validateContext must return a boolean.`,\n\t\t\t);\n\t\t}\n\t\tif (!validContext) {\n\t\t\tthrow new InvalidDomainMachineSnapshotError(\n\t\t\t\t`Domain machine snapshot violates the context invariant for state \"${snapshot.state}\".`,\n\t\t\t);\n\t\t}\n\t}\n\n\tif (definition.validateSnapshot === undefined) return;\n\n\tconst valid = definition.validateSnapshot(snapshot);\n\tif (typeof valid !== \"boolean\") {\n\t\tthrow new InvalidDomainMachineDefinitionError(\n\t\t\t\"Domain machine validateSnapshot must return a boolean.\",\n\t\t);\n\t}\n\n\tif (!valid) {\n\t\tthrow new InvalidDomainMachineSnapshotError(\n\t\t\t`Domain machine snapshot violates invariants for state \"${snapshot.state}\".`,\n\t\t);\n\t}\n}\n\nfunction readDomainMachineSnapshotState<TState extends string>(snapshot: {\n\treadonly state: TState;\n}): TState {\n\tconst stateDescriptor = Object.getOwnPropertyDescriptor(snapshot, \"state\");\n\tif (\n\t\tstateDescriptor === undefined ||\n\t\t!(\"value\" in stateDescriptor) ||\n\t\ttypeof stateDescriptor.value !== \"string\"\n\t) {\n\t\tthrow new InvalidDomainMachineSnapshotError(\n\t\t\t\"Domain machine snapshot state must be a string data property.\",\n\t\t);\n\t}\n\n\treturn stateDescriptor.value as TState;\n}\n\nfunction readDomainMachineSnapshotContext<TContext>(snapshot: {\n\treadonly context: TContext;\n}): TContext {\n\tconst contextDescriptor = Object.getOwnPropertyDescriptor(\n\t\tsnapshot,\n\t\t\"context\",\n\t);\n\tif (contextDescriptor === undefined || !(\"value\" in contextDescriptor)) {\n\t\tthrow new InvalidDomainMachineSnapshotError(\n\t\t\t\"Domain machine snapshot context must be present as a data property.\",\n\t\t);\n\t}\n\n\treturn contextDescriptor.value as TContext;\n}\n\nexport function validateDomainMachineInput(\n\tinput: unknown,\n): asserts input is DomainMachineInput {\n\tif (!isDomainMachineInput(input)) {\n\t\tthrow new InvalidDomainMachineInputError(\n\t\t\t\"Domain machine input must be an object with a string type.\",\n\t\t);\n\t}\n}\n\nexport function isDomainMachineInput(\n\tinput: unknown,\n): input is DomainMachineInput {\n\tif (!isRecord(input)) return false;\n\n\tconst typeDescriptor = Object.getOwnPropertyDescriptor(input, \"type\");\n\treturn (\n\t\ttypeDescriptor !== undefined &&\n\t\t\"value\" in typeDescriptor &&\n\t\ttypeof typeDescriptor.value === \"string\"\n\t);\n}\n\nexport function resolveDomainTransitionGuardResult(\n\tresult: unknown,\n):\n\t| { readonly allowed: true }\n\t| { readonly allowed: false; readonly rejection?: DomainError } {\n\tif (typeof result === \"boolean\") return { allowed: result };\n\tif (result instanceof DomainError) {\n\t\treturn { allowed: false, rejection: result };\n\t}\n\n\tthrow new InvalidDomainTransitionGuardResultError(\n\t\t\"Domain transition guard must return a boolean or DomainError.\",\n\t);\n}\n\nexport function validateDomainTransitionResult<TContext, TOutput>(\n\tresult: DomainTransitionResult<TContext, TOutput> | undefined,\n): void {\n\tif (result === undefined) return;\n\n\tif (!isPlainRecord(result)) {\n\t\tthrow new InvalidDomainTransitionResultError(\n\t\t\t\"Domain transition result must be a plain object when returned.\",\n\t\t);\n\t}\n\n\tfor (const key of Reflect.ownKeys(result)) {\n\t\tif (!DOMAIN_TRANSITION_RESULT_KEYS.has(key)) {\n\t\t\tthrow new InvalidDomainTransitionResultError(\n\t\t\t\t`Domain transition result contains unknown property \"${String(key)}\".`,\n\t\t\t);\n\t\t}\n\t\tconst descriptor = Object.getOwnPropertyDescriptor(result, key);\n\t\tif (descriptor !== undefined && !(\"value\" in descriptor)) {\n\t\t\tthrow new InvalidDomainTransitionResultError(\n\t\t\t\t\"Domain transition result must contain data properties only.\",\n\t\t\t);\n\t\t}\n\t}\n\n\tconst outputs = readDomainTransitionResultOutputs(result);\n\tif (outputs !== undefined && !Array.isArray(outputs)) {\n\t\tthrow new InvalidDomainTransitionResultError(\n\t\t\t\"Domain transition result outputs must be an array when provided.\",\n\t\t);\n\t}\n}\n\nexport function readDomainTransitionResultContext<TContext, TOutput>(\n\tresult: DomainTransitionResult<TContext, TOutput> | undefined,\n):\n\t| { readonly hasContext: false }\n\t| { readonly hasContext: true; readonly context: TContext } {\n\tif (result === undefined) return { hasContext: false };\n\n\tconst contextDescriptor = Object.getOwnPropertyDescriptor(result, \"context\");\n\tif (contextDescriptor === undefined) return { hasContext: false };\n\tif (!(\"value\" in contextDescriptor)) {\n\t\tthrow new InvalidDomainTransitionResultError(\n\t\t\t\"Domain transition result context must be a data property when provided.\",\n\t\t);\n\t}\n\n\treturn { hasContext: true, context: contextDescriptor.value as TContext };\n}\n\nexport function readDomainTransitionResultOutputs<TContext, TOutput>(\n\tresult: DomainTransitionResult<TContext, TOutput> | undefined,\n): readonly TOutput[] | undefined {\n\tif (result === undefined) return undefined;\n\n\tconst outputsDescriptor = Object.getOwnPropertyDescriptor(result, \"outputs\");\n\tif (outputsDescriptor === undefined) return undefined;\n\tif (!(\"value\" in outputsDescriptor)) {\n\t\tthrow new InvalidDomainTransitionResultError(\n\t\t\t\"Domain transition result outputs must be a data property when provided.\",\n\t\t);\n\t}\n\n\treturn outputsDescriptor.value as readonly TOutput[] | undefined;\n}\n","import type {\n\tDomainMachineDefinition,\n\tDomainMachineInput,\n\tDomainMachineSnapshot,\n\tDomainTransitionOutcome,\n} from \"./contracts\";\nimport {\n\tensureStableDomainMachineDefinition,\n\tgetTransition,\n} from \"./definition\";\nimport {\n\tDomainTransitionGuardRejectedError,\n\tInvalidDomainTransitionError,\n} from \"./errors\";\nimport {\n\tcopyDomainMachineInput,\n\tcopyDomainMachineOutputs,\n} from \"./machine-data\";\nimport {\n\tcreateDomainMachineSnapshot,\n\tcreateDomainMachineSnapshotFromPreparedContext,\n\tisDomainMachineInput,\n\tprepareDomainMachineSnapshot,\n\treadDomainTransitionResultContext,\n\treadDomainTransitionResultOutputs,\n\tresolveDomainTransitionGuardResult,\n\tvalidateDomainMachineInput,\n\tvalidateDomainMachineSnapshotInvariant,\n\tvalidateDomainTransitionResult,\n} from \"./snapshot\";\n\n/** Creates and validates a fresh initial snapshot from a machine definition. */\nexport function createInitialDomainMachineSnapshot<\n\tTState extends string,\n\tTContext,\n\tTInput extends DomainMachineInput,\n\tTOutput,\n>(\n\tdefinition: DomainMachineDefinition<TState, TContext, TInput, TOutput>,\n): DomainMachineSnapshot<TState, TContext> {\n\tconst stableDefinition = ensureStableDomainMachineDefinition(definition);\n\treturn createInitialDomainMachineSnapshotFromPrepared(stableDefinition);\n}\n\nexport function createInitialDomainMachineSnapshotFromPrepared<\n\tTState extends string,\n\tTContext,\n\tTInput extends DomainMachineInput,\n\tTOutput,\n>(\n\tdefinition: DomainMachineDefinition<TState, TContext, TInput, TOutput>,\n): DomainMachineSnapshot<TState, TContext> {\n\tconst snapshot = createDomainMachineSnapshot<TState, TContext>({\n\t\tstate: definition.initial,\n\t\tcontext: definition.initialContext(),\n\t});\n\tvalidateDomainMachineSnapshotInvariant(definition, snapshot);\n\treturn snapshot;\n}\n\n/**\n * Checks whether an input currently has an allowed transition.\n *\n * Returns `false` for missing transitions, terminal states, rejected guards,\n * and inputs without an own string `type` property. Invalid payload data for a\n * matching transition and broken guard code still throw structured errors.\n */\nexport function canTransitionDomainState<\n\tTState extends string,\n\tTContext,\n\tTInput extends DomainMachineInput,\n\tTOutput,\n>(\n\tdefinition: DomainMachineDefinition<TState, TContext, TInput, TOutput>,\n\tsnapshot: DomainMachineSnapshot<TState, TContext>,\n\tinput: TInput,\n): boolean {\n\tconst stableDefinition = ensureStableDomainMachineDefinition(definition);\n\tconst currentSnapshot = prepareDomainMachineSnapshot(\n\t\tstableDefinition,\n\t\tsnapshot,\n\t);\n\treturn canTransitionPreparedDomainState(\n\t\tstableDefinition,\n\t\tcurrentSnapshot,\n\t\tinput,\n\t);\n}\n\nexport function canTransitionPreparedDomainState<\n\tTState extends string,\n\tTContext,\n\tTInput extends DomainMachineInput,\n\tTOutput,\n>(\n\tdefinition: DomainMachineDefinition<TState, TContext, TInput, TOutput>,\n\tsnapshot: DomainMachineSnapshot<TState, TContext>,\n\tinput: TInput,\n): boolean {\n\tif (!isDomainMachineInput(input)) return false;\n\n\tconst stateNode = definition.states[snapshot.state];\n\tif (stateNode.terminal === true) return false;\n\n\tconst transition = getTransition(definition, snapshot.state, input);\n\tif (!transition) return false;\n\n\tconst currentInput = copyDomainMachineInput(input);\n\tif (!transition.guard) return true;\n\n\tconst guardResult = transition.guard({\n\t\tstate: snapshot.state,\n\t\tcontext: snapshot.context,\n\t\tinput: currentInput,\n\t});\n\n\treturn resolveDomainTransitionGuardResult(guardResult).allowed;\n}\n\n/**\n * Applies one input without mutating the input definition or snapshot.\n *\n * @throws {@link InvalidDomainTransitionError} when no transition is defined.\n * @throws {@link DomainTransitionGuardRejectedError} when its guard rejects.\n * @throws A concrete `DomainError` returned by a rejecting guard.\n */\nexport function transitionDomainState<\n\tTState extends string,\n\tTContext,\n\tTInput extends DomainMachineInput,\n\tTOutput,\n>(\n\tdefinition: DomainMachineDefinition<TState, TContext, TInput, TOutput>,\n\tsnapshot: DomainMachineSnapshot<TState, TContext>,\n\tinput: TInput,\n): DomainTransitionOutcome<TState, TContext, TOutput> {\n\tconst stableDefinition = ensureStableDomainMachineDefinition(definition);\n\tconst currentSnapshot = prepareDomainMachineSnapshot(\n\t\tstableDefinition,\n\t\tsnapshot,\n\t);\n\treturn transitionPreparedDomainState(\n\t\tstableDefinition,\n\t\tcurrentSnapshot,\n\t\tinput,\n\t);\n}\n\nexport function transitionPreparedDomainState<\n\tTState extends string,\n\tTContext,\n\tTInput extends DomainMachineInput,\n\tTOutput,\n>(\n\tdefinition: DomainMachineDefinition<TState, TContext, TInput, TOutput>,\n\tsnapshot: DomainMachineSnapshot<TState, TContext>,\n\tinput: TInput,\n): DomainTransitionOutcome<TState, TContext, TOutput> {\n\tvalidateDomainMachineInput(input);\n\n\tconst from = snapshot.state;\n\tconst stateNode = definition.states[from];\n\tconst transition =\n\t\tstateNode.terminal === true\n\t\t\t? undefined\n\t\t\t: getTransition(definition, from, input);\n\n\tif (!transition) {\n\t\tthrow new InvalidDomainTransitionError(from, input.type);\n\t}\n\n\tconst currentInput = copyDomainMachineInput(input);\n\tconst guardResult =\n\t\ttransition.guard === undefined\n\t\t\t? true\n\t\t\t: transition.guard({\n\t\t\t\t\tstate: from,\n\t\t\t\t\tcontext: snapshot.context,\n\t\t\t\t\tinput: currentInput,\n\t\t\t\t});\n\tconst guardDecision = resolveDomainTransitionGuardResult(guardResult);\n\n\tif (!guardDecision.allowed) {\n\t\tif (guardDecision.rejection !== undefined) {\n\t\t\tthrow guardDecision.rejection;\n\t\t}\n\t\tthrow new DomainTransitionGuardRejectedError(from, currentInput.type);\n\t}\n\n\tconst result = transition.reduce?.({\n\t\tstate: from,\n\t\tcontext: snapshot.context,\n\t\tinput: currentInput,\n\t});\n\tvalidateDomainTransitionResult(result);\n\tconst contextResult = readDomainTransitionResultContext(result);\n\tconst nextContext = contextResult.hasContext\n\t\t? contextResult.context\n\t\t: snapshot.context;\n\tconst nextSnapshot =\n\t\tnextContext === snapshot.context\n\t\t\t? createDomainMachineSnapshotFromPreparedContext<TState, TContext>(\n\t\t\t\t\ttransition.target,\n\t\t\t\t\tsnapshot.context,\n\t\t\t\t)\n\t\t\t: createDomainMachineSnapshot<TState, TContext>({\n\t\t\t\t\tstate: transition.target,\n\t\t\t\t\tcontext: nextContext,\n\t\t\t\t});\n\tvalidateDomainMachineSnapshotInvariant(definition, nextSnapshot);\n\n\t// Frozen like every sibling return value (snapshots, outputs, the\n\t// analyzer result): the contract types the fields readonly, and the\n\t// runtime must not allow a cast to rewrite from/to.\n\treturn Object.freeze({\n\t\tfrom,\n\t\tto: transition.target,\n\t\tsnapshot: nextSnapshot,\n\t\toutputs: copyDomainMachineOutputs(\n\t\t\treadDomainTransitionResultOutputs(result),\n\t\t),\n\t});\n}\n","import type { DomainMachineDefinition, DomainMachineInput } from \"./contracts\";\nimport { ensureStableDomainMachineDefinition } from \"./definition\";\n\nexport type DomainMachineDefinitionDiagnostic<TState extends string> =\n\t| {\n\t\t\treadonly code: \"unreachable-state\";\n\t\t\treadonly state: TState;\n\t }\n\t| {\n\t\t\treadonly code: \"structural-dead-end\";\n\t\t\treadonly state: TState;\n\t }\n\t| {\n\t\t\treadonly code: \"no-terminal-path\";\n\t\t\treadonly state: TState;\n\t };\n\nexport type DomainMachineTransitionDescription<\n\tTState extends string,\n\tTInputType extends string,\n> = {\n\treadonly state: TState;\n\treadonly inputType: TInputType;\n\treadonly target: TState;\n\treadonly guarded: boolean;\n};\n\nexport type DomainMachineDefinitionAnalysis<\n\tTState extends string,\n\tTInputType extends string,\n> = {\n\treadonly diagnostics: readonly DomainMachineDefinitionDiagnostic<TState>[];\n\treadonly transitions: readonly DomainMachineTransitionDescription<\n\t\tTState,\n\t\tTInputType\n\t>[];\n\t/** States reachable when every guard is assumed to allow its transition. */\n\treadonly structurallyReachableStates: readonly TState[];\n\t/** States with a graph path to a terminal state when every guard is assumed to allow it. */\n\treadonly statesWithTerminalPath: readonly TState[];\n};\n\n/**\n * Inspects the declarative transition graph without executing definition callbacks.\n * Guarded edges are treated as possible edges, so diagnostics never claim more\n * runtime reachability than the static graph can prove.\n */\nexport function analyzeDomainMachineDefinition<\n\tTState extends string,\n\tTContext,\n\tTInput extends DomainMachineInput,\n\tTOutput,\n>(\n\tdefinition: DomainMachineDefinition<TState, TContext, TInput, TOutput>,\n): DomainMachineDefinitionAnalysis<TState, TInput[\"type\"]> {\n\t// The shared entry-point normalization: a prepared definition passes\n\t// through untouched (already validated, copied, frozen), a raw one\n\t// pays the documented per-call validate-and-copy.\n\tconst stableDefinition = ensureStableDomainMachineDefinition(definition);\n\tconst states = (Object.keys(stableDefinition.states) as TState[]).sort(\n\t\tcompareStrings,\n\t);\n\tconst outgoing = new Map<TState, TState[]>();\n\tconst incoming = new Map<TState, TState[]>();\n\tconst transitions: DomainMachineTransitionDescription<\n\t\tTState,\n\t\tTInput[\"type\"]\n\t>[] = [];\n\n\tfor (const state of states) {\n\t\toutgoing.set(state, []);\n\t\tincoming.set(state, []);\n\t}\n\n\tfor (const state of states) {\n\t\tconst stateTransitions = stableDefinition.states[state].on;\n\t\tconst inputTypes = (\n\t\t\tObject.keys(stateTransitions ?? {}) as TInput[\"type\"][]\n\t\t).sort(compareStrings);\n\n\t\tfor (const inputType of inputTypes) {\n\t\t\tconst transition = stateTransitions?.[inputType];\n\t\t\tif (transition === undefined) continue;\n\n\t\t\toutgoing.get(state)?.push(transition.target);\n\t\t\tincoming.get(transition.target)?.push(state);\n\t\t\ttransitions.push(\n\t\t\t\tObject.freeze({\n\t\t\t\t\tstate,\n\t\t\t\t\tinputType,\n\t\t\t\t\ttarget: transition.target,\n\t\t\t\t\tguarded: transition.guard !== undefined,\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\t}\n\n\tconst structurallyReachable = visitGraph(\n\t\t[stableDefinition.initial],\n\t\toutgoing,\n\t);\n\tconst terminalStates = states.filter(\n\t\t(state) => stableDefinition.states[state].terminal === true,\n\t);\n\tconst statesWithTerminalPath = visitGraph(terminalStates, incoming);\n\tconst diagnostics: DomainMachineDefinitionDiagnostic<TState>[] = [];\n\n\tfor (const state of states) {\n\t\tif (!structurallyReachable.has(state)) {\n\t\t\tdiagnostics.push(Object.freeze({ code: \"unreachable-state\", state }));\n\t\t}\n\t}\n\tfor (const state of states) {\n\t\tif (\n\t\t\tstableDefinition.states[state].terminal !== true &&\n\t\t\toutgoing.get(state)?.length === 0\n\t\t) {\n\t\t\tdiagnostics.push(Object.freeze({ code: \"structural-dead-end\", state }));\n\t\t}\n\t}\n\tfor (const state of states) {\n\t\tif (!statesWithTerminalPath.has(state)) {\n\t\t\tdiagnostics.push(Object.freeze({ code: \"no-terminal-path\", state }));\n\t\t}\n\t}\n\n\treturn Object.freeze({\n\t\tdiagnostics: Object.freeze(diagnostics),\n\t\ttransitions: Object.freeze(transitions),\n\t\tstructurallyReachableStates: Object.freeze(\n\t\t\tstates.filter((state) => structurallyReachable.has(state)),\n\t\t),\n\t\tstatesWithTerminalPath: Object.freeze(\n\t\t\tstates.filter((state) => statesWithTerminalPath.has(state)),\n\t\t),\n\t});\n}\n\nfunction visitGraph<TState extends string>(\n\tstartStates: readonly TState[],\n\tedges: ReadonlyMap<TState, readonly TState[]>,\n): ReadonlySet<TState> {\n\tconst visited = new Set<TState>();\n\tconst pending = [...startStates];\n\n\twhile (pending.length > 0) {\n\t\tconst state = pending.pop();\n\t\tif (state === undefined || visited.has(state)) continue;\n\n\t\tvisited.add(state);\n\t\tfor (const next of edges.get(state) ?? []) {\n\t\t\tif (!visited.has(next)) pending.push(next);\n\t\t}\n\t}\n\n\treturn visited;\n}\n\nfunction compareStrings(left: string, right: string): number {\n\treturn left < right ? -1 : left > right ? 1 : 0;\n}\n","import type {\n\tDomainMachineDefinition,\n\tDomainMachineInput,\n\tDomainMachineReadonly,\n\tDomainMachineSnapshot,\n\tDomainTransitionOutcome,\n} from \"./contracts\";\nimport { ensureStableDomainMachineDefinition } from \"./definition\";\nimport { ReentrantDomainStateMachineEvaluationError } from \"./errors\";\nimport {\n\tcreateDomainMachineSnapshot,\n\tprepareDomainMachineSnapshot,\n} from \"./snapshot\";\nimport {\n\tcanTransitionPreparedDomainState,\n\tcreateInitialDomainMachineSnapshotFromPrepared,\n\ttransitionPreparedDomainState,\n} from \"./transition\";\n\nexport type {\n\tDomainMachineDefinitionAnalysis,\n\tDomainMachineDefinitionDiagnostic,\n\tDomainMachineTransitionDescription,\n} from \"./analyzer\";\nexport { analyzeDomainMachineDefinition } from \"./analyzer\";\nexport type {\n\tDomainMachineDefinition,\n\tDomainMachineInput,\n\tDomainMachineReadonly,\n\tDomainMachineSnapshot,\n\tDomainStateNode,\n\tDomainTransition,\n\tDomainTransitionGuardResult,\n\tDomainTransitionOutcome,\n\tDomainTransitionResult,\n} from \"./contracts\";\nexport {\n\ttype PreparedDomainMachineDefinition,\n\tprepareDomainMachineDefinition,\n} from \"./definition\";\nexport {\n\tDomainTransitionGuardRejectedError,\n\tInvalidDomainMachineContextError,\n\tInvalidDomainMachineDefinitionError,\n\tInvalidDomainMachineInputError,\n\tInvalidDomainMachineSnapshotError,\n\tInvalidDomainTransitionError,\n\tInvalidDomainTransitionGuardResultError,\n\tInvalidDomainTransitionResultError,\n\tReentrantDomainStateMachineEvaluationError,\n} from \"./errors\";\nexport {\n\tcanTransitionDomainState,\n\tcreateInitialDomainMachineSnapshot,\n\ttransitionDomainState,\n} from \"./transition\";\n\n/**\n * Stateful convenience wrapper around the pure domain transition functions.\n *\n * Persist {@link snapshot}, not the machine instance. Pass a restored snapshot\n * to the second constructor overload to validate and reconstitute a machine.\n */\nexport class DomainStateMachine<\n\tTState extends string,\n\tTContext,\n\tTInput extends DomainMachineInput,\n\tTOutput = never,\n> {\n\tprivate readonly definition: DomainMachineDefinition<\n\t\tTState,\n\t\tTContext,\n\t\tTInput,\n\t\tTOutput\n\t>;\n\n\t#snapshot: DomainMachineSnapshot<TState, TContext>;\n\t#evaluating = false;\n\n\tconstructor(\n\t\tdefinition: DomainMachineDefinition<TState, TContext, TInput, TOutput>,\n\t);\n\tconstructor(\n\t\tdefinition: DomainMachineDefinition<TState, TContext, TInput, TOutput>,\n\t\tsnapshot: DomainMachineSnapshot<TState, TContext> | undefined,\n\t);\n\tconstructor(\n\t\tdefinition: DomainMachineDefinition<TState, TContext, TInput, TOutput>,\n\t\t...snapshotInput: [] | [DomainMachineSnapshot<TState, TContext> | undefined]\n\t) {\n\t\t// A prepared definition (prepareDomainMachineDefinition) passes\n\t\t// through; a raw one pays the one-time validate-and-copy here.\n\t\tthis.definition = ensureStableDomainMachineDefinition(definition);\n\t\t// Resolve the overload by the argument value, not the rest-parameter\n\t\t// arity: an explicit `undefined` snapshot (a natural result of a\n\t\t// nullable `repo.loadSnapshot(id)` or `map.get(id)` passed straight\n\t\t// through) means \"no snapshot\", so it must fall back to the initial\n\t\t// snapshot instead of failing validation.\n\t\tconst [suppliedSnapshot] = snapshotInput;\n\t\tif (suppliedSnapshot !== undefined) {\n\t\t\t// One shared implementation with the pure path (transition.ts);\n\t\t\t// hand-rolling the validate-copy-validate trio here would let\n\t\t\t// the class and pure snapshot preparation drift.\n\t\t\tthis.#snapshot = prepareDomainMachineSnapshot(\n\t\t\t\tthis.definition,\n\t\t\t\tsuppliedSnapshot,\n\t\t\t);\n\t\t} else {\n\t\t\tthis.#snapshot = createInitialDomainMachineSnapshotFromPrepared(\n\t\t\t\tthis.definition,\n\t\t\t);\n\t\t}\n\t}\n\n\t/** Returns a defensive, deeply frozen copy of the current snapshot. */\n\tget snapshot(): DomainMachineSnapshot<TState, TContext> {\n\t\treturn createDomainMachineSnapshot<TState, TContext>(this.#snapshot);\n\t}\n\n\t/** Current named control state. */\n\tget state(): TState {\n\t\treturn this.#snapshot.state;\n\t}\n\n\t/** Current deeply readonly context. */\n\tget context(): DomainMachineReadonly<TContext> {\n\t\treturn this.#snapshot.context;\n\t}\n\n\t/** Whether the current state permanently forbids outgoing transitions. */\n\tisTerminal(): boolean {\n\t\treturn this.definition.states[this.state].terminal === true;\n\t}\n\n\t/** Checks a transition without changing the current snapshot. */\n\tcan(input: TInput): boolean {\n\t\treturn this.evaluate(() =>\n\t\t\tcanTransitionPreparedDomainState(this.definition, this.#snapshot, input),\n\t\t);\n\t}\n\n\t/** Applies an input and advances the current snapshot on success. */\n\tdispatch(input: TInput): DomainTransitionOutcome<TState, TContext, TOutput> {\n\t\treturn this.evaluate(() => {\n\t\t\tconst result = transitionPreparedDomainState(\n\t\t\t\tthis.definition,\n\t\t\t\tthis.#snapshot,\n\t\t\t\tinput,\n\t\t\t);\n\t\t\tthis.#snapshot = result.snapshot;\n\t\t\treturn result;\n\t\t});\n\t}\n\n\tprivate evaluate<TResult>(operation: () => TResult): TResult {\n\t\tif (this.#evaluating) {\n\t\t\tthrow new ReentrantDomainStateMachineEvaluationError();\n\t\t}\n\n\t\tthis.#evaluating = true;\n\t\ttry {\n\t\t\treturn operation();\n\t\t} finally {\n\t\t\tthis.#evaluating = false;\n\t\t}\n\t}\n}\n","import { ValidationError } from \"@shirudo/base-error\";\nimport { err, ok, type Result } from \"@shirudo/result\";\nimport { type VO, vo } from \"./value-object\";\n\n/**\n * Builds an immutable value object while collecting **all** validation\n * violations into a single {@link ValidationError}, instead of failing on the\n * first one. This is the Result-first, multi-error counterpart to\n * `voWithValidation` (which returns a single string message).\n *\n * The `validate` callback receives a fresh `ValidationError` to push field\n * issues onto (via `addIssue` / `addIssues`) and the raw input. When no issue\n * was recorded the input is frozen into a `VO<T>` and returned as `Ok`;\n * otherwise the populated `ValidationError` is returned as `Err`.\n *\n * `ValidationError` comes from `@shirudo/base-error`; import it from there to\n * narrow the `Err` branch, exactly as `Result` is imported from\n * `@shirudo/result`. At the HTTP boundary, `toProblemDetails` from\n * `@shirudo/ddd-kit/http` surfaces the issues as an RFC 9457 result.\n *\n * @example\n * ```ts\n * const result = voValidated(\n * { email, age },\n * (issues, m) => {\n * if (!isEmail(m.email))\n * issues.addIssue({ message: \"must be a valid email\", path: [\"email\"] });\n * if (m.age < 0)\n * issues.addIssue({ message: \"must not be negative\", path: [\"age\"] });\n * },\n * \"Registration is invalid\",\n * );\n * // result.isErr() → result.error.publicIssues() has both violations\n * ```\n */\nexport function voValidated<T>(\n\tt: T,\n\tvalidate: (issues: ValidationError, value: T) => void,\n\tmessage = \"Validation failed\",\n): Result<VO<T>, ValidationError> {\n\tconst issues = new ValidationError(message);\n\tvalidate(issues, t);\n\treturn issues.hasIssues() ? err(issues) : ok(vo(t));\n}\n","import {\n\tbuiltInTagWithoutInvokingAccessors,\n\thasIntrinsicPrototypeChain,\n\tisIntrinsicConstructorPrototype,\n} from \"./is-built-in\";\n\n/**\n * Returns a copy of `state` that shares no object with the original.\n * Throws a `TypeError` that names the path when the graph carries a value\n * a structured clone would lose or silently degrade. A class instance, a\n * subclass of a built-in included, loses the methods on its prototype. A\n * symbol-keyed, non-enumerable, or accessor property and an expando on a\n * built-in are dropped. A function or a symbol value throws a raw\n * `DataCloneError`. An Error, a Promise, a WeakMap, or a WeakSet cannot be\n * detached at all. A SharedArrayBuffer and a view over one keep sharing\n * their memory. A Proxy is invisible to the walk and fails inside the\n * clone; that failure is rethrown as a `TypeError` with the cause.\n *\n * Plain objects (from any realm), arrays, Dates, Maps, Sets, bigints, and\n * typed arrays pass. A RegExp passes: pattern and flags survive the clone,\n * and `lastIndex` restores as 0. The scan state of a global or sticky\n * pattern is not domain data. A non-enumerable property on a built-in\n * passes: it is the built-in's own machinery (`lastIndex`), not data. A\n * non-enumerable symbol key passes anywhere: it is metadata by convention.\n *\n * The concrete entity uses it for a detached read DTO of a plain-data\n * state. The snapshot model uses it for the captured DTO and the restored\n * state. A state that carries a class-based child is mapped to plain data\n * first, in the entity or in the model.\n */\nexport function detachState<T>(state: T): T {\n\tassertDetachable(state, \"\", new WeakSet());\n\ttry {\n\t\treturn structuredClone(state);\n\t} catch (cause) {\n\t\tthrow new TypeError(\n\t\t\t\"detachState: state holds a Proxy or a host object that cannot be cloned; map it to plain data\",\n\t\t\t{ cause },\n\t\t);\n\t}\n}\n\nconst INDEX_KEY = /^(0|[1-9]\\d*)$/;\n\nfunction assertDetachable(\n\tvalue: unknown,\n\tpath: string,\n\tseen: WeakSet<object>,\n): void {\n\tif (typeof value === \"function\") {\n\t\tthrow new TypeError(\n\t\t\t`detachState: state${path} is a function; map it to plain data`,\n\t\t);\n\t}\n\t// Guided rejection instead of the raw DataCloneError DOMException that\n\t// structuredClone throws for symbols, which no recovery channel catches.\n\tif (typeof value === \"symbol\") {\n\t\tthrow new TypeError(\n\t\t\t`detachState: state${path} is a symbol; map it to plain data`,\n\t\t);\n\t}\n\tif (value === null || typeof value !== \"object\") return;\n\tconst object = value as object;\n\tif (seen.has(object)) return;\n\tseen.add(object);\n\n\tif (Array.isArray(object)) {\n\t\tif (!hasIntrinsicPrototypeChain(object, \"Array\")) {\n\t\t\tthrowClassInstance(object, path);\n\t\t}\n\t\tassertOwnPropertiesDetachable(object, path, seen, \"array\");\n\t\treturn;\n\t}\n\n\tconst tag = builtInTagWithoutInvokingAccessors(object);\n\tif (tag !== undefined) {\n\t\tif (!hasIntrinsicPrototypeChain(object)) {\n\t\t\tthrowClassInstance(object, path);\n\t\t}\n\t\tif (tag === \"[object Map]\") {\n\t\t\tlet index = 0;\n\t\t\tfor (const [key, entry] of object as Map<unknown, unknown>) {\n\t\t\t\tassertDetachable(key, `${path}<map key #${index}>`, seen);\n\t\t\t\tassertDetachable(entry, `${path}<map value #${index}>`, seen);\n\t\t\t\tindex++;\n\t\t\t}\n\t\t} else if (tag === \"[object Set]\") {\n\t\t\tlet index = 0;\n\t\t\tfor (const member of object as Set<unknown>) {\n\t\t\t\tassertDetachable(member, `${path}<set member #${index}>`, seen);\n\t\t\t\tindex++;\n\t\t\t}\n\t\t} else if (\n\t\t\ttag === \"[object Promise]\" ||\n\t\t\ttag === \"[object WeakMap]\" ||\n\t\t\ttag === \"[object WeakSet]\"\n\t\t) {\n\t\t\tthrow new TypeError(\n\t\t\t\t`detachState: state${path} is a ${tag.slice(8, -1)} and cannot be detached`,\n\t\t\t);\n\t\t} else if (tag === \"[object Error]\") {\n\t\t\tthrow new TypeError(\n\t\t\t\t`detachState: state${path} is an Error; map it to plain data`,\n\t\t\t);\n\t\t} else if (sharesMemory(object, tag)) {\n\t\t\tthrow new TypeError(\n\t\t\t\t`detachState: state${path} is backed by a SharedArrayBuffer and the copy would share its memory; map it to plain data`,\n\t\t\t);\n\t\t}\n\t\tassertOwnPropertiesDetachable(object, path, seen, \"built-in\");\n\t\treturn;\n\t}\n\n\tconst prototype = Object.getPrototypeOf(object);\n\tconst isPlainRecord =\n\t\tprototype === null ||\n\t\t(isIntrinsicConstructorPrototype(prototype, \"Object\") &&\n\t\t\tObject.getPrototypeOf(prototype) === null);\n\tif (!isPlainRecord) {\n\t\tthrowClassInstance(object, path);\n\t}\n\tassertOwnPropertiesDetachable(object, path, seen, \"record\");\n}\n\n/**\n * Audits the own properties the clone would copy or drop. The clone keeps\n * the enumerable own keys of a record and of an array, expandos included,\n * and drops every own key of another built-in. `length` on an array and\n * the non-enumerable keys of a built-in (`lastIndex`) are its own\n * machinery, not data. Index keys of a typed array or a boxed String are\n * its content and pass as such.\n */\nfunction assertOwnPropertiesDetachable(\n\tobject: object,\n\tpath: string,\n\tseen: WeakSet<object>,\n\tkind: \"array\" | \"built-in\" | \"record\",\n): void {\n\tfor (const key of Reflect.ownKeys(object)) {\n\t\tconst descriptor = Object.getOwnPropertyDescriptor(object, key);\n\t\tif (descriptor === undefined) continue;\n\t\tif (typeof key === \"symbol\") {\n\t\t\tif (!descriptor.enumerable) continue;\n\t\t\tthrow new TypeError(\n\t\t\t\t`detachState: state${path} has a symbol-keyed property; map it to plain data`,\n\t\t\t);\n\t\t}\n\t\tif (kind === \"array\" && key === \"length\") continue;\n\t\tconst isIndex = INDEX_KEY.test(key);\n\t\tif (!descriptor.enumerable) {\n\t\t\tif (kind === \"built-in\") continue;\n\t\t\tthrow new TypeError(\n\t\t\t\t`detachState: state${path}.${key} is not enumerable and the clone would drop it; map it to plain data`,\n\t\t\t);\n\t\t}\n\t\tif (kind === \"built-in\" && isIndex) continue;\n\t\tconst memberPath = isIndex ? `${path}[${key}]` : `${path}.${key}`;\n\t\tif (!(\"value\" in descriptor)) {\n\t\t\tthrow new TypeError(\n\t\t\t\t`detachState: state${memberPath} is an accessor property; map it to plain data`,\n\t\t\t);\n\t\t}\n\t\tif (kind === \"built-in\") {\n\t\t\tthrow new TypeError(\n\t\t\t\t`detachState: state${memberPath} is an expando on a ${object.constructor?.name ?? \"built-in\"} and the clone would drop it; map it to plain data`,\n\t\t\t);\n\t\t}\n\t\tassertDetachable(descriptor.value, memberPath, seen);\n\t}\n}\n\nfunction sharesMemory(object: object, tag: string): boolean {\n\tif (tag === \"[object SharedArrayBuffer]\") return true;\n\treturn (\n\t\tArrayBuffer.isView(object) &&\n\t\tObject.prototype.toString.call(object.buffer) ===\n\t\t\t\"[object SharedArrayBuffer]\"\n\t);\n}\n\nfunction throwClassInstance(object: object, path: string): never {\n\tconst name: string =\n\t\tObject.getPrototypeOf(object)?.constructor?.name || \"anonymous class\";\n\tthrow new TypeError(\n\t\t`detachState: state${path} is a class instance (${name}); map it to plain data`,\n\t);\n}\n","import { KitWiringError } from \"../../errors/kit-errors\";\n\n/** Keeps a deep chain readable in the message without losing the recent path. */\nconst CHAIN_DISPLAY_LIMIT = 8;\n\nfunction formatChain(eventTypeChain: readonly string[]): string {\n\tif (eventTypeChain.length <= CHAIN_DISPLAY_LIMIT) {\n\t\treturn eventTypeChain.join(\" -> \");\n\t}\n\treturn `... -> ${eventTypeChain.slice(-CHAIN_DISPLAY_LIMIT).join(\" -> \")}`;\n}\n\n/**\n * Thrown when one publish chain reaches `maxPublishDepth`.\n *\n * A handler that publishes re-enters `publish`, and JavaScript bounds nothing\n * here. A synchronous cycle overflows the call stack. An asynchronous cycle\n * starves the event loop until the process runs out of memory. The publish\n * timeout cannot stop either one, because a timer is a macrotask and a starved\n * loop never runs one.\n *\n * This is a wiring error, not an infrastructure failure. The handler graph\n * contains a cycle, or the nesting is deeper than the bus permits. A retry\n * repeats the fault, so `retryable` stays false, and a generic\n * `catch (error instanceof InfrastructureError)` cannot mask it.\n *\n * The guard follows the publish chain, never the bus instance. Concurrent\n * publications on one shared bus are correct usage and never reach it.\n */\nexport class PublishDepthExceededError extends KitWiringError<\"PUBLISH_DEPTH_EXCEEDED\"> {\n\tconstructor(\n\t\tpublic readonly depth: number,\n\t\tpublic readonly maxPublishDepth: number,\n\t\tpublic readonly eventTypeChain: readonly string[],\n\t) {\n\t\tsuper(\n\t\t\t\"PUBLISH_DEPTH_EXCEEDED\",\n\t\t\t`EventBus.publish reached depth ${depth} of ${maxPublishDepth}: ` +\n\t\t\t\t`${formatChain(eventTypeChain)}. A handler publishes an event that ` +\n\t\t\t\t\"leads back into the same chain. Break the cycle, or raise \" +\n\t\t\t\t\"maxPublishDepth when the nesting is intended.\",\n\t\t);\n\t}\n}\n\n/**\n * Thrown when a closed bus is used.\n *\n * `close()` releases every subscription and settles every waiter, so the bus\n * holds nothing afterwards. A later `publish` would reach no handler and a\n * later `subscribe` would never fire, and both would look like a delivery\n * that simply did not happen.\n *\n * Use after close is a programming bug, usually a leaked reference or an\n * operation that outlived the scope that owned the bus, so this carries the\n * `WIRING` category and crashes loud rather than dropping the work in\n * silence.\n */\nexport class EventBusClosedError extends KitWiringError<\"EVENT_BUS_CLOSED\"> {\n\tconstructor(public readonly operation: string) {\n\t\tsuper(\n\t\t\t\"EVENT_BUS_CLOSED\",\n\t\t\t`Event bus is closed: ${operation} was called after close(). ` +\n\t\t\t\t\"Create one bus per scope and close it when that scope ends, \" +\n\t\t\t\t\"instead of holding a reference past it.\",\n\t\t);\n\t}\n}\n","import { ownerSignalOf } from \"../../internal/async/execution\";\n\n/**\n * Hops one ancestor walk inspects at most. A dead ancestor drops out of the\n * chain once it is collected, so a real chain stays short. This only stops a\n * pathological walk from becoming the cost of publishing.\n */\nconst WALK_LIMIT = 1024;\n\n/** Where a new publication sits on its chain. */\nexport interface PublishChainOrigin {\n\t/** Ancestors whose dispatch is still open. */\n\treadonly depth: number;\n\t/** Event types along the chain, oldest first. */\n\treadonly path: readonly string[];\n\t/** The nearest open ancestor, which the new state records as enclosing. */\n\treadonly enclosing?: PublishChainState;\n}\n\n/**\n * The event path of one publish chain.\n *\n * It carries no depth. Depth is counted from the states that are still open at\n * the moment a publication starts, so a number stored here would be the count\n * from an earlier moment and could disagree with it.\n */\nexport interface PublishChainState {\n\t/** Event types along the chain, oldest first. */\n\treadonly path: readonly string[];\n}\n\n/**\n * Carries a publish chain across an `await` when the signal cannot.\n *\n * The shape is that of `AsyncLocalStorage`. The kit does not import\n * `node:async_hooks` itself: that specifier does not resolve under the browser\n * conditions an edge bundle uses, and the kit ships one build. A consumer on\n * Node passes the platform class, and a consumer on an edge runtime passes\n * nothing.\n *\n * ```ts\n * import { AsyncLocalStorage } from \"node:async_hooks\";\n *\n * const bus = new EventBusImpl<OrderEvent>({\n * chainStore: new AsyncLocalStorage<PublishChainState>(),\n * });\n * ```\n */\nexport interface PublishChainStore {\n\trun<R>(state: PublishChainState, callback: () => R): R;\n\tgetStore(): PublishChainState | undefined;\n}\n\n/**\n * Knows how deep the publish chain of a new publication is.\n *\n * A cycle in a handler graph either overflows the call stack or starves the\n * event loop until the process runs out of memory. Bounding it needs one\n * number: the depth of the chain the caller is already on. Nothing in\n * JavaScript reports that number, so this tracks it.\n *\n * Depth follows the chain, never the bus instance. One bus is shared and\n * published to concurrently by design, so an instance counter would reject\n * correct usage.\n *\n * Three windows can see a chain, and each one is blind in a different way:\n *\n * - the **store** follows every chain and needs a consumer to inject it;\n * - the **signal** survives an `await` and needs the handler to pass\n * `context.signal`, and it ends at a signal the kit did not derive;\n * - the **synchronous window** needs nothing and ends at the first `await`.\n *\n * A window that cannot see a chain reports 0, never a wrong depth, so the\n * deepest one is the truth.\n *\n * Depth is the number of ancestors that are STILL OPEN, never a number copied\n * from the parent. That distinction is the whole guard. A cycle keeps its\n * ancestors open, because each one awaits the next, so the count grows. A\n * relay lets them finish: a handler that starts the next publication without\n * awaiting it ends, its publication ends, and the count stays flat. A copied\n * depth counts both the same way and kills a correct relay at the bound.\n *\n * One graph of states carries that. Each publication records the state it was\n * created inside, and a walk of that graph counts the states whose dispatch is\n * still open. The three windows differ only in how they find the state to\n * start the walk from.\n */\nexport class PublishChainTracker {\n\tprivate readonly store: PublishChainStore | undefined;\n\n\t// The state each publication was created inside, and the states whose\n\t// dispatch has not ended. Depth is a walk of the first, counting the\n\t// second. Weak throughout, so a chain that ends is collectable.\n\tprivate readonly enclosingState = new WeakMap<\n\t\tPublishChainState,\n\t\tPublishChainState\n\t>();\n\tprivate readonly openStates = new WeakSet<PublishChainState>();\n\n\t// The state a dispatched context belongs to. A nested publication that\n\t// carries `context.signal` finds it here, across `await`.\n\tprivate readonly stateBySignal = new WeakMap<\n\t\tAbortSignal,\n\t\tPublishChainState\n\t>();\n\n\t// The state whose synchronous window is open. A synchronous window always\n\t// runs to completion, so a concurrent publication never observes it open.\n\tprivate syncWindowState: PublishChainState | undefined;\n\n\tconstructor(store: PublishChainStore | undefined) {\n\t\tif (\n\t\t\tstore !== undefined &&\n\t\t\t(typeof store.run !== \"function\" || typeof store.getStore !== \"function\")\n\t\t) {\n\t\t\tthrow new TypeError(\n\t\t\t\t\"EventBusImpl.chainStore must provide run and getStore\",\n\t\t\t);\n\t\t}\n\t\t// Kept as the original object: the methods of AsyncLocalStorage need\n\t\t// their receiver, so copying them onto a new object would break it.\n\t\tthis.store = store;\n\t}\n\n\t/** Depth, path and enclosing state that a publication on `signal` inherits. */\n\tparentOf(signal: AbortSignal | undefined): PublishChainOrigin {\n\t\tlet deepest: PublishChainOrigin = { depth: 0, path: [] };\n\t\tfor (const start of [\n\t\t\tthis.store?.getStore(),\n\t\t\tthis.syncWindowState,\n\t\t\tthis.stateOn(signal),\n\t\t]) {\n\t\t\tconst window = this.openAncestorsFrom(start);\n\t\t\tif (window.depth > deepest.depth) deepest = window;\n\t\t}\n\t\treturn deepest;\n\t}\n\n\t/** Records the chain of the event dispatching now and runs `dispatch`. */\n\tasync whileOnEvent(\n\t\tsignal: AbortSignal,\n\t\tstate: PublishChainState,\n\t\tenclosing: PublishChainState | undefined,\n\t\tdispatch: () => Promise<void>,\n\t): Promise<void> {\n\t\tif (enclosing !== undefined) this.enclosingState.set(state, enclosing);\n\t\tthis.stateBySignal.set(signal, state);\n\t\tthis.openStates.add(state);\n\t\ttry {\n\t\t\tawait (this.store === undefined\n\t\t\t\t? dispatch()\n\t\t\t\t: this.store.run(state, dispatch));\n\t\t} finally {\n\t\t\tthis.openStates.delete(state);\n\t\t\t// The link dies with the dispatch. A relay keeps the signal of each\n\t\t\t// generation reachable, so without this the chain grows by one\n\t\t\t// ancestor per hop and every later publication walks all of them.\n\t\t\tthis.enclosingState.delete(state);\n\t\t}\n\t}\n\n\t/** Runs one handler call with the synchronous window open. */\n\tinSyncWindow<R>(state: PublishChainState, call: () => R): R {\n\t\tconst outer = this.syncWindowState;\n\t\tthis.syncWindowState = state;\n\t\ttry {\n\t\t\treturn call();\n\t\t} finally {\n\t\t\tthis.syncWindowState = outer;\n\t\t}\n\t}\n\n\t/**\n\t * Counts the still-open states above `start`, itself included.\n\t *\n\t * The path comes from the nearest open one, which already carries the\n\t * event chain up to itself.\n\t */\n\tprivate openAncestorsFrom(\n\t\tstart: PublishChainState | undefined,\n\t): PublishChainOrigin {\n\t\tlet current = start;\n\t\tlet depth = 0;\n\t\tlet path: readonly string[] = [];\n\t\tlet nearest: PublishChainState | undefined;\n\t\tlet hops = 0;\n\t\twhile (current !== undefined && hops < WALK_LIMIT) {\n\t\t\thops++;\n\t\t\tif (this.openStates.has(current)) {\n\t\t\t\tdepth++;\n\t\t\t\tif (nearest === undefined) {\n\t\t\t\t\tnearest = current;\n\t\t\t\t\tpath = current.path;\n\t\t\t\t}\n\t\t\t}\n\t\t\tcurrent = this.enclosingState.get(current);\n\t\t}\n\t\treturn { depth, path, enclosing: nearest };\n\t}\n\n\t/**\n\t * The state of the nearest dispatch on the owner chain of `signal`.\n\t *\n\t * A caller can wrap one publication in further bounded executions, and\n\t * `withCommit` does exactly that. Every hop derives a fresh signal, so an\n\t * identity check alone loses the chain at the first hop.\n\t */\n\tprivate stateOn(\n\t\tsignal: AbortSignal | undefined,\n\t): PublishChainState | undefined {\n\t\tlet current = signal;\n\t\tlet hops = 0;\n\t\twhile (current !== undefined && hops < WALK_LIMIT) {\n\t\t\thops++;\n\t\t\tconst state = this.stateBySignal.get(current);\n\t\t\tif (state !== undefined) return state;\n\t\t\tcurrent = ownerSignalOf(current);\n\t\t}\n\t\treturn undefined;\n\t}\n}\n","import type { AnyDomainEvent } from \"../../domain/event/domain-event\";\nimport { abortReason } from \"../../internal/async/abort\";\nimport {\n\tDEFAULT_EXECUTION_TIMEOUT_MS,\n\ttype ExecutionContext,\n\trunBoundedExecution,\n} from \"../../internal/async/execution\";\nimport {\n\tcaptureObserverFunctions,\n\treportToObserver,\n} from \"../../internal/observer\";\nimport { assertPositiveInteger } from \"../../internal/validate\";\nimport { EventBusClosedError, PublishDepthExceededError } from \"./errors\";\nimport type {\n\tEventBus,\n\tEventHandler,\n\tOnceOptions,\n\tPublishOptions,\n} from \"./ports\";\nimport {\n\ttype PublishChainOrigin,\n\ttype PublishChainState,\n\ttype PublishChainStore,\n\tPublishChainTracker,\n} from \"./publish-chain\";\n\n/**\n * Wraps a handler rejection as an error without ever throwing itself.\n *\n * A value with a null prototype has no string form, so `String()` on it\n * throws. A throw here would leave the failure recorded in the index list but\n * absent from the error list, and the caller would receive `undefined`.\n */\nfunction toHandlerError(reason: unknown): Error {\n\tif (reason instanceof Error) return reason;\n\tlet described: string;\n\ttry {\n\t\tdescribed = String(reason);\n\t} catch {\n\t\tdescribed = \"Event handler rejected with a value that has no string form\";\n\t}\n\t// Attach the raw reason as cause: a handler rejecting with a structured\n\t// payload must stay diagnosable, not collapse to '[object Object]'.\n\treturn new Error(described, { cause: reason });\n}\n\n/** Bound for one publish chain. Real nesting stays far below this. */\nconst DEFAULT_MAX_PUBLISH_DEPTH = 32;\n\n/**\n * Subscriptions held for one event type when the count crossed the threshold.\n */\nexport interface SubscriptionThresholdReport {\n\t/** The event type, or `null` when the subscriptions are catch-all. */\n\treadonly eventType: string | null;\n\t/** Subscriptions held at the moment of the crossing. */\n\treadonly subscriptionCount: number;\n\t/** The threshold that was crossed. */\n\treadonly threshold: number;\n}\n\n/** One handler rejected during a publication. */\nexport interface HandlerFailureReport {\n\t/** The event the handler received. */\n\treadonly event: AnyDomainEvent;\n\t/** Position of the handler in the dispatch batch for this event. */\n\treadonly index: number;\n\t/** True when `subscribeAll` registered the handler. */\n\treadonly catchAll: boolean;\n\t/** The rejection, wrapped when the handler rejected with a non-error. */\n\treadonly error: Error;\n}\n\n/** A publication ended while handlers were pending. */\nexport interface PublishAbortedReport {\n\t/** The event whose dispatch was in flight. */\n\treadonly event: AnyDomainEvent;\n\t/** Positions in the batch of the handlers that had not settled. */\n\treadonly pendingIndices: readonly number[];\n\t/** Why the publication ended, from the abort reason of the signal. */\n\treadonly reason: unknown;\n}\n\n/** Operational signals from one event bus. */\nexport interface EventBusObservers {\n\t/**\n\t * A handler rejected.\n\t *\n\t * A thrown `AggregateError` carries its failures without their\n\t * subscription, so it cannot say which handler failed. This report can:\n\t * it carries the batch position and the event.\n\t *\n\t * This reports, it does not handle. The error still reaches the caller of\n\t * `publish` under the aggregation contract.\n\t */\n\treadonly onHandlerError: (report: HandlerFailureReport) => void;\n\t/**\n\t * A timeout or an owner abort ended the publication while handlers were\n\t * pending. A pending handler continues, and its side effects still land,\n\t * because JavaScript cannot stop a running promise.\n\t *\n\t * The report names them. Without it a timed-out publication says only that\n\t * it timed out, never which handler was pending.\n\t */\n\treadonly onPublishAborted: (report: PublishAbortedReport) => void;\n\t/**\n\t * One event type crossed `maxSubscriptionsPerEventType`. Reported at the\n\t * crossing and then at each doubling, never once per `subscribe`: a real\n\t * leak never drops back, so the trend is the useful part. The report\n\t * re-arms only strictly below the threshold: a steady state that sits on\n\t * it would otherwise report once per release.\n\t *\n\t * A subscription that a request path opens without the matching\n\t * unsubscribe leaks. The symptom is memory growth, and the bus is the only\n\t * place that can name the event type. The hook is best-effort: a throw or\n\t * a rejected promise cannot affect the subscription.\n\t */\n\treadonly onSubscriptionThresholdExceeded: (\n\t\treport: SubscriptionThresholdReport,\n\t) => void;\n}\n\n/** Marks the catch-all subscriptions in the reported-once set. */\nconst CATCH_ALL = Symbol(\"EventBusImpl.subscribeAll\");\n\n/**\n * Subscriptions for one event type above which the bus reports a leak. A\n * fan-out of projections stays far below this.\n */\nconst DEFAULT_MAX_SUBSCRIPTIONS_PER_EVENT_TYPE = 32;\n\n/** Construction options for {@link EventBusImpl}. */\nexport interface EventBusOptions {\n\t/**\n\t * Subscriptions for one event type above which the bus reports through\n\t * `observers.onSubscriptionThresholdExceeded`. Default `32`.\n\t *\n\t * This reports, it never throws. A legitimate fan-out of many projections\n\t * on one event type stays possible.\n\t */\n\treadonly maxSubscriptionsPerEventType?: number;\n\t/**\n\t * Where operational signals go. Without this the bus reports nothing, and\n\t * a subscription leak stays invisible.\n\t */\n\treadonly observers?: EventBusObservers;\n\t/**\n\t * Maximum depth of one publish chain. Default `32`.\n\t *\n\t * A handler that publishes re-enters `publish`. An unbounded chain either\n\t * overflows the call stack or starves the event loop until the process runs\n\t * out of memory, and the publish timeout stops neither. Beyond this depth\n\t * the bus throws {@link PublishDepthExceededError}.\n\t *\n\t * The bound counts one publish CHAIN, never the bus instance. Concurrent\n\t * publications on one shared bus never reach it.\n\t */\n\treadonly maxPublishDepth?: number;\n\t/**\n\t * Where the publish chain is kept across an `await`.\n\t *\n\t * Without this the bus follows the chain through the signal, which holds\n\t * across its own nested operations but ends at a signal the kit did not\n\t * derive, for example one from `AbortSignal.any`. A store follows every\n\t * chain, whatever the handler does with the signal.\n\t */\n\treadonly chainStore?: PublishChainStore;\n}\n\n/**\n * Simple in-memory event bus implementation.\n * Supports multiple subscribers per event type (pub/sub pattern).\n *\n * @template Evt - The type of domain events (must extend DomainEvent)\n *\n * @example\n * ```typescript\n * const bus = new EventBusImpl<OrderEvent>();\n *\n * bus.subscribe(\"OrderCreated\", async (event) => {\n * await sendEmail(event.payload.customerId);\n * });\n *\n * bus.subscribe(\"OrderCreated\", async (event) => {\n * await logEvent(event);\n * });\n *\n * await bus.publish([orderCreatedEvent]);\n * // Both handlers will be called\n * ```\n *\n * **What this bus does not promise.** Delivery is at most once and\n * in memory. Nothing is persisted, nothing is retried, and there is\n * no dead-letter path. A process that dies mid-publish loses the\n * remaining work. Anything that must survive a crash belongs behind\n * the `Outbox` port, not here. This bus fits in-process consumers\n * whose work can be rebuilt: projections, caches, metrics.\n *\n * **Handlers must tolerate a second run.** The bus never redelivers. A\n * caller that retries after a timeout does redeliver. The handlers of\n * the first attempt can still run, or they can be finished already.\n * Make a handler idempotent, or do not retry a timed-out publish.\n *\n * **Errors name the failure, not the handler.** A rejected handler\n * reaches the caller unchanged, and an `AggregateError` carries every\n * failure in subscription order. Neither names which subscription\n * failed. `observers.onHandlerError` carries the batch position and the\n * event, so a handler no longer names itself to be identifiable.\n *\n * **A handler that publishes keeps the chain visible, or the bound cannot\n * see it.** Pass `context.signal` into the nested publication, or inject a\n * `chainStore`. A handler that does neither and publishes after an `await`\n * leaves a chain no window can follow, and the bound never fires for it.\n *\n * Such a handler re-enters `publish`, and it does so synchronously even when\n * it does not await the result. A cycle in the handler graph overflows\n * the call stack, or it starves the event loop until the process runs\n * out of memory. `timeoutMs` stops neither. A timer is a macrotask, and\n * a starved loop never runs one. Beyond `maxPublishDepth` (default 32)\n * the bus throws `PublishDepthExceededError` and names the event path.\n * The aggregation contract still applies to it. If a second handler of\n * the same event also fails, the caller receives an `AggregateError` that\n * carries the depth error, not the depth error itself.\n *\n * The bound counts one chain, never the bus. Concurrent publications on\n * one shared bus never reach it. A handler links its nested publication\n * to the chain when it passes `context.signal`. That is the same\n * practice that gives the handler cancellation. The link survives the\n * nested operations of the kit, `withCommit` included. It ends at a\n * signal the kit did not derive, for example one from `AbortSignal.any`.\n * A handler that drops the signal leaves no link at all. There, only a\n * synchronous cycle is caught.\n *\n * Pass `chainStore` to follow every chain, whatever a handler does with\n * the signal.\n *\n */\nexport class EventBusImpl<Evt extends AnyDomainEvent> implements EventBus<Evt> {\n\tprivate readonly handlers = new Map<string, EventHandler<Evt>[]>();\n\tprivate readonly catchAllHandlers: EventHandler<Evt>[] = [];\n\tprivate readonly maxPublishDepth: number;\n\n\tprivate readonly chain: PublishChainTracker;\n\tprivate closed = false;\n\t// How to settle each waiter `once()` created, cleanup included. A callback\n\t// learns that no event follows by not being called again; a promise cannot,\n\t// so closing has to settle it or it waits forever. Rejecting alone would\n\t// leave the timer armed and the abort listener attached, which is the leak\n\t// close() exists to end.\n\tprivate readonly pendingOnce = new Set<(error: Error) => void>();\n\tprivate readonly maxSubscriptionsPerEventType: number;\n\tprivate readonly observers: Readonly<EventBusObservers> | undefined;\n\t// The count at which each event type last reported. A real leak never\n\t// drops back, so reporting only the first crossing would hide the number\n\t// the operator needs. Reporting again at each doubling shows the trend and\n\t// stays quiet. Cleared when the count drops back, so a transient spike,\n\t// for example many in-flight `once` waiters, cannot mute the event type\n\t// for the rest of the process.\n\tprivate readonly reportedAt = new Map<string | symbol, number>();\n\n\tconstructor(options: EventBusOptions = {}) {\n\t\tif (options.maxPublishDepth !== undefined) {\n\t\t\tassertPositiveInteger(\n\t\t\t\t\"EventBusImpl\",\n\t\t\t\t\"maxPublishDepth\",\n\t\t\t\toptions.maxPublishDepth,\n\t\t\t);\n\t\t}\n\t\tif (options.maxSubscriptionsPerEventType !== undefined) {\n\t\t\tassertPositiveInteger(\n\t\t\t\t\"EventBusImpl\",\n\t\t\t\t\"maxSubscriptionsPerEventType\",\n\t\t\t\toptions.maxSubscriptionsPerEventType,\n\t\t\t);\n\t\t}\n\t\tthis.chain = new PublishChainTracker(options.chainStore);\n\t\tthis.maxPublishDepth = options.maxPublishDepth ?? DEFAULT_MAX_PUBLISH_DEPTH;\n\t\tthis.maxSubscriptionsPerEventType =\n\t\t\toptions.maxSubscriptionsPerEventType ??\n\t\t\tDEFAULT_MAX_SUBSCRIPTIONS_PER_EVENT_TYPE;\n\t\tthis.observers =\n\t\t\toptions.observers === undefined\n\t\t\t\t? undefined\n\t\t\t\t: captureObserverFunctions(\"EventBusImpl\", options.observers, [\n\t\t\t\t\t\t\"onSubscriptionThresholdExceeded\",\n\t\t\t\t\t\t\"onHandlerError\",\n\t\t\t\t\t\t\"onPublishAborted\",\n\t\t\t\t\t]);\n\t}\n\n\tprivate rearmSubscriptionReport(\n\t\teventType: string | null,\n\t\tsubscriptionCount: number,\n\t): void {\n\t\t// Strictly below, never at the threshold. A steady state that sits on\n\t\t// it would otherwise re-arm on every release and report once per\n\t\t// request.\n\t\tif (subscriptionCount >= this.maxSubscriptionsPerEventType) return;\n\t\tthis.reportedAt.delete(eventType ?? CATCH_ALL);\n\t}\n\n\tprivate reportSubscriptionCount(\n\t\teventType: string | null,\n\t\tsubscriptionCount: number,\n\t): void {\n\t\tconst observer = this.observers?.onSubscriptionThresholdExceeded;\n\t\tif (observer === undefined) return;\n\t\tif (subscriptionCount <= this.maxSubscriptionsPerEventType) return;\n\t\tconst key = eventType ?? CATCH_ALL;\n\t\tconst lastReportedAt = this.reportedAt.get(key);\n\t\tif (\n\t\t\tlastReportedAt !== undefined &&\n\t\t\tsubscriptionCount < lastReportedAt * 2\n\t\t) {\n\t\t\treturn;\n\t\t}\n\t\tthis.reportedAt.set(key, subscriptionCount);\n\t\treportToObserver(() =>\n\t\t\tobserver({\n\t\t\t\teventType,\n\t\t\t\tsubscriptionCount,\n\t\t\t\tthreshold: this.maxSubscriptionsPerEventType,\n\t\t\t}),\n\t\t);\n\t}\n\n\t/** See {@link EventBus.close}. */\n\tclose(): void {\n\t\tif (this.closed) return;\n\t\tthis.closed = true;\n\t\tthis.handlers.clear();\n\t\tthis.catchAllHandlers.length = 0;\n\t\tthis.reportedAt.clear();\n\t\tconst waiting = [...this.pendingOnce];\n\t\tthis.pendingOnce.clear();\n\t\tfor (const settle of waiting) {\n\t\t\ttry {\n\t\t\t\tsettle(new EventBusClosedError(\"once\"));\n\t\t\t} catch {\n\t\t\t\t// The waiters are already out of the set, so a throw here would\n\t\t\t\t// strand every waiter after this one and no later close() could\n\t\t\t\t// reach them. Closing settles all of them or none of the port\n\t\t\t\t// contract holds.\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate assertOpen(operation: string): void {\n\t\tif (this.closed) throw new EventBusClosedError(operation);\n\t}\n\n\tsubscribe<K extends Evt[\"type\"]>(\n\t\teventType: K,\n\t\thandler: EventHandler<Extract<Evt, { type: K }>>,\n\t): () => void {\n\t\tthis.assertOpen(\"subscribe\");\n\t\tconst type = eventType;\n\t\tlet handlersForType = this.handlers.get(type);\n\t\tif (handlersForType === undefined) {\n\t\t\thandlersForType = [];\n\t\t\tthis.handlers.set(type, handlersForType);\n\t\t}\n\t\tconst casted = handler as EventHandler<Evt>;\n\t\thandlersForType.push(casted);\n\t\tthis.reportSubscriptionCount(type, handlersForType.length);\n\n\t\t// Return unsubscribe: removes exactly this subscription, even if the\n\t\t// same handler reference was subscribed multiple times (each call to\n\t\t// subscribe gets its own unsubscribe).\n\t\tlet removed = false;\n\t\treturn () => {\n\t\t\tif (removed) return;\n\t\t\tconst idx = handlersForType.indexOf(casted);\n\t\t\tif (idx !== -1) {\n\t\t\t\thandlersForType.splice(idx, 1);\n\t\t\t\tremoved = true;\n\t\t\t}\n\t\t\tthis.rearmSubscriptionReport(type, handlersForType.length);\n\t\t\tif (handlersForType.length === 0) {\n\t\t\t\tthis.handlers.delete(type);\n\t\t\t}\n\t\t};\n\t}\n\n\t/** See {@link EventBus.subscribeMany}. */\n\tsubscribeMany<K extends Evt[\"type\"]>(\n\t\teventTypes: readonly K[],\n\t\thandler: EventHandler<Extract<Evt, { type: K }>>,\n\t): () => void {\n\t\tthis.assertOpen(\"subscribeMany\");\n\t\t// A set: the same type twice is one subscription, never two\n\t\t// deliveries of one event to one handler.\n\t\tconst releases = [...new Set(eventTypes)].map((eventType) =>\n\t\t\tthis.subscribe(eventType, handler),\n\t\t);\n\t\tlet released = false;\n\t\treturn () => {\n\t\t\tif (released) return;\n\t\t\treleased = true;\n\t\t\tfor (const release of releases) release();\n\t\t};\n\t}\n\n\t/**\n\t * See {@link EventBus.subscribeAll}: every published event, in the\n\t * same dispatch batch as its typed handlers.\n\t */\n\tsubscribeAll(handler: EventHandler<Evt>): () => void {\n\t\tthis.assertOpen(\"subscribeAll\");\n\t\tthis.catchAllHandlers.push(handler);\n\t\tthis.reportSubscriptionCount(null, this.catchAllHandlers.length);\n\n\t\t// Unsubscribe semantics as in subscribe(): removes exactly this\n\t\t// subscription, even when the same handler reference was\n\t\t// subscribed multiple times.\n\t\tlet removed = false;\n\t\treturn () => {\n\t\t\tif (removed) return;\n\t\t\tconst idx = this.catchAllHandlers.indexOf(handler);\n\t\t\tif (idx !== -1) {\n\t\t\t\tthis.catchAllHandlers.splice(idx, 1);\n\t\t\t\tremoved = true;\n\t\t\t}\n\t\t\tthis.rearmSubscriptionReport(null, this.catchAllHandlers.length);\n\t\t};\n\t}\n\n\tonce<K extends Evt[\"type\"]>(\n\t\teventType: K,\n\t\toptions?: OnceOptions,\n\t): Promise<Extract<Evt, { type: K }>> {\n\t\treturn new Promise<Extract<Evt, { type: K }>>((resolve, reject) => {\n\t\t\tif (this.closed) {\n\t\t\t\treject(new EventBusClosedError(\"once\"));\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst signal = options?.signal;\n\n\t\t\t// Reject synchronously if the signal is already aborted; don't\n\t\t\t// even subscribe.\n\t\t\tif (signal?.aborted) {\n\t\t\t\treject(abortReason(signal, \"EventBus.once aborted\"));\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tlet timer: ReturnType<typeof setTimeout> | undefined;\n\t\t\tlet settled = false;\n\t\t\tlet abortListener: (() => void) | undefined;\n\n\t\t\t// Assigned by the subscribe below. `once` subscribes internally, and\n\t\t\t// that can report a subscription threshold, so an observer is able\n\t\t\t// to close the bus before this binding exists. A `const` would then\n\t\t\t// be read from its temporal dead zone and the waiter would hang.\n\t\t\tlet unsubscribe: () => void = () => {};\n\t\t\tconst settleAsClosed = (error: Error): void => {\n\t\t\t\t// Reject first. A cleanup that throws, for example a signal\n\t\t\t\t// whose listener removal fails, must not keep this waiter\n\t\t\t\t// unsettled: the promise is what the caller awaits.\n\t\t\t\treject(error);\n\t\t\t\tcleanup();\n\t\t\t};\n\t\t\tconst cleanup = () => {\n\t\t\t\tif (settled) return;\n\t\t\t\tsettled = true;\n\t\t\t\tthis.pendingOnce.delete(settleAsClosed);\n\t\t\t\tunsubscribe();\n\t\t\t\tif (timer !== undefined) clearTimeout(timer);\n\t\t\t\tif (abortListener && signal) {\n\t\t\t\t\tsignal.removeEventListener(\"abort\", abortListener);\n\t\t\t\t}\n\t\t\t};\n\n\t\t\tunsubscribe = this.subscribe(eventType, (event) => {\n\t\t\t\tcleanup();\n\t\t\t\tresolve(event);\n\t\t\t});\n\t\t\t// Registered only once the subscription exists, and re-checked:\n\t\t\t// closing during that subscribe would otherwise leave this waiter\n\t\t\t// on a closed bus with nothing left to settle it.\n\t\t\tthis.pendingOnce.add(settleAsClosed);\n\t\t\tif (this.closed) {\n\t\t\t\tsettleAsClosed(new EventBusClosedError(\"once\"));\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (signal) {\n\t\t\t\tabortListener = () => {\n\t\t\t\t\tcleanup();\n\t\t\t\t\treject(abortReason(signal, \"EventBus.once aborted\"));\n\t\t\t\t};\n\t\t\t\tsignal.addEventListener(\"abort\", abortListener);\n\t\t\t}\n\n\t\t\tif (typeof options?.timeoutMs === \"number\") {\n\t\t\t\ttimer = setTimeout(() => {\n\t\t\t\t\tcleanup();\n\t\t\t\t\treject(\n\t\t\t\t\t\tnew Error(\n\t\t\t\t\t\t\t`EventBus.once timed out after ${options.timeoutMs}ms waiting for \"${eventType}\"`,\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\t}, options.timeoutMs);\n\t\t\t}\n\t\t});\n\t}\n\n\t/**\n\t * See {@link EventBus.publish} for the full ordering / parallelism /\n\t * error-aggregation contract this implementation realizes:\n\t * - events in input order, sequentially;\n\t * - handlers within one event in parallel via `Promise.allSettled`;\n\t * - errors collected and thrown after the batch (single Error, or\n\t * `AggregateError` for multiple failures).\n\t */\n\tasync publish(\n\t\tevents: ReadonlyArray<Evt>,\n\t\toptions: PublishOptions = {},\n\t): Promise<void> {\n\t\tthis.assertOpen(\"publish\");\n\t\t// The errors array lives HERE, outside the bounded execution: the\n\t\t// abort/timeout race can reject while handlers already failed, and\n\t\t// the port contract promises that collected handler errors are\n\t\t// thrown after dispatch. An abort ends the batch but must not\n\t\t// swallow the failures that already happened.\n\t\t// Depth comes from the chain, never from the instance: one bus is\n\t\t// published to concurrently by design. Three windows can see a chain,\n\t\t// and a window that cannot see it reports 0, never a wrong depth, so\n\t\t// the deepest one is the truth. Depth and path come from that same\n\t\t// window, so a reported depth and the path beside it cannot describe\n\t\t// different chains. Each window counts only while its own dispatch\n\t\t// runs; the fields say why.\n\t\tconst parent = this.chain.parentOf(options.signal);\n\t\tconst depth = parent.depth + 1;\n\t\t// An empty batch dispatches nothing, so it cannot extend a chain and\n\t\t// must not meet the bound. Everything else still runs, so an invalid\n\t\t// option is still rejected. Only the first event is about to dispatch,\n\t\t// and naming the rest would put events on the chain that never\n\t\t// reached it.\n\t\tconst [first] = events;\n\t\tif (first !== undefined && depth > this.maxPublishDepth) {\n\t\t\tthrow new PublishDepthExceededError(depth, this.maxPublishDepth, [\n\t\t\t\t...parent.path,\n\t\t\t\tfirst.type,\n\t\t\t]);\n\t\t}\n\n\t\tconst errors: Error[] = [];\n\t\ttry {\n\t\t\tawait runBoundedExecution(\n\t\t\t\t\"EventBus.publish\",\n\t\t\t\t{\n\t\t\t\t\tsignal: options.signal,\n\t\t\t\t\ttimeoutMs: options.timeoutMs ?? DEFAULT_EXECUTION_TIMEOUT_MS,\n\t\t\t\t},\n\t\t\t\t(context) =>\n\t\t\t\t\tthis.publishWithinContext(events, context, errors, depth, parent),\n\t\t\t);\n\t\t} catch (boundedError) {\n\t\t\tif (errors.length === 0) throw boundedError;\n\t\t\tthrow new AggregateError(\n\t\t\t\t[\n\t\t\t\t\tboundedError instanceof Error\n\t\t\t\t\t\t? boundedError\n\t\t\t\t\t\t: new Error(String(boundedError), { cause: boundedError }),\n\t\t\t\t\t...errors,\n\t\t\t\t],\n\t\t\t\t\"EventBus.publish aborted after handler failures\",\n\t\t\t);\n\t\t}\n\t\tif (errors.length === 1) {\n\t\t\tthrow errors[0];\n\t\t}\n\t\tif (errors.length > 1) {\n\t\t\tthrow new AggregateError(errors, \"Multiple event handlers failed\");\n\t\t}\n\t}\n\n\tprivate async publishWithinContext(\n\t\tevents: ReadonlyArray<Evt>,\n\t\tcontext: ExecutionContext,\n\t\terrors: Error[],\n\t\tdepth: number,\n\t\tparent: PublishChainOrigin,\n\t): Promise<void> {\n\t\t// One abort check for each event, after its dispatch. A check before\n\t\t// the dispatch cannot fire: an already aborted signal never reaches\n\t\t// here, because the bounded execution returns before it calls this,\n\t\t// and the check below ends the loop before the next event starts.\n\t\tfor (const event of events) {\n\t\t\t// Closing during a batch ends it. Dispatching the rest to the\n\t\t\t// subscriptions that close() released would resolve as if every\n\t\t\t// event had been delivered.\n\t\t\tthis.assertOpen(\"publish\");\n\t\t\t// The chain is recorded for the event that dispatches now, never for\n\t\t\t// the whole batch: an event that has not dispatched yet is not on\n\t\t\t// the chain, and naming it in a cycle report is wrong.\n\t\t\tconst state: PublishChainState = {\n\t\t\t\tpath: [...parent.path, event.type],\n\t\t\t};\n\t\t\tawait this.chain.whileOnEvent(\n\t\t\t\tcontext.signal,\n\t\t\t\tstate,\n\t\t\t\tparent.enclosing,\n\t\t\t\t() => this.dispatchEvent(event, context, errors, state),\n\t\t\t);\n\t\t\tif (context.signal.aborted) {\n\t\t\t\tthrow abortReason(context.signal, \"EventBus.publish aborted\");\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate async dispatchEvent(\n\t\tevent: Evt,\n\t\tcontext: ExecutionContext,\n\t\terrors: Error[],\n\t\tstate: PublishChainState,\n\t): Promise<void> {\n\t\t// Typed and catch-all handlers share ONE allSettled batch, so the\n\t\t// contract holds across both kinds: none sees the others' errors,\n\t\t// none is skipped when a peer fails. Snapshot so a handler\n\t\t// unsubscribing during dispatch doesn't shift indices while we\n\t\t// iterate. `typedCount` is part of that snapshot: the typed array is\n\t\t// live, and an unsubscribe would otherwise turn a typed handler into a\n\t\t// reported catch-all.\n\t\tconst typed = this.handlers.get(event.type) ?? [];\n\t\tconst batch = [...typed, ...this.catchAllHandlers];\n\t\tconst typedCount = typed.length;\n\t\tif (batch.length === 0) return;\n\n\t\t// Each failure is recorded the moment it happens, not after the\n\t\t// whole batch settles: a hung peer would otherwise trap a\n\t\t// settled rejection inside allSettled, invisible to the\n\t\t// abort/timeout path that ends the publish.\n\t\tconst batchStart = errors.length;\n\t\tconst failedIndices: number[] = [];\n\t\t// A handler that never returns stays pending. On abort the bus reports\n\t\t// the pending handlers, because the thrown TimeoutError names only the\n\t\t// publication, never the handler that did not return.\n\t\tconst settledIndices = new Set<number>();\n\t\tconst reportPending = (): void => {\n\t\t\tconst observer = this.observers?.onPublishAborted;\n\t\t\tif (observer === undefined) return;\n\t\t\t// One microtask later. A handler that returned an already resolved\n\t\t\t// promise settles in that window, and calling it pending would tell\n\t\t\t// an operator the opposite of the truth.\n\t\t\tqueueMicrotask(() => {\n\t\t\t\tconst pendingIndices = batch\n\t\t\t\t\t.map((_, index) => index)\n\t\t\t\t\t.filter((index) => !settledIndices.has(index));\n\t\t\t\tif (pendingIndices.length === 0) return;\n\t\t\t\treportToObserver(() =>\n\t\t\t\t\tobserver({ event, pendingIndices, reason: context.signal.reason }),\n\t\t\t\t);\n\t\t\t});\n\t\t};\n\t\tcontext.signal.addEventListener(\"abort\", reportPending, { once: true });\n\t\ttry {\n\t\t\tawait Promise.allSettled(\n\t\t\t\tbatch.map(async (handler, index) => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\t// `handler(...)` returns at its first `await`, so this\n\t\t\t\t\t\t// window covers exactly the synchronous part of the\n\t\t\t\t\t\t// handler. Splitting the call from the `await` keeps a\n\t\t\t\t\t\t// synchronous throw on the same path as a rejection.\n\t\t\t\t\t\tconst running = this.chain.inSyncWindow(state, () =>\n\t\t\t\t\t\t\thandler(event, context),\n\t\t\t\t\t\t);\n\t\t\t\t\t\t// A handler that returned without a promise is not pending.\n\t\t\t\t\t\t// Mark it here, because a peer that aborts synchronously\n\t\t\t\t\t\t// runs before this wrapper resumes.\n\t\t\t\t\t\tif (typeof (running as { then?: unknown })?.then !== \"function\") {\n\t\t\t\t\t\t\tsettledIndices.add(index);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tawait running;\n\t\t\t\t\t} catch (reason) {\n\t\t\t\t\t\t// Wrap first. An index without its error desynchronizes the\n\t\t\t\t\t\t// reorder below and puts `undefined` in front of the caller.\n\t\t\t\t\t\tconst error = toHandlerError(reason);\n\t\t\t\t\t\tfailedIndices.push(index);\n\t\t\t\t\t\terrors.push(error);\n\t\t\t\t\t\tconst observer = this.observers?.onHandlerError;\n\t\t\t\t\t\tif (observer !== undefined) {\n\t\t\t\t\t\t\treportToObserver(() =>\n\t\t\t\t\t\t\t\tobserver({\n\t\t\t\t\t\t\t\t\tevent,\n\t\t\t\t\t\t\t\t\tindex,\n\t\t\t\t\t\t\t\t\tcatchAll: index >= typedCount,\n\t\t\t\t\t\t\t\t\terror,\n\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t} finally {\n\t\t\t\t\t\tsettledIndices.add(index);\n\t\t\t\t\t}\n\t\t\t\t}),\n\t\t\t);\n\t\t} finally {\n\t\t\tcontext.signal.removeEventListener(\"abort\", reportPending);\n\t\t}\n\t\t// A settled batch reports its failures in subscription order\n\t\t// (the aggregation contract); recording order above is\n\t\t// settlement order so an abort mid-batch already sees them.\n\t\tconst settled = errors.splice(batchStart);\n\t\terrors.push(\n\t\t\t...failedIndices\n\t\t\t\t.map((index, i) => ({ index, error: settled[i] as Error }))\n\t\t\t\t.sort((a, b) => a.index - b.index)\n\t\t\t\t.map((entry) => entry.error),\n\t\t);\n\t}\n}\n","import type { AggregateAddress } from \"../../domain/aggregate/aggregate-address\";\nimport {\n\ttype AnyDomainEvent,\n\tcreateDomainEvent,\n\ttype DomainEvent,\n\ttype EventMetadata,\n} from \"../../domain/event/domain-event\";\nimport { deepFreeze } from \"../../domain/value-object/value-object\";\nimport { InvalidIntegrationMessageError } from \"../../errors/kit-errors\";\nimport {\n\tassertJsonValue,\n\tisJsonObject,\n\ttype JsonObject,\n\ttype JsonValue,\n} from \"../../internal/json-value\";\nimport type { CommitPosition, CommittedDomainEvent } from \"../committed-event\";\n\nexport type {\n\tJsonObject,\n\tJsonPrimitive,\n\tJsonValue,\n} from \"../../internal/json-value\";\n\n/** Standard relationship headers carried by the public message envelope. */\nexport interface IntegrationMessageRelationships {\n\t/** Groups messages that belong to one operation or trace. */\n\treadonly correlationId?: string;\n\t/** Groups a long-running business interaction across several correlations. */\n\treadonly conversationId?: string;\n\t/** Identifies the message, event, or command that immediately caused this one. */\n\treadonly causationId?: string;\n}\n\n/** Application-owned public content produced from one internal domain event. */\nexport interface IntegrationMessageContent<\n\tTType extends string,\n\tTPayload extends JsonValue,\n\tTMetadata extends JsonObject = JsonObject,\n> extends IntegrationMessageRelationships {\n\treadonly type: TType;\n\treadonly version: number;\n\treadonly payload: TPayload;\n\t/** Custom JSON metadata; relationship header names are reserved. */\n\treadonly metadata?: TMetadata;\n}\n\n/**\n * JSON-safe broker envelope, deliberately separate from {@link DomainEvent}.\n * Standard message relationships are explicit headers rather than payload or\n * custom metadata. Its source cursor supports ordered, gap-aware projection\n * consumption.\n */\nexport interface IntegrationMessage<\n\tTType extends string = string,\n\tTPayload extends JsonValue = JsonValue,\n\tTMetadata extends JsonObject = JsonObject,\n> extends IntegrationMessageContent<TType, TPayload, TMetadata> {\n\treadonly messageId: string;\n\treadonly occurredAt: string;\n\treadonly source: AggregateAddress;\n\treadonly position: CommitPosition;\n}\n\n/** Maps a private domain event to its explicit public message schema. */\nexport type IntegrationMessageMapper<\n\tEvt extends AnyDomainEvent,\n\tTType extends string,\n\tTPayload extends JsonValue,\n\tTMetadata extends JsonObject = JsonObject,\n> = (event: Evt) => IntegrationMessageContent<TType, TPayload, TMetadata>;\n\n/**\n * Maps a committed domain event to a deeply frozen JSON-safe message. The\n * mapper explicitly chooses every public relationship header; producer-private\n * domain metadata is never copied implicitly. Values JSON would change or\n * discard reject as {@link InvalidIntegrationMessageError}.\n */\nexport function createIntegrationMessage<\n\tEvt extends AnyDomainEvent,\n\tTType extends string,\n\tTPayload extends JsonValue,\n\tTMetadata extends JsonObject = JsonObject,\n>(\n\trecord: CommittedDomainEvent<Evt>,\n\tmapper: IntegrationMessageMapper<Evt, TType, TPayload, TMetadata>,\n): IntegrationMessage<TType, TPayload, TMetadata> {\n\tconst content = mapper(record.event);\n\treturn stabilizeIntegrationMessage({\n\t\tmessageId: record.event.eventId,\n\t\ttype: content.type,\n\t\tversion: content.version,\n\t\toccurredAt: record.event.occurredAt.toISOString(),\n\t\t...relationshipHeaders(content),\n\t\tpayload: content.payload,\n\t\t...(content.metadata === undefined ? {} : { metadata: content.metadata }),\n\t\tsource: record.source,\n\t\tposition: record.position,\n\t});\n}\n\n/** Validates and serializes an integration message without lossy coercion. */\nexport function encodeIntegrationMessage(message: IntegrationMessage): string {\n\tassertIntegrationMessage(message);\n\treturn JSON.stringify(message);\n}\n\n/**\n * Parses and validates a broker body, normalizes supported RFC 3339 timestamps\n * to canonical UTC milliseconds, then defensively copies and deeply freezes it.\n */\nexport function decodeIntegrationMessage(\n\tserialized: string,\n): IntegrationMessage {\n\ttry {\n\t\treturn stabilizeIntegrationMessage(JSON.parse(serialized), \"wire\");\n\t} catch (error) {\n\t\tif (error instanceof InvalidIntegrationMessageError) throw error;\n\t\tthrow new InvalidIntegrationMessageError(\n\t\t\t\"$\",\n\t\t\t\"body is not valid JSON\",\n\t\t\terror,\n\t\t);\n\t}\n}\n\n/**\n * Composes a validated public message into a minted local projector input.\n * Relationship headers become local event metadata. The public JSON schema is\n * retained; producer-private domain types are not reconstructed.\n */\nexport function integrationMessageToCommittedEvent<\n\tTType extends string,\n\tTPayload extends JsonValue,\n\tTMetadata extends JsonObject = JsonObject,\n>(\n\tmessage: IntegrationMessage<TType, TPayload, TMetadata>,\n): CommittedDomainEvent<DomainEvent<TType, TPayload>> {\n\tconst stableMessage = stabilizeIntegrationMessage(message);\n\tconst metadata = localEventMetadata(stableMessage);\n\treturn {\n\t\tevent: createDomainEvent(stableMessage.type, stableMessage.payload, {\n\t\t\teventId: stableMessage.messageId,\n\t\t\taggregateId: stableMessage.source.aggregateId,\n\t\t\taggregateType: stableMessage.source.aggregateType,\n\t\t\toccurredAt: new Date(stableMessage.occurredAt),\n\t\t\tschemaVersion: stableMessage.version,\n\t\t\tmetadata,\n\t\t}),\n\t\tsource: stableMessage.source,\n\t\tposition: stableMessage.position,\n\t};\n}\n\nfunction stabilizeIntegrationMessage<T>(\n\tvalue: T,\n\ttimestampFormat: \"canonical\" | \"wire\" = \"canonical\",\n): T {\n\tassertIntegrationMessage(value, timestampFormat);\n\tconst copy = JSON.parse(JSON.stringify(value));\n\tif (timestampFormat === \"wire\") {\n\t\tcopy.occurredAt = normalizeWireTimestamp(copy.occurredAt);\n\t}\n\treturn deepFreeze(copy) as T;\n}\n\nfunction assertIntegrationMessage(\n\tvalue: unknown,\n\ttimestampFormat: \"canonical\" | \"wire\" = \"canonical\",\n): asserts value is IntegrationMessage {\n\tassertJsonValue(value, \"$\", invalid);\n\tif (!isJsonObject(value)) {\n\t\tinvalid(\"$\", \"envelope must be a plain JSON object\");\n\t}\n\tif (typeof value.messageId !== \"string\" || value.messageId.length === 0) {\n\t\tinvalid(\"$.messageId\", \"must be a non-empty string\");\n\t}\n\tfor (const field of RELATIONSHIP_FIELDS) {\n\t\tif (!Object.hasOwn(value, field)) continue;\n\t\tconst relationshipId = value[field];\n\t\tif (typeof relationshipId !== \"string\" || relationshipId.length === 0) {\n\t\t\tinvalid(`$.${field}`, \"must be a non-empty string when present\");\n\t\t}\n\t}\n\tif (typeof value.type !== \"string\" || value.type.length === 0) {\n\t\tinvalid(\"$.type\", \"must be a non-empty string\");\n\t}\n\tconst version = value.version;\n\tif (\n\t\ttypeof version !== \"number\" ||\n\t\t!Number.isInteger(version) ||\n\t\tversion < 1\n\t) {\n\t\tinvalid(\"$.version\", \"must be an integer >= 1\");\n\t}\n\tif (\n\t\ttypeof value.occurredAt !== \"string\" ||\n\t\t(timestampFormat === \"canonical\"\n\t\t\t? !isCanonicalIsoTimestamp(value.occurredAt)\n\t\t\t: normalizeWireTimestamp(value.occurredAt) === undefined)\n\t) {\n\t\tinvalid(\n\t\t\t\"$.occurredAt\",\n\t\t\ttimestampFormat === \"canonical\"\n\t\t\t\t? \"must be a canonical UTC ISO-8601 timestamp\"\n\t\t\t\t: \"must be an RFC 3339 timestamp with an explicit offset and at most millisecond precision\",\n\t\t);\n\t}\n\tif (!Object.hasOwn(value, \"payload\")) {\n\t\tinvalid(\"$.payload\", \"is required (use null for an empty JSON payload)\");\n\t}\n\tif (\n\t\tObject.hasOwn(value, \"metadata\") &&\n\t\tvalue.metadata !== undefined &&\n\t\t!isJsonObject(value.metadata)\n\t) {\n\t\tinvalid(\"$.metadata\", \"must be a plain JSON object when present\");\n\t}\n\tif (isJsonObject(value.metadata)) {\n\t\tfor (const field of RELATIONSHIP_FIELDS) {\n\t\t\tif (Object.hasOwn(value.metadata, field)) {\n\t\t\t\tinvalid(\n\t\t\t\t\t`$.metadata.${field}`,\n\t\t\t\t\t\"is reserved for the explicit message envelope header\",\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\tif (!isJsonObject(value.source)) {\n\t\tinvalid(\"$.source\", \"must be a plain JSON object\");\n\t}\n\tif (\n\t\ttypeof value.source.aggregateType !== \"string\" ||\n\t\tvalue.source.aggregateType.length === 0\n\t) {\n\t\tinvalid(\"$.source.aggregateType\", \"must be a non-empty string\");\n\t}\n\tif (\n\t\ttypeof value.source.aggregateId !== \"string\" ||\n\t\tvalue.source.aggregateId.length === 0\n\t) {\n\t\tinvalid(\"$.source.aggregateId\", \"must be a non-empty string\");\n\t}\n\tif (!isJsonObject(value.position)) {\n\t\tinvalid(\"$.position\", \"must be a plain JSON object\");\n\t}\n\tconst { position } = value;\n\tconst aggregateVersion = position.aggregateVersion;\n\tif (\n\t\ttypeof aggregateVersion !== \"number\" ||\n\t\t!Number.isInteger(aggregateVersion) ||\n\t\taggregateVersion < 0\n\t) {\n\t\tinvalid(\"$.position.aggregateVersion\", \"must be an integer >= 0\");\n\t}\n\tconst commitSequence = position.commitSequence;\n\tif (\n\t\ttypeof commitSequence !== \"number\" ||\n\t\t!Number.isInteger(commitSequence) ||\n\t\tcommitSequence < 0\n\t) {\n\t\tinvalid(\"$.position.commitSequence\", \"must be an integer >= 0\");\n\t}\n\tconst commitSize = position.commitSize;\n\tif (\n\t\ttypeof commitSize !== \"number\" ||\n\t\t!Number.isInteger(commitSize) ||\n\t\tcommitSize <= commitSequence\n\t) {\n\t\tinvalid(\n\t\t\t\"$.position.commitSize\",\n\t\t\t\"must be a positive integer greater than commitSequence\",\n\t\t);\n\t}\n\tif (!Object.hasOwn(position, \"previousEventfulAggregateVersion\")) {\n\t\tinvalid(\n\t\t\t\"$.position.previousEventfulAggregateVersion\",\n\t\t\t\"is required (use null at genesis)\",\n\t\t);\n\t}\n\tconst previous = position.previousEventfulAggregateVersion;\n\tif (\n\t\tprevious !== null &&\n\t\t(typeof previous !== \"number\" ||\n\t\t\t!Number.isInteger(previous) ||\n\t\t\tprevious < 0 ||\n\t\t\tprevious >= aggregateVersion)\n\t) {\n\t\tinvalid(\n\t\t\t\"$.position.previousEventfulAggregateVersion\",\n\t\t\t\"must be null at genesis or an earlier non-negative aggregate version\",\n\t\t);\n\t}\n}\n\nconst RELATIONSHIP_FIELDS = [\n\t\"correlationId\",\n\t\"conversationId\",\n\t\"causationId\",\n] as const;\n\nfunction relationshipHeaders(\n\tprimary: IntegrationMessageRelationships,\n): IntegrationMessageRelationships {\n\tconst { correlationId, conversationId, causationId } = primary;\n\treturn {\n\t\t...(correlationId === undefined ? {} : { correlationId }),\n\t\t...(conversationId === undefined ? {} : { conversationId }),\n\t\t...(causationId === undefined ? {} : { causationId }),\n\t};\n}\n\nfunction localEventMetadata(\n\tmessage: IntegrationMessage,\n): EventMetadata | undefined {\n\tconst relationships = relationshipHeaders(message);\n\tif (\n\t\tmessage.metadata === undefined &&\n\t\tObject.keys(relationships).length === 0\n\t) {\n\t\treturn undefined;\n\t}\n\treturn { ...message.metadata, ...relationships };\n}\n\nfunction isCanonicalIsoTimestamp(value: string): boolean {\n\tconst timestamp = new Date(value);\n\treturn (\n\t\t!Number.isNaN(timestamp.getTime()) && timestamp.toISOString() === value\n\t);\n}\n\nconst WIRE_TIMESTAMP =\n\t/^(\\d{4})-(\\d{2})-(\\d{2})T(\\d{2}):(\\d{2}):(\\d{2})(?:\\.(\\d{1,3}))?(Z|[+-](\\d{2}):(\\d{2}))$/;\n\nfunction normalizeWireTimestamp(value: string): string | undefined {\n\tconst match = WIRE_TIMESTAMP.exec(value);\n\tif (match === null) return undefined;\n\n\tconst [\n\t\t,\n\t\tyear,\n\t\tmonth,\n\t\tday,\n\t\thour,\n\t\tminute,\n\t\tsecond,\n\t\t,\n\t\t,\n\t\toffsetHour,\n\t\toffsetMinute,\n\t] = match;\n\tconst numericYear = Number(year);\n\tconst numericMonth = Number(month);\n\tconst numericDay = Number(day);\n\tif (\n\t\tnumericMonth < 1 ||\n\t\tnumericMonth > 12 ||\n\t\tnumericDay < 1 ||\n\t\tnumericDay > daysInMonth(numericYear, numericMonth) ||\n\t\tNumber(hour) > 23 ||\n\t\tNumber(minute) > 59 ||\n\t\tNumber(second) > 59 ||\n\t\t(offsetHour !== undefined && Number(offsetHour) > 23) ||\n\t\t(offsetMinute !== undefined && Number(offsetMinute) > 59)\n\t) {\n\t\treturn undefined;\n\t}\n\n\tconst timestamp = new Date(value);\n\treturn Number.isNaN(timestamp.getTime())\n\t\t? undefined\n\t\t: timestamp.toISOString();\n}\n\nfunction daysInMonth(year: number, month: number): number {\n\tif (month === 2) {\n\t\treturn year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0) ? 29 : 28;\n\t}\n\treturn month === 4 || month === 6 || month === 9 || month === 11 ? 30 : 31;\n}\n\nfunction invalid(path: string, reason: string): never {\n\tthrow new InvalidIntegrationMessageError(path, reason);\n}\n","import {\n\ttype AggregateAddress,\n\tencodeAggregateAddress,\n} from \"../../domain/aggregate/aggregate-address\";\nimport type { AnyDomainEvent } from \"../../domain/event/domain-event\";\nimport {\n\tEventHarvestError,\n\tInMemoryCapacityExceededError,\n} from \"../../errors/kit-errors\";\nimport {\n\tassertPositiveInteger,\n\tassertPositiveSafeInteger,\n} from \"../../internal/validate\";\nimport type {\n\tEventCommitCandidate,\n\tEventCommitCandidatePosition,\n} from \"../committed-event\";\nimport type {\n\tDeadLetterRecord,\n\tDispatchTrackingOutbox,\n\tOutboxRecord,\n\tOutboxWriter,\n} from \"./ports\";\n\n/**\n * An {@link OutboxWriter} that deliberately drops every event: the\n * no-op (noop) writer, named for its consequence rather than its\n * mechanism, so the call site reads as the decision it is.\n *\n * `withCommit` and `UnitOfWork` require an outbox on purpose: the\n * asymmetry against the optional `bus` is the design. The bus is the\n * best-effort in-process fast path (post-commit, no durability), so it\n * may be omitted; the outbox is the delivery GUARANTEE, so running\n * without one is a decision, not a default. This writer is that\n * decision, made readable at the call site.\n *\n * Legitimate uses: aggregates that emit no events (`TEvent = never`,\n * nothing will ever be written), and deliberate best-effort setups\n * where the in-process bus is the only delivery and event loss on a\n * crash between commit and publish is ACCEPTED. Do not reach for an\n * undrained `InMemoryOutbox` instead: its pending map grows unbounded\n * (see the class docs).\n *\n * The name is long on purpose, same discipline as\n * `setStateWithoutVersionBump`: the dangerous variant carries the loud\n * name.\n */\nexport function outboxWriterAcceptingEventLoss<\n\tEvt extends AnyDomainEvent,\n>(): OutboxWriter<Evt> {\n\treturn {\n\t\tadd: async () => {},\n\t};\n}\n\n/** Construction options for {@link InMemoryOutbox}. */\nexport interface InMemoryOutboxOptions {\n\t/** Maximum records retained across pending and dead-letter states. */\n\treadonly maxRecords?: number;\n\n\t/** Maximum qualified aggregate source cursors retained by this instance. */\n\treadonly maxSources?: number;\n\n\t/**\n\t * Failed-delivery ceiling: once `markFailed` has been reported this\n\t * many times for a record, it moves to {@link InMemoryOutbox.deadLetters}\n\t * and stops coming back from `getPending`. Default `5`.\n\t */\n\tmaxDeliveryAttempts?: number;\n\n\t/**\n\t * Maximum recently dispatched event receipts (id, qualified source, and\n\t * candidate commit position) retained for idempotent `add` retries and\n\t * collision detection. Older receipts are evicted in dispatch order; a later\n\t * candidate behind its source head then rejects instead of rewinding the\n\t * cursor.\n\t * Default `10_000`.\n\t */\n\tmaxRetainedDispatchedEventIds?: number;\n}\n\ntype TrackedRecord<Evt extends AnyDomainEvent> = {\n\tdispatchId: string;\n\tevent: Evt;\n\tsource: OutboxRecord<Evt>[\"source\"];\n\tposition: OutboxRecord<Evt>[\"position\"];\n\tattempts: number;\n\tlastError?: string;\n};\n\ntype EventSourceCursor = {\n\taggregateVersion: number;\n\tpreviousEventfulAggregateVersion: number | null;\n\tcommitSize: number;\n\teventIdsBySequence: ReadonlyMap<number, string>;\n};\n\ntype DispatchedEventReceipt = {\n\treadonly source: AggregateAddress;\n\treadonly position: EventCommitCandidatePosition;\n};\n\n/**\n * In-memory reference implementation of `DispatchTrackingOutbox<Evt>`\n * (and therefore of the plain `Outbox<Evt>` port).\n *\n * Intended for finite-lifetime tests and quick-start demos. Without\n * `maxRecords` and `maxSources`, active delivery state and source cursors are\n * unbounded. Long-lived processes must configure both limits or use a durable\n * adapter. Exhaustion rejects the complete `add` batch before mutation;\n * correctness state is never silently evicted.\n * Uses the event's own `eventId` as the dispatch id: the common, clean\n * choice. Active storage is a `Map` keyed by `eventId`, and a bounded\n * recent-dispatch receipt cache keeps retries idempotent after acknowledgement.\n * Re-adding a pending event refreshes the stored commit envelope while the\n * delivery attempt count survives. Its commit sequence and size remain\n * immutable; only this transaction-unaware adapter may move a still-pending\n * event to another aggregate version after an outer rollback leaked the first\n * add. Dead-lettered and acknowledged retries must match the complete original\n * candidate receipt. Reusing an `eventId` for another source or commit position\n * throws {@link EventHarvestError} while the pending, dead-letter, or bounded\n * dispatched receipt still proves the collision. Insertion order is preserved:\n * `getPending` returns records in commit order, as the port contract requires.\n *\n * Dispatch tracking: `markFailed` increments the record's attempt count\n * and, at `maxDeliveryAttempts`, moves it to the dead-letter set\n * exposed by `deadLetters()`. Re-`add`ing a dead-lettered event\n * requeues it with a fresh attempts budget (the operator-facing\n * inverse of `deadLetters()`); `markDispatched` acks pending AND\n * dead-lettered records (manual redelivery then ack).\n * To link future eventful commits, the implementation also retains one\n * source cursor per qualified aggregate after dispatch. Consequently a\n * long-lived instance is bounded only when `maxRecords` and `maxSources` are\n * configured, plus `maxRetainedDispatchedEventIds`; use a durable adapter with\n * an explicit source-head lifecycle and an event-id unique key for unbounded\n * production workloads.\n *\n * For production, back the outbox with a transactional store so the\n * outbox row participates in the same transaction as the aggregate\n * write (see `TransactionScope` + `withCommit`). This class lives in\n * memory only: events are lost on process restart. Do NOT use it as a\n * dummy for bus-only setups without a dispatcher draining it: records\n * that are never `markDispatched` accumulate until `maxRecords` rejects a new\n * add, or without that option grow unbounded. For a deliberate no-delivery\n * setup use {@link outboxWriterAcceptingEventLoss} instead. Sharper still:\n * events `add()`ed inside a transaction that later rolls back are NOT\n * removed (the Map knows nothing about your scope's rollback). Tests\n * that assert rollback purity need an outbox that participates in the\n * test store's transactional semantics; see the reference adapter at\n * https://github.com/shi-rudo/ddd-kit-ts/blob/main/src/testing/repository-contract.test.ts\n * (repo-only, not shipped to npm).\n *\n * @example\n * ```ts\n * import { InMemoryOutbox, EventBusImpl } from \"@shirudo/ddd-kit\";\n *\n * const outbox = new InMemoryOutbox<OrderEvent>();\n * const bus = new EventBusImpl<OrderEvent>();\n *\n * const uow = makeOrderUnitOfWork({ outbox, bus });\n * await uow.run(async ({ repositories }) => {\n * const order = await repositories.orders.getById(id);\n * order.confirm();\n * repositories.orders.update(order);\n * return order.id;\n * });\n * ```\n */\nexport class InMemoryOutbox<Evt extends AnyDomainEvent>\n\timplements DispatchTrackingOutbox<Evt>\n{\n\tprivate readonly pending = new Map<string, TrackedRecord<Evt>>();\n\tprivate readonly dead = new Map<string, DeadLetterRecord<Evt>>();\n\t/** Latest eventful commit and its predecessor per qualified source. */\n\tprivate readonly sourceCursors = new Map<string, EventSourceCursor>();\n\t/** Bounded insertion-ordered receipts for exact retries after acknowledgement. */\n\tprivate readonly dispatchedEventIds = new Map<\n\t\tstring,\n\t\tDispatchedEventReceipt\n\t>();\n\tprivate readonly maxDeliveryAttempts: number;\n\tprivate readonly maxRetainedDispatchedEventIds: number;\n\tprivate readonly maxRecords: number | undefined;\n\tprivate readonly maxSources: number | undefined;\n\n\tconstructor(options?: InMemoryOutboxOptions) {\n\t\tconst max = options?.maxDeliveryAttempts ?? 5;\n\t\tassertPositiveInteger(\"InMemoryOutbox\", \"maxDeliveryAttempts\", max);\n\t\tthis.maxDeliveryAttempts = max;\n\t\tconst retained = options?.maxRetainedDispatchedEventIds ?? 10_000;\n\t\tassertPositiveInteger(\n\t\t\t\"InMemoryOutbox\",\n\t\t\t\"maxRetainedDispatchedEventIds\",\n\t\t\tretained,\n\t\t);\n\t\tthis.maxRetainedDispatchedEventIds = retained;\n\t\tif (options?.maxRecords !== undefined) {\n\t\t\tassertPositiveSafeInteger(\n\t\t\t\t\"InMemoryOutbox\",\n\t\t\t\t\"maxRecords\",\n\t\t\t\toptions.maxRecords,\n\t\t\t);\n\t\t}\n\t\tif (options?.maxSources !== undefined) {\n\t\t\tassertPositiveSafeInteger(\n\t\t\t\t\"InMemoryOutbox\",\n\t\t\t\t\"maxSources\",\n\t\t\t\toptions.maxSources,\n\t\t\t);\n\t\t}\n\t\tthis.maxRecords = options?.maxRecords;\n\t\tthis.maxSources = options?.maxSources;\n\t}\n\n\tasync add(events: ReadonlyArray<EventCommitCandidate<Evt>>): Promise<void> {\n\t\t// Prove identity/receipt and source-position consistency for the whole input\n\t\t// before mutating pending records or source heads. Otherwise a conflict later\n\t\t// in one add() call could reject only after its earlier prefix had leaked.\n\t\tthis.assertBatchEventReceiptIntegrity(events);\n\t\tthis.assertBatchPositionIntegrity(events);\n\t\tthis.assertCapacity(events);\n\t\tfor (const message of events) {\n\t\t\tconst { event, source, position } = message;\n\t\t\tconst dispatchedReceipt = this.dispatchedEventIds.get(event.eventId);\n\t\t\tif (dispatchedReceipt !== undefined) {\n\t\t\t\tassertSameEventSource(event, source, dispatchedReceipt.source);\n\t\t\t\tassertSameCandidateReceipt(event, position, dispatchedReceipt.position);\n\t\t\t\t// eventId is the outbox idempotency key. Refresh its LRU position\n\t\t\t\t// without recreating a pending record or touching the source head.\n\t\t\t\tthis.rememberDispatched(\n\t\t\t\t\tevent.eventId,\n\t\t\t\t\tdispatchedReceipt.source,\n\t\t\t\t\tdispatchedReceipt.position,\n\t\t\t\t);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst existing = this.pending.get(event.eventId);\n\t\t\tconst deadLetter = this.dead.get(event.eventId);\n\t\t\tif (existing !== undefined) {\n\t\t\t\tassertSameEventSource(event, source, existing.source);\n\t\t\t\t// A pending record may move to another aggregateVersion only because\n\t\t\t\t// this in-memory adapter cannot observe rollback and the same event is\n\t\t\t\t// re-harvested. Its index and commit cardinality remain immutable.\n\t\t\t\tassertSameCandidateReceiptAllowingVersionRefresh(\n\t\t\t\t\tevent,\n\t\t\t\t\tposition,\n\t\t\t\t\texisting.position,\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (deadLetter) {\n\t\t\t\tassertSameEventSource(event, source, deadLetter.source);\n\t\t\t\tassertSameCandidateReceipt(event, position, deadLetter.position);\n\t\t\t\t// Requeue the durable record exactly as committed. A dead letter is a\n\t\t\t\t// delivery state, not a new aggregate commit to re-finalize.\n\t\t\t\tthis.dead.delete(event.eventId);\n\t\t\t\tthis.pending.set(event.eventId, {\n\t\t\t\t\tdispatchId: deadLetter.dispatchId,\n\t\t\t\t\tevent: deadLetter.event,\n\t\t\t\t\tsource: deadLetter.source,\n\t\t\t\t\tposition: deadLetter.position,\n\t\t\t\t\tattempts: 0,\n\t\t\t\t});\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst ownedSource = Object.freeze({ ...source });\n\t\t\tconst sourceKey = encodeAggregateAddress(source);\n\t\t\tconst sourceCursor = this.sourceCursors.get(sourceKey);\n\t\t\tlet staleHeadVersion: number | undefined;\n\t\t\tif (\n\t\t\t\texisting !== undefined &&\n\t\t\t\tposition.aggregateVersion < existing.position.aggregateVersion\n\t\t\t) {\n\t\t\t\tstaleHeadVersion = existing.position.aggregateVersion;\n\t\t\t} else if (\n\t\t\t\texisting === undefined &&\n\t\t\t\tsourceCursor !== undefined &&\n\t\t\t\tposition.aggregateVersion < sourceCursor.aggregateVersion\n\t\t\t) {\n\t\t\t\tstaleHeadVersion = sourceCursor.aggregateVersion;\n\t\t\t}\n\t\t\tif (staleHeadVersion !== undefined) {\n\t\t\t\tthrow staleHeadError(event, source, position, staleHeadVersion);\n\t\t\t}\n\t\t\tif (sourceCursor?.aggregateVersion === position.aggregateVersion) {\n\t\t\t\tif (sourceCursor.commitSize !== position.commitSize) {\n\t\t\t\t\tthrow new EventHarvestError(\n\t\t\t\t\t\t`InMemoryOutbox rejected event \"${event.eventId}\" for ` +\n\t\t\t\t\t\t\t`${source.aggregateType} ${source.aggregateId}: aggregate version ` +\n\t\t\t\t\t\t\t`${position.aggregateVersion} was already recorded with commitSize ` +\n\t\t\t\t\t\t\t`${sourceCursor.commitSize}, not ${position.commitSize}.`,\n\t\t\t\t\t\tevent.type,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tconst positionOwner = sourceCursor.eventIdsBySequence.get(\n\t\t\t\t\tposition.commitSequence,\n\t\t\t\t);\n\t\t\t\tif (positionOwner !== undefined && positionOwner !== event.eventId) {\n\t\t\t\t\tthrow new EventHarvestError(\n\t\t\t\t\t\t`InMemoryOutbox rejected event \"${event.eventId}\" for ` +\n\t\t\t\t\t\t\t`${source.aggregateType} ${source.aggregateId}: source position ` +\n\t\t\t\t\t\t\t`(${position.aggregateVersion}, ${position.commitSequence}) is ` +\n\t\t\t\t\t\t\t`already owned by event \"${positionOwner}\". One qualified source ` +\n\t\t\t\t\t\t\t\"position must identify exactly one immutable event.\",\n\t\t\t\t\t\tevent.type,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t\tlet previousEventfulAggregateVersion: number | null;\n\t\t\tconst refreshesLeakedCommit =\n\t\t\t\texisting !== undefined &&\n\t\t\t\texisting.position.aggregateVersion !== position.aggregateVersion;\n\t\t\tif (refreshesLeakedCommit) {\n\t\t\t\t// InMemoryOutbox cannot observe transaction rollback. A pending\n\t\t\t\t// record with the same eventId but a new commit version is therefore\n\t\t\t\t// a replacement for the leaked attempt, not its successor. Preserve\n\t\t\t\t// the event-source predecessor and move the in-memory source head.\n\t\t\t\tpreviousEventfulAggregateVersion =\n\t\t\t\t\texisting.position.previousEventfulAggregateVersion;\n\t\t\t\tif (\n\t\t\t\t\tsourceCursor?.aggregateVersion === existing.position.aggregateVersion\n\t\t\t\t) {\n\t\t\t\t\tthis.sourceCursors.set(sourceKey, {\n\t\t\t\t\t\taggregateVersion: position.aggregateVersion,\n\t\t\t\t\t\tpreviousEventfulAggregateVersion,\n\t\t\t\t\t\tcommitSize: position.commitSize,\n\t\t\t\t\t\teventIdsBySequence: new Map([\n\t\t\t\t\t\t\t[position.commitSequence, event.eventId],\n\t\t\t\t\t\t]),\n\t\t\t\t\t});\n\t\t\t\t} else if (\n\t\t\t\t\tsourceCursor?.aggregateVersion === position.aggregateVersion &&\n\t\t\t\t\t!sourceCursor.eventIdsBySequence.has(position.commitSequence)\n\t\t\t\t) {\n\t\t\t\t\tthis.sourceCursors.set(\n\t\t\t\t\t\tsourceKey,\n\t\t\t\t\t\tcursorWithEvent(\n\t\t\t\t\t\t\tsourceCursor,\n\t\t\t\t\t\t\tposition.commitSequence,\n\t\t\t\t\t\t\tevent.eventId,\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t} else if (existing !== undefined) {\n\t\t\t\tpreviousEventfulAggregateVersion =\n\t\t\t\t\texisting.position.previousEventfulAggregateVersion;\n\t\t\t} else if (sourceCursor?.aggregateVersion === position.aggregateVersion) {\n\t\t\t\tpreviousEventfulAggregateVersion =\n\t\t\t\t\tsourceCursor.previousEventfulAggregateVersion;\n\t\t\t\tif (!sourceCursor.eventIdsBySequence.has(position.commitSequence)) {\n\t\t\t\t\tthis.sourceCursors.set(\n\t\t\t\t\t\tsourceKey,\n\t\t\t\t\t\tcursorWithEvent(\n\t\t\t\t\t\t\tsourceCursor,\n\t\t\t\t\t\t\tposition.commitSequence,\n\t\t\t\t\t\t\tevent.eventId,\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tpreviousEventfulAggregateVersion =\n\t\t\t\t\tsourceCursor?.aggregateVersion ?? null;\n\t\t\t\tthis.sourceCursors.set(sourceKey, {\n\t\t\t\t\taggregateVersion: position.aggregateVersion,\n\t\t\t\t\tpreviousEventfulAggregateVersion,\n\t\t\t\t\tcommitSize: position.commitSize,\n\t\t\t\t\teventIdsBySequence: new Map([\n\t\t\t\t\t\t[position.commitSequence, event.eventId],\n\t\t\t\t\t]),\n\t\t\t\t});\n\t\t\t}\n\t\t\tconst ownedPosition = Object.freeze({\n\t\t\t\t...position,\n\t\t\t\tpreviousEventfulAggregateVersion,\n\t\t\t});\n\t\t\tif (existing) {\n\t\t\t\t// Re-add refreshes the stored COPY but keeps the delivery\n\t\t\t\t// bookkeeping: a failed-commit-then-retry re-adds the same\n\t\t\t\t// eventId with a new commit position. Dispatching the stale\n\t\t\t\t// envelope would hand consumers a position from a commit that\n\t\t\t\t// never happened. Attempts belong to delivery, so they survive.\n\t\t\t\texisting.event = event;\n\t\t\t\texisting.source = ownedSource;\n\t\t\t\texisting.position = ownedPosition;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tthis.pending.set(event.eventId, {\n\t\t\t\tdispatchId: event.eventId,\n\t\t\t\tevent,\n\t\t\t\tsource: ownedSource,\n\t\t\t\tposition: ownedPosition,\n\t\t\t\tattempts: 0,\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate assertCapacity(\n\t\tevents: ReadonlyArray<EventCommitCandidate<Evt>>,\n\t): void {\n\t\tconst newRecordIds = new Set<string>();\n\t\tconst newSourceKeys = new Set<string>();\n\t\tfor (const { event, source } of events) {\n\t\t\tif (\n\t\t\t\tthis.pending.has(event.eventId) ||\n\t\t\t\tthis.dead.has(event.eventId) ||\n\t\t\t\tthis.dispatchedEventIds.has(event.eventId)\n\t\t\t) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tnewRecordIds.add(event.eventId);\n\t\t\tconst sourceKey = encodeAggregateAddress(source);\n\t\t\tif (!this.sourceCursors.has(sourceKey)) newSourceKeys.add(sourceKey);\n\t\t}\n\n\t\tconst currentRecords = this.pending.size + this.dead.size;\n\t\tif (\n\t\t\tthis.maxRecords !== undefined &&\n\t\t\tcurrentRecords + newRecordIds.size > this.maxRecords\n\t\t) {\n\t\t\tthrow new InMemoryCapacityExceededError({\n\t\t\t\tstore: \"InMemoryOutbox\",\n\t\t\t\tresource: \"records\",\n\t\t\t\tlimit: this.maxRecords,\n\t\t\t\tcurrent: currentRecords,\n\t\t\t\tattempted: newRecordIds.size,\n\t\t\t});\n\t\t}\n\t\tif (\n\t\t\tthis.maxSources !== undefined &&\n\t\t\tthis.sourceCursors.size + newSourceKeys.size > this.maxSources\n\t\t) {\n\t\t\tthrow new InMemoryCapacityExceededError({\n\t\t\t\tstore: \"InMemoryOutbox\",\n\t\t\t\tresource: \"sources\",\n\t\t\t\tlimit: this.maxSources,\n\t\t\t\tcurrent: this.sourceCursors.size,\n\t\t\t\tattempted: newSourceKeys.size,\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate assertBatchEventReceiptIntegrity(\n\t\tevents: ReadonlyArray<EventCommitCandidate<Evt>>,\n\t): void {\n\t\tconst receiptsInBatch = new Map<\n\t\t\tstring,\n\t\t\t{\n\t\t\t\treadonly source: AggregateAddress;\n\t\t\t\treadonly position: EventCommitCandidatePosition;\n\t\t\t}\n\t\t>();\n\t\tfor (const { event, source, position } of events) {\n\t\t\tconst batchReceipt = receiptsInBatch.get(event.eventId);\n\t\t\tif (batchReceipt !== undefined) {\n\t\t\t\tassertSameEventSource(event, source, batchReceipt.source);\n\t\t\t\tassertSameCandidateReceipt(event, position, batchReceipt.position);\n\t\t\t} else {\n\t\t\t\treceiptsInBatch.set(event.eventId, { source, position });\n\t\t\t}\n\t\t\tconst dispatchedReceipt = this.dispatchedEventIds.get(event.eventId);\n\t\t\tif (dispatchedReceipt !== undefined) {\n\t\t\t\tassertSameEventSource(event, source, dispatchedReceipt.source);\n\t\t\t\tassertSameCandidateReceipt(event, position, dispatchedReceipt.position);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst existing = this.pending.get(event.eventId);\n\t\t\tif (existing !== undefined) {\n\t\t\t\tassertSameEventSource(event, source, existing.source);\n\t\t\t\tassertSameCandidateReceiptAllowingVersionRefresh(\n\t\t\t\t\tevent,\n\t\t\t\t\tposition,\n\t\t\t\t\texisting.position,\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst deadLetter = this.dead.get(event.eventId);\n\t\t\tif (deadLetter !== undefined) {\n\t\t\t\tassertSameEventSource(event, source, deadLetter.source);\n\t\t\t\tassertSameCandidateReceipt(event, position, deadLetter.position);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate assertBatchPositionIntegrity(\n\t\tevents: ReadonlyArray<EventCommitCandidate<Evt>>,\n\t): void {\n\t\tconst simulatedCursors = new Map<string, EventSourceCursor>();\n\t\tfor (const { event, source, position } of events) {\n\t\t\tconst sourceKey = encodeAggregateAddress(source);\n\t\t\tconst cursor =\n\t\t\t\tsimulatedCursors.get(sourceKey) ?? this.sourceCursors.get(sourceKey);\n\t\t\tif (\n\t\t\t\tcursor === undefined ||\n\t\t\t\tposition.aggregateVersion > cursor.aggregateVersion\n\t\t\t) {\n\t\t\t\tsimulatedCursors.set(sourceKey, {\n\t\t\t\t\taggregateVersion: position.aggregateVersion,\n\t\t\t\t\tpreviousEventfulAggregateVersion: cursor?.aggregateVersion ?? null,\n\t\t\t\t\tcommitSize: position.commitSize,\n\t\t\t\t\teventIdsBySequence: new Map([\n\t\t\t\t\t\t[position.commitSequence, event.eventId],\n\t\t\t\t\t]),\n\t\t\t\t});\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (position.aggregateVersion < cursor.aggregateVersion) {\n\t\t\t\t// Mirror of the main loop's stale-head rejection. A silent\n\t\t\t\t// `continue` here would break add()'s all-or-nothing promise:\n\t\t\t\t// the main loop would insert every earlier candidate and only\n\t\t\t\t// then throw for this one, leaving a pending event for a\n\t\t\t\t// commit the caller rolled back. Exact retries still dedupe:\n\t\t\t\t// dispatched receipts, dead letters, and a pending record at\n\t\t\t\t// or below the candidate version pass through.\n\t\t\t\tconst dedupes =\n\t\t\t\t\tthis.dispatchedEventIds.has(event.eventId) ||\n\t\t\t\t\tthis.dead.has(event.eventId);\n\t\t\t\tconst pendingRecord = this.pending.get(event.eventId);\n\t\t\t\tconst staleAgainstPending =\n\t\t\t\t\tpendingRecord !== undefined &&\n\t\t\t\t\tposition.aggregateVersion < pendingRecord.position.aggregateVersion;\n\t\t\t\tconst staleAgainstHead = pendingRecord === undefined && !dedupes;\n\t\t\t\tif (staleAgainstPending || staleAgainstHead) {\n\t\t\t\t\tthrow staleHeadError(\n\t\t\t\t\t\tevent,\n\t\t\t\t\t\tsource,\n\t\t\t\t\t\tposition,\n\t\t\t\t\t\tpendingRecord?.position.aggregateVersion ?? cursor.aggregateVersion,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (cursor.commitSize !== position.commitSize) {\n\t\t\t\tthrow new EventHarvestError(\n\t\t\t\t\t`InMemoryOutbox rejected event \"${event.eventId}\" for ` +\n\t\t\t\t\t\t`${source.aggregateType} ${source.aggregateId}: aggregate version ` +\n\t\t\t\t\t\t`${position.aggregateVersion} was already recorded with commitSize ` +\n\t\t\t\t\t\t`${cursor.commitSize}, not ${position.commitSize}.`,\n\t\t\t\t\tevent.type,\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst positionOwner = cursor.eventIdsBySequence.get(\n\t\t\t\tposition.commitSequence,\n\t\t\t);\n\t\t\tif (positionOwner !== undefined && positionOwner !== event.eventId) {\n\t\t\t\tthrow new EventHarvestError(\n\t\t\t\t\t`InMemoryOutbox rejected event \"${event.eventId}\" for ` +\n\t\t\t\t\t\t`${source.aggregateType} ${source.aggregateId}: source position ` +\n\t\t\t\t\t\t`(${position.aggregateVersion}, ${position.commitSequence}) is ` +\n\t\t\t\t\t\t`already owned by event \"${positionOwner}\". One qualified source ` +\n\t\t\t\t\t\t\"position must identify exactly one immutable event.\",\n\t\t\t\t\tevent.type,\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (positionOwner === undefined) {\n\t\t\t\tsimulatedCursors.set(\n\t\t\t\t\tsourceKey,\n\t\t\t\t\tcursorWithEvent(cursor, position.commitSequence, event.eventId),\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\tasync getPending(limit?: number): Promise<ReadonlyArray<OutboxRecord<Evt>>> {\n\t\t// Copies, not the tracked internals: a caller mutating a returned\n\t\t// record must not corrupt the attempt bookkeeping. Map iteration\n\t\t// preserves insertion order, satisfying the port's ordering\n\t\t// contract. Stop at the limit instead of materializing the whole\n\t\t// backlog: a dispatcher polling a large backlog with a small batch\n\t\t// pays O(limit), not O(total pending). The clamp keeps a negative\n\t\t// limit (batchSize - inFlight going negative) at \"nothing\", not\n\t\t// \"everything but the last records\".\n\t\t// NaN (e.g. batchSize - inFlight with an undefined operand) clamps\n\t\t// to zero like the old slice(0, NaN) did, never to \"everything\".\n\t\tconst max =\n\t\t\ttypeof limit === \"number\"\n\t\t\t\t? Math.max(0, Number.isNaN(limit) ? 0 : limit)\n\t\t\t\t: Number.POSITIVE_INFINITY;\n\t\tconst batch: Array<OutboxRecord<Evt>> = [];\n\t\tfor (const record of this.pending.values()) {\n\t\t\tif (batch.length >= max) break;\n\t\t\tbatch.push({\n\t\t\t\tdispatchId: record.dispatchId,\n\t\t\t\tevent: record.event,\n\t\t\t\tsource: record.source,\n\t\t\t\tposition: record.position,\n\t\t\t\tattempts: record.attempts,\n\t\t\t});\n\t\t}\n\t\treturn batch;\n\t}\n\n\tasync markDispatched(dispatchIds: ReadonlyArray<string>): Promise<void> {\n\t\tfor (const id of dispatchIds) {\n\t\t\tconst record = this.pending.get(id) ?? this.dead.get(id);\n\t\t\tif (record !== undefined) {\n\t\t\t\tthis.rememberDispatched(id, record.source, record.position);\n\t\t\t}\n\t\t\tthis.pending.delete(id);\n\t\t\t// Manual redelivery then ack: dispatching a dead-lettered record\n\t\t\t// clears it too.\n\t\t\tthis.dead.delete(id);\n\t\t}\n\t}\n\n\tprivate rememberDispatched(\n\t\teventId: string,\n\t\tsource: AggregateAddress,\n\t\tposition: EventCommitCandidatePosition,\n\t): void {\n\t\tthis.dispatchedEventIds.delete(eventId);\n\t\tthis.dispatchedEventIds.set(eventId, {\n\t\t\tsource: Object.freeze({ ...source }),\n\t\t\tposition: Object.freeze({\n\t\t\t\taggregateVersion: position.aggregateVersion,\n\t\t\t\tcommitSequence: position.commitSequence,\n\t\t\t\tcommitSize: position.commitSize,\n\t\t\t}),\n\t\t});\n\t\twhile (this.dispatchedEventIds.size > this.maxRetainedDispatchedEventIds) {\n\t\t\tconst oldest = this.dispatchedEventIds.keys().next();\n\t\t\tif (oldest.done) break;\n\t\t\tthis.dispatchedEventIds.delete(oldest.value);\n\t\t}\n\t}\n\n\tasync markFailed(\n\t\tdispatchId: string,\n\t\terror?: unknown,\n\t): Promise<DeadLetterRecord<Evt> | undefined> {\n\t\tconst record = this.pending.get(dispatchId);\n\t\t// Unknown or already-dispatched (or already dead-lettered) id: a\n\t\t// late failure report must not resurrect anything.\n\t\tif (!record) return undefined;\n\t\trecord.attempts += 1;\n\t\trecord.lastError =\n\t\t\terror instanceof Error ? error.message : String(error ?? \"unknown\");\n\t\tif (record.attempts >= this.maxDeliveryAttempts) {\n\t\t\tthis.pending.delete(dispatchId);\n\t\t\tconst deadLetter: DeadLetterRecord<Evt> = {\n\t\t\t\tdispatchId: record.dispatchId,\n\t\t\t\tevent: record.event,\n\t\t\t\tsource: record.source,\n\t\t\t\tposition: record.position,\n\t\t\t\tattempts: record.attempts,\n\t\t\t\tlastError: record.lastError,\n\t\t\t};\n\t\t\tthis.dead.set(dispatchId, deadLetter);\n\t\t\treturn { ...deadLetter };\n\t\t}\n\t\treturn undefined;\n\t}\n\n\tasync deadLetters(): Promise<ReadonlyArray<DeadLetterRecord<Evt>>> {\n\t\treturn [...this.dead.values()].map((record) => ({ ...record }));\n\t}\n}\n\nfunction cursorWithEvent(\n\tcursor: EventSourceCursor,\n\tcommitSequence: number,\n\teventId: string,\n): EventSourceCursor {\n\treturn {\n\t\t...cursor,\n\t\teventIdsBySequence: new Map(cursor.eventIdsBySequence).set(\n\t\t\tcommitSequence,\n\t\t\teventId,\n\t\t),\n\t};\n}\n\nfunction assertSameCandidateReceipt(\n\tevent: AnyDomainEvent,\n\treceived: EventCommitCandidatePosition,\n\trecorded: EventCommitCandidatePosition,\n): void {\n\tassertReceiptShape(event, received, recorded, false);\n}\n\n/**\n * The lenient variant for PENDING records only: this in-memory adapter\n * cannot observe rollback, so a re-harvested event may legitimately arrive\n * at a new aggregateVersion. Index and commit cardinality stay immutable.\n */\nfunction assertSameCandidateReceiptAllowingVersionRefresh(\n\tevent: AnyDomainEvent,\n\treceived: EventCommitCandidatePosition,\n\trecorded: EventCommitCandidatePosition,\n): void {\n\tassertReceiptShape(event, received, recorded, true);\n}\n\nfunction assertReceiptShape(\n\tevent: AnyDomainEvent,\n\treceived: EventCommitCandidatePosition,\n\trecorded: EventCommitCandidatePosition,\n\tallowAggregateVersionRefresh: boolean,\n): void {\n\tconst sameVersion =\n\t\tallowAggregateVersionRefresh ||\n\t\treceived.aggregateVersion === recorded.aggregateVersion;\n\tif (\n\t\tsameVersion &&\n\t\treceived.commitSequence === recorded.commitSequence &&\n\t\treceived.commitSize === recorded.commitSize\n\t) {\n\t\treturn;\n\t}\n\tthrow new EventHarvestError(\n\t\t`InMemoryOutbox rejected event \"${event.eventId}\": its commit candidate ` +\n\t\t\t`changed from (${recorded.aggregateVersion}, ${recorded.commitSequence}; ` +\n\t\t\t`commitSize=${recorded.commitSize}) to (${received.aggregateVersion}, ` +\n\t\t\t`${received.commitSequence}; commitSize=${received.commitSize}). ` +\n\t\t\t\"An exact redelivery must keep its source position immutable.\",\n\t\tevent.type,\n\t);\n}\n\nfunction staleHeadError(\n\tevent: { readonly eventId: string; readonly type: string },\n\tsource: AggregateAddress,\n\tposition: EventCommitCandidatePosition,\n\tstaleHeadVersion: number,\n): EventHarvestError {\n\treturn new EventHarvestError(\n\t\t`InMemoryOutbox rejected stale event \"${event.eventId}\" for ` +\n\t\t\t`${source.aggregateType} ${source.aggregateId} at aggregate version ` +\n\t\t\t`${position.aggregateVersion}: the event-source head is already ` +\n\t\t\t`${staleHeadVersion}. The dispatched-id receipt may have ` +\n\t\t\t\"expired; use a durable outbox with a transactional eventId unique key \" +\n\t\t\t\"for unbounded idempotency.\",\n\t\tevent.type,\n\t);\n}\n\nfunction assertSameEventSource(\n\tevent: AnyDomainEvent,\n\treceived: AggregateAddress,\n\trecorded: AggregateAddress,\n): void {\n\tif (\n\t\treceived.aggregateType === recorded.aggregateType &&\n\t\treceived.aggregateId === recorded.aggregateId\n\t) {\n\t\treturn;\n\t}\n\tthrow new EventHarvestError(\n\t\t`InMemoryOutbox rejected eventId collision for \"${event.eventId}\": ` +\n\t\t\t`it already belongs to ${recorded.aggregateType} ${recorded.aggregateId}, ` +\n\t\t\t`but was received for ${received.aggregateType} ${received.aggregateId}. ` +\n\t\t\t\"An eventId must identify one immutable event across all aggregate sources.\",\n\t\tevent.type,\n\t);\n}\n","import type { AnyDomainEvent } from \"../../domain/event/domain-event\";\nimport {\n\tDEFAULT_EXECUTION_TIMEOUT_MS,\n\ttype ExecutionContext,\n\trunBoundedExecution,\n} from \"../../internal/async/execution\";\nimport { PollLoop } from \"../../internal/async/poll-loop\";\nimport {\n\tassessDeliveryFailure,\n\ttype DeliveryFailureAssessment,\n\ttype DeliveryFailureClassifier,\n} from \"../../internal/delivery-failure\";\nimport {\n\tcaptureObserverFunctions,\n\treportToObserver,\n} from \"../../internal/observer\";\nimport { assertNonNegativeFinite } from \"../../internal/validate\";\nimport type { EventBus } from \"../event-bus/ports\";\nimport {\n\ttype DeadLetterRecord,\n\ttype DispatchTrackingOutbox,\n\tisDispatchTrackingOutbox,\n\ttype Outbox,\n\ttype OutboxRecord,\n} from \"./ports\";\n\n/**\n * Required operational observers for {@link OutboxDispatcher}. All hooks are\n * best-effort notifications: synchronous throws and rejected promises are\n * neutralized so observability cannot change delivery state. The dispatcher\n * captures and freezes these function references at construction, so later\n * mutation of the supplied object cannot disable an operational channel.\n *\n * `onDeadLetter` fires immediately after `markFailed` reports the exact\n * transition. It is not a durable notification boundary: a process can stop\n * after the store commits the transition and before the callback runs. Keep\n * polling {@link DispatchTrackingOutbox.deadLetters} for durable alerting and\n * reconciliation; the hook provides low-latency diagnostics.\n */\nexport interface OutboxDispatcherObservers<Evt extends AnyDomainEvent> {\n\t/**\n\t * A publish, acknowledgement, or failure-tracking operation failed.\n\t * Delivery failures include their accounting assessment. Store failures do\n\t * not; they are operationally distinct from poison-message attempts.\n\t */\n\treadonly onDispatchError: (\n\t\terror: unknown,\n\t\trecord: OutboxRecord<Evt>,\n\t\tassessment?: DeliveryFailureAssessment,\n\t) => void;\n\t/** Reading the pending page failed. */\n\treadonly onPollError: (error: unknown) => void;\n\t/** A tracked record crossed the store's dead-letter threshold. */\n\treadonly onDeadLetter: (record: DeadLetterRecord<Evt>) => void;\n}\n\n/**\n * Delivery target of the {@link OutboxDispatcher}: one driven port with a\n * single question, \"deliver this record's event\". The consumer implements\n * it against the real transport (message broker, webhook, queue\n * producer); {@link eventBusSink} adapts the in-process `EventBus` for\n * setups without a broker.\n *\n * The sink is called once per record, sequentially, in commit order. A\n * throw signals delivery failure; the dispatcher stops the batch,\n * reports the failure, and retries later (see the dispatcher contract).\n * Sinks must tolerate duplicate delivery: the dispatcher is\n * at-least-once by construction (a crash or ack failure between\n * `publish` and `markDispatched` redelivers). Dedupe on\n * `record.event.eventId`; projection sinks use the event's full gap-proof\n * commit cursor.\n *\n * **Resolve only after the transport acknowledged.** The dispatcher\n * calls `markDispatched` as soon as `publish` resolves, so the\n * resolution IS the delivery confirmation: await the broker's ack\n * (Kafka producer confirm, SQS SendMessage response, JetStream publish\n * ack, HTTP 2xx) before returning. A fire-and-forget publish that\n * resolves early marks records dispatched that the broker may never\n * have stored, which silently voids the at-least-once guarantee the\n * outbox exists to provide.\n *\n * Pass `context.signal` into the transport or enforce a native timeout no\n * later than `context.deadlineAt`. The dispatcher bounds its own wait, but it\n * cannot terminate a foreign promise that ignores cancellation; such an\n * adapter can leave zombie I/O overlapping the retry and is not production\n * conforming. The record remains pending unless `publish` had already resolved\n * and its dispatch acknowledgement was persisted.\n */\nexport interface OutboxSink<Evt extends AnyDomainEvent> {\n\tpublish: (\n\t\trecord: OutboxRecord<Evt>,\n\t\tcontext: ExecutionContext,\n\t) => Promise<void>;\n}\n\n/**\n * Adapts the in-process {@link EventBus} as an {@link OutboxSink}: the\n * zero-broker setup where the outbox still provides durability and\n * replay, and subscribers run in-process. Handler errors propagate as\n * delivery failures, so failed events retry through the normal\n * dispatcher loop instead of being lost.\n *\n * **Do not combine with `withCommit`'s `bus` fast path on the same\n * bus.** `withCommit({ scope, outbox, bus })` already publishes every\n * committed event to that bus post-commit, and the outbox record stays\n * pending regardless; a dispatcher with `eventBusSink(bus)` then\n * publishes the same event to the same subscribers a second time, on\n * EVERY commit, by construction. Pick one: omit `bus` from `withCommit`\n * and let the dispatcher deliver (durable, replayable), or keep the\n * fast path and point the dispatcher's sink at a different transport.\n *\n * **Retries are per event, not per handler.** One `publish` fans out to\n * ALL subscribers of the event's type, and the bus reports errors only\n * after every handler ran; the outbox tracks the EVENT, not individual\n * handlers. When one subscriber keeps failing, each retry re-executes\n * its co-subscribers too, up to the attempt ceiling. In-process\n * handlers are therefore consumers in the checklist sense: they must\n * be idempotent (dedupe on `eventId`), or non-idempotent reactions\n * (send mail, charge a card) must not share an event subscription with\n * failure-prone handlers. Per-handler delivery tracking is what broker\n * consumer groups (or per-subscriber checkpoints, see the read-model\n * guide) provide; this sink deliberately does not reimplement it.\n *\n * **Subscribe first, then start the dispatcher.** Publishing to a bus\n * with ZERO subscribers for the event's type resolves as delivered\n * (pub/sub semantics: delivery to all current subscribers, even none),\n * so the dispatcher acks the record and it never comes back. Records\n * polled in a startup window before module wiring registered its\n * subscriptions are therefore consumed without any handler seeing\n * them; register every subscription before `run()`/`drainOnce()`. A\n * `subscribeAll` consumer counts as a subscriber for every type. The\n * same holds for reactions added later: a new subscriber does not see\n * already-dispatched history; replay is a read-model concern, not a\n * bus feature.\n */\nexport function eventBusSink<Evt extends AnyDomainEvent>(\n\tbus: EventBus<Evt>,\n): OutboxSink<Evt> {\n\treturn {\n\t\tpublish: (record, context) =>\n\t\t\tbus.publish([record.event], {\n\t\t\t\tsignal: context.signal,\n\t\t\t\ttimeoutMs: Math.max(0, context.deadlineAt - Date.now()),\n\t\t\t}),\n\t};\n}\n\n/** Construction options for {@link OutboxDispatcher}. */\nexport interface OutboxDispatcherOptions<Evt extends AnyDomainEvent> {\n\t/**\n\t * The poll surface. Pass a {@link DispatchTrackingOutbox} to get\n\t * bounded retries: the dispatcher reports each delivery failure via\n\t * `markFailed`, and the store dead-letters records past its attempt\n\t * ceiling so a poison message stops blocking the queue. With a plain\n\t * {@link Outbox}, a poison message retries forever, rate-limited by\n\t * the backoff ceiling (documented trade-off; prefer the tracking\n\t * port in production).\n\t *\n\t * The tracking capability is detected STRUCTURALLY at runtime\n\t * (`markFailed` and `deadLetters` both present). A wrapper or\n\t * decorator around a tracking outbox must forward both methods;\n\t * one that exposes only the plain `Outbox` surface silently turns\n\t * bounded retries off.\n\t */\n\toutbox: Outbox<Evt> | DispatchTrackingOutbox<Evt>;\n\n\t/** Where events go; see {@link OutboxSink}. */\n\tsink: OutboxSink<Evt>;\n\n\t/**\n\t * Complete, required operational observer bundle. A plain `Outbox` never\n\t * calls `onDeadLetter`, but the complete bundle remains required so changing\n\t * the adapter to a tracking outbox cannot silently omit the alarm path.\n\t */\n\tobservers: OutboxDispatcherObservers<Evt>;\n\n\t/** Records fetched per poll. Default `32`. */\n\tbatchSize?: number;\n\n\t/** Idle sleep between polls when the outbox is empty. Default `250`ms. */\n\tpollIntervalMs?: number;\n\n\t/**\n\t * First backoff delay after a failure; grows exponentially with the\n\t * failing record's attempt count or the dispatcher's own\n\t * consecutive-failure streak (whichever is larger, so the delay grows\n\t * even when the store does not track attempts) and is jittered.\n\t * Default `50`ms.\n\t */\n\tbaseDelayMs?: number;\n\n\t/** Ceiling for the failure backoff. Default `5000`ms. */\n\tmaxDelayMs?: number;\n\n\t/**\n\t * Maximum time to await one sink publication. The sink receives the same\n\t * deadline as an AbortSignal and an absolute `deadlineAt`. Default `30000`ms.\n\t */\n\tdeliveryTimeoutMs?: number;\n\n\t/**\n\t * Maximum time to await one poll-store read, acknowledgement, or failure\n\t * update. The store receives the same cooperative context. This bounds the\n\t * worker's wait; production adapters must also cancel or natively bound the\n\t * underlying I/O. Default `30000`ms.\n\t */\n\tstorageTimeoutMs?: number;\n\n\t/**\n\t * Jitter source for the failure backoff, injectable for deterministic\n\t * tests. Default `Math.random`.\n\t */\n\trandom?: () => number;\n\n\t/**\n\t * Classifies delivery errors as transient, permanent, or unknown. Transient\n\t * failures back off without consuming the poison ceiling; permanent and\n\t * unknown failures count. The default walks the cause chain: native\n\t * `TimeoutError` and `retryable: true` are transient, `retryable: false` is\n\t * permanent, and unmapped errors are unknown. A throwing or invalid custom\n\t * classifier becomes unknown and is exposed through the observer assessment\n\t * without replacing the original delivery error.\n\t */\n\tclassifyFailure?: DeliveryFailureClassifier;\n}\n\n/**\n * Minimal polling dispatcher over the {@link Outbox} poll surface: the\n * delivery half of the transactional outbox for setups that do not plug\n * in an external delivery solution (see the outbox guide, \"External\n * dispatchers\", for that path). Intended for tests, moduliths without a\n * broker, and single-process deployments; it is deliberately a loop\n * over the kit's own port, not a messaging framework.\n *\n * Contract:\n *\n * - **At-least-once.** `markDispatched` runs only AFTER successful\n * `sink.publish` calls (the delivered prefix of a batch is acked in\n * one call); a crash or a failed ack between publish and ack\n * redelivers. Sinks and subscribers dedupe on `eventId` or the\n * full gap-proof commit cursor\n * (`domain-event-design.md`).\n * - **Sequential, stop-on-failure.** Records dispatch one at a time in\n * commit order, and the first failure stops the batch: continuing\n * past a failed event would break the per-aggregate causal order\n * `withCommit` promises subscribers. The price is head-of-line\n * blocking; the escape is the tracking outbox's attempt ceiling,\n * which dead-letters a poison record so the queue flows again.\n * - **Never rejects, always backs off.** Storage errors from\n * `getPending` and `markDispatched` are reported to the observers and\n * absorbed; every failed cycle grows the backoff (per the failing\n * record's attempts or the dispatcher's consecutive-failure streak)\n * toward `maxDelayMs`, so a persistent fault degrades to a slow,\n * observable retry cadence instead of a hot loop or a dead loop.\n * - **Bounded retries only with tracking.** With a\n * {@link DispatchTrackingOutbox}, permanent and unknown delivery failures\n * are reported via `markFailed`; transient failures back off without\n * consuming the poison ceiling. The shared default recognizes native\n * timeouts and `retryable` markers, and consumers can override it through\n * {@link OutboxDispatcherOptions.classifyFailure};\n * the store owns the ceiling and the dead-letter set (wire\n * `deadLetters()` to alerting). An ack failure\n * (`markDispatched` throwing) is NOT reported as a delivery failure:\n * the events were delivered, and counting them toward the poison\n * ceiling would dead-letter healthy records; they surface via\n * `onDispatchError`, once per record of the delivered prefix (every\n * one of them will redeliver), and a persistent ack fault is an\n * operational incident the observer makes visible on every cycle.\n * - **One logical instance per outbox** unless the adapter's\n * `getPending` claims records (see the port contract). The dispatcher\n * itself adds no cross-instance coordination.\n * - **Graceful stop.** `run(signal)` resolves (never rejects) when the\n * signal fires: mid-sleep immediately, mid-batch after the in-flight\n * record settles.\n *\n * For cron triggers and serverless runtimes, use {@link drainOnce} per\n * tick instead of the long-running `run`.\n *\n * @example\n * ```ts\n * const dispatcher = new OutboxDispatcher({\n * outbox,\n * sink,\n * observers: {\n * onDispatchError: (error, record) =>\n * log.warn({ error, eventId: record.event.eventId }, \"dispatch failed\"),\n * onPollError: (error) => log.warn({ error }, \"outbox poll failed\"),\n * onDeadLetter: (record) =>\n * alerts.page({ eventId: record.event.eventId }, \"outbox dead letter\"),\n * },\n * });\n * const stop = new AbortController();\n * void dispatcher.run(stop.signal);\n * // on shutdown:\n * stop.abort();\n * ```\n */\nexport class OutboxDispatcher<Evt extends AnyDomainEvent> extends PollLoop {\n\tprivate readonly outbox: Outbox<Evt> | DispatchTrackingOutbox<Evt>;\n\tprivate readonly sink: OutboxSink<Evt>;\n\tprivate readonly classifyFailure?: DeliveryFailureClassifier;\n\tprivate readonly observers: OutboxDispatcherObservers<Evt>;\n\tprivate readonly deliveryTimeoutMs: number;\n\tprivate readonly storageTimeoutMs: number;\n\n\t/**\n\t * Whether the outbox passed at construction implements the\n\t * dispatch-tracking protocol (`markFailed` AND `deadLetters`), i.e.\n\t * whether bounded retries and dead-lettering are active. Detection\n\t * is structural and happens ONCE, here. Assert this in your wiring\n\t * tests: a decorator that forwards only the plain `Outbox` methods\n\t * silently turns tracking off, and this flag is where that loss\n\t * becomes visible instead of surfacing as an endless poison retry.\n\t */\n\treadonly usesDispatchTracking: boolean;\n\n\t/** The tracking view of the outbox, when it qualifies (see above). */\n\tprivate readonly trackingOutbox?: DispatchTrackingOutbox<Evt>;\n\n\tconstructor(options: OutboxDispatcherOptions<Evt>) {\n\t\tsuper(\"OutboxDispatcher\", options);\n\t\tthis.observers = captureObserverFunctions(\n\t\t\t\"OutboxDispatcher\",\n\t\t\toptions.observers,\n\t\t\t[\"onDispatchError\", \"onPollError\", \"onDeadLetter\"],\n\t\t);\n\t\tthis.outbox = options.outbox;\n\t\tthis.trackingOutbox = isDispatchTrackingOutbox(options.outbox)\n\t\t\t? options.outbox\n\t\t\t: undefined;\n\t\tthis.usesDispatchTracking = this.trackingOutbox !== undefined;\n\t\tthis.sink = options.sink;\n\t\tthis.classifyFailure = options.classifyFailure;\n\t\tthis.deliveryTimeoutMs =\n\t\t\toptions.deliveryTimeoutMs ?? DEFAULT_EXECUTION_TIMEOUT_MS;\n\t\tthis.storageTimeoutMs =\n\t\t\toptions.storageTimeoutMs ?? DEFAULT_EXECUTION_TIMEOUT_MS;\n\t\tassertNonNegativeFinite(\n\t\t\t\"OutboxDispatcher\",\n\t\t\t\"deliveryTimeoutMs\",\n\t\t\tthis.deliveryTimeoutMs,\n\t\t);\n\t\tassertNonNegativeFinite(\n\t\t\t\"OutboxDispatcher\",\n\t\t\t\"storageTimeoutMs\",\n\t\t\tthis.storageTimeoutMs,\n\t\t);\n\t}\n\n\t/**\n\t * One full dispatch pass (the `run`/`drainOnce` shell lives on\n\t * {@link PollLoop}): dispatches pending records batch by batch until\n\t * the backlog is empty or a failure stops progress. A `\"stopped\"`\n\t * pass leaves the failed record pending (or dead-lettered by a\n\t * tracking outbox); the next cycle retries it.\n\t */\n\tprotected async pass(signal?: AbortSignal): Promise<\"drained\" | \"stopped\"> {\n\t\twhile (!signal?.aborted) {\n\t\t\tlet batch: ReadonlyArray<OutboxRecord<Evt>>;\n\t\t\ttry {\n\t\t\t\tbatch = await runBoundedExecution(\n\t\t\t\t\t\"OutboxDispatcher.getPending\",\n\t\t\t\t\t{ signal, timeoutMs: this.storageTimeoutMs },\n\t\t\t\t\t(context) => this.outbox.getPending(this.batchSize, context),\n\t\t\t\t);\n\t\t\t} catch (error) {\n\t\t\t\tif (signal?.aborted) return \"stopped\";\n\t\t\t\tthis.consecutiveFailures += 1;\n\t\t\t\treportToObserver(() => this.observers.onPollError(error));\n\t\t\t\treturn \"stopped\";\n\t\t\t}\n\t\t\tif (batch.length === 0) {\n\t\t\t\t// An empty backlog is proof of a healthy state: reset the\n\t\t\t\t// failure streak so the next, unrelated failure starts its\n\t\t\t\t// backoff at attempt 1 instead of inheriting an old streak\n\t\t\t\t// (e.g. after the store dead-lettered a poison record).\n\t\t\t\tthis.consecutiveFailures = 0;\n\t\t\t\treturn \"drained\";\n\t\t\t}\n\t\t\tconst completed = await this.dispatchBatch(batch, signal);\n\t\t\tif (!completed) return \"stopped\";\n\t\t}\n\t\treturn \"stopped\";\n\t}\n\n\t/**\n\t * Dispatches one batch sequentially and acks the delivered prefix in\n\t * a single `markDispatched` call. Returns `true` when every record\n\t * was delivered and acked, `false` when the pass stopped early\n\t * (publish failure, ack failure, or abort).\n\t */\n\tprivate async dispatchBatch(\n\t\tbatch: ReadonlyArray<OutboxRecord<Evt>>,\n\t\tsignal?: AbortSignal,\n\t): Promise<boolean> {\n\t\tconst delivered: string[] = [];\n\t\tlet failedRecord: OutboxRecord<Evt> | undefined;\n\t\tlet failure: unknown;\n\t\tfor (const record of batch) {\n\t\t\tif (signal?.aborted) break;\n\t\t\ttry {\n\t\t\t\tawait runBoundedExecution(\n\t\t\t\t\t\"OutboxDispatcher.publish\",\n\t\t\t\t\t{ signal, timeoutMs: this.deliveryTimeoutMs },\n\t\t\t\t\t(context) => this.sink.publish(record, context),\n\t\t\t\t);\n\t\t\t\tdelivered.push(record.dispatchId);\n\t\t\t} catch (error) {\n\t\t\t\tif (signal?.aborted) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tfailedRecord = record;\n\t\t\t\tfailure = error;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\t// Ack the delivered prefix in one round-trip, before handling the\n\t\t// failure, so delivered records do not redeliver.\n\t\tlet acked = true;\n\t\tif (delivered.length > 0) {\n\t\t\ttry {\n\t\t\t\t// A broker acknowledgement that won the publish/abort race must still\n\t\t\t\t// get one bounded persistence attempt. If shutdown had already fired\n\t\t\t\t// before this ack starts, the storage timeout owns that short grace\n\t\t\t\t// period; an ack already in flight remains owner-cancellable.\n\t\t\t\tconst acknowledgementSignal = signal?.aborted ? undefined : signal;\n\t\t\t\tawait runBoundedExecution(\n\t\t\t\t\t\"OutboxDispatcher.markDispatched\",\n\t\t\t\t\t{\n\t\t\t\t\t\tsignal: acknowledgementSignal,\n\t\t\t\t\t\ttimeoutMs: this.storageTimeoutMs,\n\t\t\t\t\t},\n\t\t\t\t\t(context) => this.outbox.markDispatched(delivered, context),\n\t\t\t\t);\n\t\t\t\tthis.consecutiveFailures = 0;\n\t\t\t} catch (error) {\n\t\t\t\t// The events WERE delivered; a failed ack means they will\n\t\t\t\t// redeliver (the documented at-least-once duplicates), so it\n\t\t\t\t// must not count toward the poison ceiling. The growing\n\t\t\t\t// consecutive-failure backoff rate-limits the duplicates.\n\t\t\t\t// Every record in the delivered prefix is affected; report\n\t\t\t\t// each one, so the operator can match the coming duplicates\n\t\t\t\t// to this ack failure instead of chasing them individually.\n\t\t\t\tacked = false;\n\t\t\t\tif (!signal?.aborted) {\n\t\t\t\t\tfor (const context of batch.slice(0, delivered.length)) {\n\t\t\t\t\t\treportToObserver(() =>\n\t\t\t\t\t\t\tthis.observers.onDispatchError(error, context),\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (failedRecord !== undefined) {\n\t\t\tconst record = failedRecord;\n\t\t\tconst error = failure;\n\t\t\tconst assessment = assessDeliveryFailure(error, this.classifyFailure);\n\t\t\treportToObserver(() =>\n\t\t\t\tthis.observers.onDispatchError(error, record, assessment),\n\t\t\t);\n\t\t\tconst tracking = this.trackingOutbox;\n\t\t\tif (tracking !== undefined && assessment.kind !== \"transient\") {\n\t\t\t\ttry {\n\t\t\t\t\tconst deadLetter = await runBoundedExecution(\n\t\t\t\t\t\t\"OutboxDispatcher.markFailed\",\n\t\t\t\t\t\t{ signal, timeoutMs: this.storageTimeoutMs },\n\t\t\t\t\t\t(context) => tracking.markFailed(record.dispatchId, error, context),\n\t\t\t\t\t);\n\t\t\t\t\tif (deadLetter !== undefined) {\n\t\t\t\t\t\treportToObserver(() => this.observers.onDeadLetter(deadLetter));\n\t\t\t\t\t}\n\t\t\t\t} catch (markError) {\n\t\t\t\t\tif (!signal?.aborted) {\n\t\t\t\t\t\treportToObserver(() =>\n\t\t\t\t\t\t\tthis.observers.onDispatchError(markError, record),\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// One streak bump per failed cycle, whatever combination of ack and\n\t\t// publish failures occurred, so the backoff grows exactly one\n\t\t// exponential step per cycle as documented.\n\t\tif (failedRecord !== undefined || !acked) {\n\t\t\tthis.consecutiveFailures = Math.max(\n\t\t\t\tthis.consecutiveFailures + 1,\n\t\t\t\t(failedRecord?.attempts ?? 0) + 1,\n\t\t\t);\n\t\t}\n\t\tif (failedRecord !== undefined) return false;\n\t\tif (!acked) return false;\n\t\t// An abort mid-batch left records unpublished; not a failure, but\n\t\t// not a completed batch either.\n\t\tif (signal?.aborted && delivered.length < batch.length) return false;\n\t\treturn true;\n\t}\n}\n","import {\n\ttype AggregateAddress,\n\tencodeAggregateAddress,\n} from \"../../../domain/aggregate/aggregate-address\";\nimport type { AnyDomainEvent } from \"../../../domain/event/domain-event\";\nimport {\n\tConcurrencyConflictError,\n\tInMemoryCapacityExceededError,\n} from \"../../../errors/kit-errors\";\nimport { assertPositiveSafeInteger } from \"../../../internal/validate\";\nimport type {\n\tEventStore,\n\tEventStoreAppendOptions,\n\tReadStreamOptions,\n\tStreamReadResult,\n} from \"../event-store\";\n\n/** Optional fail-loud capacities for the finite-lifetime reference store. */\nexport interface InMemoryEventStoreOptions {\n\t/** Maximum aggregate streams retained by this instance. */\n\treadonly maxStreams?: number;\n\t/** Maximum events retained across every stream in this instance. */\n\treadonly maxEvents?: number;\n}\n\nfunction assertStreamPosition(\n\tname: \"fromVersion\" | \"toVersion\",\n\tvalue: number | undefined,\n): void {\n\tif (value !== undefined && (!Number.isSafeInteger(value) || value < 0)) {\n\t\tthrow new RangeError(\n\t\t\t`InMemoryEventStore: ${name} must be a non-negative safe integer, got ${String(value)}`,\n\t\t);\n\t}\n}\n\n/**\n * In-memory reference implementation of `EventStore<Evt>`.\n *\n * Intended for finite-lifetime tests and quick-start demos. With no capacity\n * options, streams and events are unbounded for the lifetime of the instance.\n * Long-lived processes must configure `maxStreams` and `maxEvents` or use a\n * durable adapter. Capacity exhaustion rejects before mutation with\n * `InMemoryCapacityExceededError`; histories are never silently evicted.\n * Implements the full port contract: expectedVersion-guarded appends\n * (throwing `ConcurrencyConflictError` on mismatch), atomic rejected\n * appends, explicit missing/existing stream state with the actual head,\n * append-order reads, mandatory page bounds, and `(fromVersion, toVersion]`\n * slicing. Invalid limits or positions reject with `RangeError`.\n *\n * For production, back the port with a durable store whose append and\n * the aggregate transaction share atomicity (a table with a\n * `(aggregate_type, aggregate_id, position)` unique key inside the same\n * transaction, or a dedicated event store). Same caveat as\n * `InMemoryOutbox`: this class\n * lives in memory only and knows nothing about your `TransactionScope`\n * rollbacks; events appended inside a transaction that later rolls back\n * are NOT removed. The event-sourced repository contract suite's\n * reference environment shows the snapshot/restore pattern for\n * rollback-pure in-memory testing.\n */\nexport class InMemoryEventStore<Evt extends AnyDomainEvent>\n\timplements EventStore<Evt>\n{\n\tprivate readonly streams = new Map<string, Evt[]>();\n\tprivate readonly maxStreams: number | undefined;\n\tprivate readonly maxEvents: number | undefined;\n\tprivate totalEvents = 0;\n\n\tconstructor(options: InMemoryEventStoreOptions = {}) {\n\t\tif (options.maxStreams !== undefined) {\n\t\t\tassertPositiveSafeInteger(\n\t\t\t\t\"InMemoryEventStore\",\n\t\t\t\t\"maxStreams\",\n\t\t\t\toptions.maxStreams,\n\t\t\t);\n\t\t}\n\t\tif (options.maxEvents !== undefined) {\n\t\t\tassertPositiveSafeInteger(\n\t\t\t\t\"InMemoryEventStore\",\n\t\t\t\t\"maxEvents\",\n\t\t\t\toptions.maxEvents,\n\t\t\t);\n\t\t}\n\t\tthis.maxStreams = options.maxStreams;\n\t\tthis.maxEvents = options.maxEvents;\n\t}\n\n\tasync append(\n\t\tstream: AggregateAddress,\n\t\tevents: ReadonlyArray<Evt>,\n\t\toptions: EventStoreAppendOptions,\n\t): Promise<void> {\n\t\tif (events.length === 0) return;\n\t\tconst key = encodeAggregateAddress(stream);\n\t\tconst existing = this.streams.get(key);\n\t\tif ((existing?.length ?? 0) !== options.expectedVersion) {\n\t\t\tthrow new ConcurrencyConflictError({\n\t\t\t\taggregateType: stream.aggregateType,\n\t\t\t\taggregateId: stream.aggregateId,\n\t\t\t\texpectedVersion: options.expectedVersion,\n\t\t\t\tactualVersion: existing?.length ?? 0,\n\t\t\t});\n\t\t}\n\t\tif (\n\t\t\texisting === undefined &&\n\t\t\tthis.maxStreams !== undefined &&\n\t\t\tthis.streams.size >= this.maxStreams\n\t\t) {\n\t\t\tthrow new InMemoryCapacityExceededError({\n\t\t\t\tstore: \"InMemoryEventStore\",\n\t\t\t\tresource: \"streams\",\n\t\t\t\tlimit: this.maxStreams,\n\t\t\t\tcurrent: this.streams.size,\n\t\t\t\tattempted: 1,\n\t\t\t});\n\t\t}\n\t\tif (\n\t\t\tthis.maxEvents !== undefined &&\n\t\t\tthis.totalEvents + events.length > this.maxEvents\n\t\t) {\n\t\t\tthrow new InMemoryCapacityExceededError({\n\t\t\t\tstore: \"InMemoryEventStore\",\n\t\t\t\tresource: \"events\",\n\t\t\t\tlimit: this.maxEvents,\n\t\t\t\tcurrent: this.totalEvents,\n\t\t\t\tattempted: events.length,\n\t\t\t});\n\t\t}\n\t\t// Atomic by construction: the conflict check above throws before\n\t\t// anything is written (including the get-or-create, so a rejected\n\t\t// append on a nonexistent stream leaves no empty entry behind).\n\t\t// Pushing in place keeps append O(batch) instead of O(stream) per\n\t\t// call; no caller ever holds the internal array (readStream\n\t\t// slices). Element-wise, not push(...events): a spread into\n\t\t// arguments overflows the engine's argument limit on huge batches.\n\t\tlet storedEvents = existing;\n\t\tif (storedEvents === undefined) {\n\t\t\tstoredEvents = [];\n\t\t\tthis.streams.set(key, storedEvents);\n\t\t}\n\t\tfor (const event of events) {\n\t\t\t// Detached on write and on read: the port forbids handing out\n\t\t\t// live internal state, and a caller-mutated plain event must not\n\t\t\t// rewrite stored history. Kit-minted events are already frozen;\n\t\t\t// the clone detaches them from the shared graph as well.\n\t\t\tstoredEvents.push(structuredClone(event));\n\t\t}\n\t\tthis.totalEvents += events.length;\n\t}\n\n\tasync readStream(\n\t\tstream: AggregateAddress,\n\t\toptions: ReadStreamOptions,\n\t): Promise<StreamReadResult<Evt>> {\n\t\tif (!Number.isSafeInteger(options?.limit) || options.limit < 1) {\n\t\t\tthrow new RangeError(\n\t\t\t\t`InMemoryEventStore: limit must be a positive safe integer, got ${String(options?.limit)}`,\n\t\t\t);\n\t\t}\n\t\tassertStreamPosition(\"fromVersion\", options.fromVersion);\n\t\tassertStreamPosition(\"toVersion\", options.toVersion);\n\t\tconst events = this.streams.get(encodeAggregateAddress(stream));\n\t\tif (events === undefined) {\n\t\t\treturn { exists: false, lastVersion: 0, events: [] };\n\t\t}\n\t\tconst fromVersion = options.fromVersion ?? 0;\n\t\tconst toVersion = options.toVersion;\n\t\tconst pageEnd = Math.min(\n\t\t\ttoVersion ?? events.length,\n\t\t\tfromVersion + options.limit,\n\t\t);\n\t\t// Cloned, not sliced: slice() copies the ARRAY but hands out live\n\t\t// references to the stored elements, and a reader mutating one would\n\t\t// silently corrupt every later replay.\n\t\treturn {\n\t\t\texists: true,\n\t\t\tlastVersion: events.length,\n\t\t\tevents: structuredClone(events.slice(fromVersion, pageEnd)),\n\t\t};\n\t}\n}\n","import { someChainRetryable } from \"@shirudo/base-error\";\nimport { abortReason } from \"../../internal/async/abort\";\nimport {\n\tcomputeBackoffDelay,\n\tneutralJitterSource,\n} from \"../../internal/async/backoff\";\nimport { sleepRejectingOnAbort } from \"../../internal/async/sleep\";\nimport { reportToObserver } from \"../../internal/observer\";\nimport {\n\tassertNonNegativeFinite,\n\tassertPositiveInteger,\n} from \"../../internal/validate\";\nimport type { TransactionalOptions, TransactionScope } from \"./scope\";\n\n/**\n * Tuning for {@link RetryingTransactionScope}. All fields are optional;\n * the defaults suit optimistic-concurrency retries (a handful of writers\n * racing one aggregate), not high-fan-out hot-row contention.\n */\nexport interface RetryPolicy {\n\t/** Total tries, including the first. Default `3` (1 initial + 2 retries). */\n\tmaxAttempts?: number;\n\t/** First backoff delay; doubles each retry. Default `50`ms. */\n\tbaseDelayMs?: number;\n\t/** Ceiling for the backoff delay. Default `1000`ms. */\n\tmaxDelayMs?: number;\n\t/**\n\t * Classifier deciding whether an error is worth retrying. Default\n\t * {@link someChainRetryable} (walks the cause chain for the loose\n\t * `retryable === true` marker, so `ConcurrencyConflictError` matches\n\t * even when an adapter wraps it). Override to add driver-specific\n\t * serialization codes (Postgres 40001, MySQL 1213, SQLite SQLITE_BUSY)\n\t * that your adapter has not mapped to a retryable kit error.\n\t *\n\t * Guarded like `onRetry`: a THROWING classifier counts as \"not\n\t * retryable\" and the transaction's ORIGINAL error surfaces, never the\n\t * classifier's own failure.\n\t */\n\tisRetryable?: (error: unknown) => boolean;\n\t/**\n\t * Observer fired before each backoff wait (logging / metrics).\n\t * Neutralised like the `withCommit` observers: a synchronous throw or\n\t * an async rejection is swallowed, so a buggy observer can neither\n\t * abort the retry loop nor mask the original retryable error.\n\t */\n\tonRetry?: (info: {\n\t\tattempt: number;\n\t\terror: unknown;\n\t\tdelayMs: number;\n\t}) => void;\n\t/** Backoff wait. Default an abortable `setTimeout`. Injectable for tests. */\n\tsleep?: (ms: number, signal?: AbortSignal) => Promise<void>;\n\t/** Jitter source in `[0, 1)`. Default `Math.random`. Injectable for tests. */\n\trandom?: () => number;\n}\n\nconst DEFAULT_MAX_ATTEMPTS = 3;\nconst DEFAULT_BASE_DELAY_MS = 50;\nconst DEFAULT_MAX_DELAY_MS = 1000;\n\nconst ABORT_MESSAGE = \"RetryingTransactionScope aborted\";\n\n/** Abortable `setTimeout`; rejects with the signal reason if aborted. */\nfunction defaultSleep(ms: number, signal?: AbortSignal): Promise<void> {\n\treturn sleepRejectingOnAbort(ms, signal, ABORT_MESSAGE);\n}\n\n/**\n * A {@link TransactionScope} that retries its inner scope on transient\n * failures with exponential backoff and jitter. Compose it transparently:\n *\n * ```ts\n * const scope = new RetryingTransactionScope(drizzleScope, { maxAttempts: 5 });\n * const uow = new UnitOfWork({ scope, outbox, repositories });\n * ```\n *\n * **Retries the transaction only.** Each attempt re-invokes the inner\n * `transactional` with a fresh transaction, so the work callback must be\n * reload-safe (load aggregates via `findById` inside it, never capture an\n * aggregate from a previous attempt) and free of non-transactional side\n * effects before commit. `withCommit` publishes AFTER the commit, so the\n * in-process publish is outside the retried region and never duplicated;\n * publish failures are handled by `onPublishError`, not retried here.\n *\n * **Classification is by error, not by guesswork.** Only errors the\n * `isRetryable` predicate accepts are retried; everything else (a\n * `DomainError`, `EventHarvestError`, `UnenrolledChangesError`,\n * `DuplicateAggregateError`, a non-Error throw) surfaces immediately.\n * After `maxAttempts` the last error is rethrown unchanged, so a caller\n * can still match `ConcurrencyConflictError` and map it to HTTP 409.\n *\n * **Cancellation.** The `AbortSignal` from `transactional` options is\n * checked before each attempt and aborts the backoff wait, so an\n * `AbortSignal.timeout(ms)` bounds total elapsed time (there is\n * deliberately no separate max-elapsed knob).\n */\nexport class RetryingTransactionScope<TCtx> implements TransactionScope<TCtx> {\n\t// Policy resolved and validated once at construction (a misconfigured\n\t// policy is a wiring bug and fails fast, never at run time).\n\tprivate readonly maxAttempts: number;\n\tprivate readonly baseDelayMs: number;\n\tprivate readonly maxDelayMs: number;\n\tprivate readonly isRetryable: (error: unknown) => boolean;\n\tprivate readonly sleep: (ms: number, signal?: AbortSignal) => Promise<void>;\n\tprivate readonly random: () => number;\n\tprivate readonly onRetry?: RetryPolicy[\"onRetry\"];\n\n\tconstructor(\n\t\tprivate readonly inner: TransactionScope<TCtx>,\n\t\tpolicy: RetryPolicy = {},\n\t) {\n\t\tthis.maxAttempts = policy.maxAttempts ?? DEFAULT_MAX_ATTEMPTS;\n\t\tthis.baseDelayMs = policy.baseDelayMs ?? DEFAULT_BASE_DELAY_MS;\n\t\tthis.maxDelayMs = policy.maxDelayMs ?? DEFAULT_MAX_DELAY_MS;\n\t\tassertPositiveInteger(\n\t\t\t\"RetryingTransactionScope\",\n\t\t\t\"maxAttempts\",\n\t\t\tthis.maxAttempts,\n\t\t);\n\t\tassertNonNegativeFinite(\n\t\t\t\"RetryingTransactionScope\",\n\t\t\t\"baseDelayMs\",\n\t\t\tthis.baseDelayMs,\n\t\t);\n\t\tassertNonNegativeFinite(\n\t\t\t\"RetryingTransactionScope\",\n\t\t\t\"maxDelayMs\",\n\t\t\tthis.maxDelayMs,\n\t\t);\n\t\tthis.isRetryable = policy.isRetryable ?? someChainRetryable;\n\t\tthis.sleep = policy.sleep ?? defaultSleep;\n\t\t// Wrapped like the poll loop's jitter: an injected source that throws\n\t\t// or returns a non-finite value must not replace the transaction's\n\t\t// original retryable error or eliminate the backoff.\n\t\tthis.random = neutralJitterSource(policy.random ?? Math.random);\n\t\tthis.onRetry = policy.onRetry;\n\t}\n\n\tasync transactional<T>(\n\t\tfn: (ctx: TCtx) => Promise<T>,\n\t\toptions?: TransactionalOptions,\n\t): Promise<T> {\n\t\tconst { maxAttempts, isRetryable, sleep } = this;\n\t\tconst signal = options?.signal;\n\t\tconst isRetryableSafe = (error: unknown): boolean => {\n\t\t\ttry {\n\t\t\t\treturn isRetryable(error);\n\t\t\t} catch {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t};\n\n\t\tfor (let attempt = 1; attempt <= maxAttempts; attempt++) {\n\t\t\tif (signal?.aborted) {\n\t\t\t\tthrow abortReason(signal, ABORT_MESSAGE);\n\t\t\t}\n\t\t\ttry {\n\t\t\t\treturn await this.inner.transactional(fn, options);\n\t\t\t} catch (error) {\n\t\t\t\t// Exhausted, or a failure retrying cannot fix: surface it\n\t\t\t\t// unchanged so the caller keeps the original error type.\n\t\t\t\t// The classifier itself is guarded like the onRetry observer\n\t\t\t\t// below: a throwing classifier (a custom predicate bug, or\n\t\t\t\t// the default someChainRetryable on a circular cause chain)\n\t\t\t\t// must not replace the transaction's failure, so its throw\n\t\t\t\t// counts as \"not retryable\" and the ORIGINAL error surfaces.\n\t\t\t\tif (attempt === maxAttempts || !isRetryableSafe(error)) {\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t\tconst delayMs = computeBackoffDelay(attempt, {\n\t\t\t\t\tbaseDelayMs: this.baseDelayMs,\n\t\t\t\t\tmaxDelayMs: this.maxDelayMs,\n\t\t\t\t\trandom: this.random,\n\t\t\t\t});\n\t\t\t\t// Observer only: a throwing or async-rejecting onRetry must\n\t\t\t\t// neither abort the retry loop nor mask the original error.\n\t\t\t\treportToObserver(() => this.onRetry?.({ attempt, error, delayMs }));\n\t\t\t\t// An abort during the wait rejects out of the loop with the\n\t\t\t\t// signal reason: cancellation wins over another attempt.\n\t\t\t\tawait sleep(delayMs, signal);\n\t\t\t}\n\t\t}\n\t\t// Unreachable: the loop either returns or throws on the last attempt.\n\t\tthrow new Error(\"RetryingTransactionScope: exhausted without result\");\n\t}\n}\n","import type { AggregateSnapshot } from \"../../../domain/aggregate/aggregate\";\nimport {\n\ttype AggregateAddress,\n\tencodeAggregateAddress,\n} from \"../../../domain/aggregate/aggregate-address\";\nimport { assertPositiveSafeInteger } from \"../../../internal/validate\";\nimport type { SnapshotStore } from \"../snapshot-store\";\n\nexport interface InMemorySnapshotStoreOptions {\n\t/** Maximum retained snapshots. The least recently used entry is evicted. */\n\treadonly maxEntries?: number;\n\t/** Snapshot lifetime from the most recent save. Loads do not extend it. */\n\treadonly ttlMs?: number;\n\t/** Store-local clock used only when `ttlMs` is configured. */\n\treadonly clock?: () => Date;\n}\n\ninterface StoredSnapshot<TState> {\n\treadonly snapshot: AggregateSnapshot<TState>;\n\treadonly expiresAtMs?: number;\n}\n\n/**\n * In-memory reference implementation of {@link SnapshotStore}: defines\n * the port's semantics and serves tests and demos. Snapshots are\n * deep-copied on save AND load (`structuredClone`; snapshot state is\n * serialisable data by the `SnapshotModel` contract), so neither the caller\n * nor the store can mutate the other's copy.\n *\n * Unconfigured retention is intended only for finite-lifetime tests and\n * demos. Unlike event history, receipts, or checkpoints, snapshots are\n * rebuildable derived data, so `maxEntries` may evict the least recently used\n * entry and `ttlMs` may expire it safely. A load updates LRU recency but does\n * not extend TTL; only another save does.\n */\nexport class InMemorySnapshotStore<TState = unknown>\n\timplements SnapshotStore<TState>\n{\n\tprivate readonly snapshots = new Map<string, StoredSnapshot<TState>>();\n\tprivate readonly maxEntries: number | undefined;\n\tprivate readonly ttlMs: number | undefined;\n\tprivate readonly clock: () => Date;\n\n\tconstructor(options: InMemorySnapshotStoreOptions = {}) {\n\t\tif (options.maxEntries !== undefined) {\n\t\t\tassertPositiveSafeInteger(\n\t\t\t\t\"InMemorySnapshotStore\",\n\t\t\t\t\"maxEntries\",\n\t\t\t\toptions.maxEntries,\n\t\t\t);\n\t\t}\n\t\tif (options.ttlMs !== undefined) {\n\t\t\tassertPositiveSafeInteger(\n\t\t\t\t\"InMemorySnapshotStore\",\n\t\t\t\t\"ttlMs\",\n\t\t\t\toptions.ttlMs,\n\t\t\t);\n\t\t}\n\t\tthis.maxEntries = options.maxEntries;\n\t\tthis.ttlMs = options.ttlMs;\n\t\tthis.clock = options.clock ?? (() => new Date());\n\t}\n\n\tasync load(\n\t\taddress: AggregateAddress,\n\t): Promise<AggregateSnapshot<TState> | undefined> {\n\t\tconst key = encodeAggregateAddress(address);\n\t\tconst stored = this.snapshots.get(key);\n\t\tif (stored === undefined) return undefined;\n\t\tif (\n\t\t\tstored.expiresAtMs !== undefined &&\n\t\t\tthis.readClock() >= stored.expiresAtMs\n\t\t) {\n\t\t\tthis.snapshots.delete(key);\n\t\t\treturn undefined;\n\t\t}\n\t\t// Map order is the LRU order. A read makes this entry most recent but\n\t\t// deliberately preserves its original expiry.\n\t\tthis.snapshots.delete(key);\n\t\tthis.snapshots.set(key, stored);\n\t\treturn structuredClone(stored.snapshot);\n\t}\n\n\tasync save(\n\t\taddress: AggregateAddress,\n\t\tsnapshot: AggregateSnapshot<TState>,\n\t): Promise<void> {\n\t\t// Clone before changing retention state: an unsupported snapshot value\n\t\t// must not evict a valid entry.\n\t\tconst ownedSnapshot = structuredClone(snapshot);\n\t\tconst key = encodeAggregateAddress(address);\n\t\tlet expiresAtMs: number | undefined;\n\t\tif (this.ttlMs !== undefined) {\n\t\t\tconst nowMs = this.readClock();\n\t\t\tthis.deleteExpired(nowMs);\n\t\t\texpiresAtMs = nowMs + this.ttlMs;\n\t\t}\n\t\tif (this.snapshots.has(key)) {\n\t\t\tthis.snapshots.delete(key);\n\t\t} else if (\n\t\t\tthis.maxEntries !== undefined &&\n\t\t\tthis.snapshots.size >= this.maxEntries\n\t\t) {\n\t\t\tconst oldest = this.snapshots.keys().next();\n\t\t\tif (!oldest.done) this.snapshots.delete(oldest.value);\n\t\t}\n\t\tthis.snapshots.set(key, { snapshot: ownedSnapshot, expiresAtMs });\n\t}\n\n\tasync delete(address: AggregateAddress): Promise<void> {\n\t\tthis.snapshots.delete(encodeAggregateAddress(address));\n\t}\n\n\tprivate readClock(): number {\n\t\tconst now = this.clock();\n\t\tif (!(now instanceof Date) || !Number.isFinite(now.getTime())) {\n\t\t\tthrow new TypeError(\n\t\t\t\t\"InMemorySnapshotStore: clock must return a valid Date\",\n\t\t\t);\n\t\t}\n\t\treturn now.getTime();\n\t}\n\n\tprivate deleteExpired(nowMs: number): void {\n\t\tfor (const [key, stored] of this.snapshots) {\n\t\t\tif (stored.expiresAtMs !== undefined && nowMs >= stored.expiresAtMs) {\n\t\t\t\tthis.snapshots.delete(key);\n\t\t\t}\n\t\t}\n\t}\n}\n","import {\n\ttype AggregateSnapshot,\n\ttoVersion,\n\ttype Version,\n} from \"../../domain/aggregate/aggregate\";\nimport { SnapshotTimeValidationError } from \"../../domain/event/domain-event-errors\";\nimport type { Id } from \"../../domain/identity/id\";\nimport { deepFreeze } from \"../../domain/value-object/value-object\";\nimport {\n\tisDomainErrorLike,\n\tSnapshotCorruptedError,\n\tSnapshotSchemaMismatchError,\n\tSnapshotVersionNotRestoredError,\n} from \"../../errors/kit-errors\";\nimport { detachState } from \"../../internal/structural/detach-state\";\nimport { assertPositiveSafeInteger } from \"../../internal/validate\";\n\ninterface SnapshotAggregate {\n\treadonly id: Id<string>;\n\treadonly version: Version;\n}\n\n/**\n * Adapter-owned mapping between an OO aggregate and its stored snapshot DTO.\n *\n * Snapshot shape, schema migration, envelope construction, and reconstitution\n * are persistence concerns. The aggregate remains responsible for producing a\n * valid domain object; it does not know when or how snapshots are stored.\n */\nexport interface SnapshotModel<\n\tTAggregate extends SnapshotAggregate,\n\tTSnapshotState,\n> {\n\t/** Stable type name used to address schema errors and snapshot storage. */\n\treadonly aggregateType: string;\n\n\t/** Current schema version of the stored snapshot DTO. */\n\treadonly schemaVersion: number;\n\n\t/** Projects the current aggregate into a persistence DTO. */\n\tcapture(aggregate: TAggregate): TSnapshotState;\n\n\t/**\n\t * Reconstitutes a fresh, valid aggregate without recording a new decision.\n\t * This is normally a call to a static aggregate factory.\n\t *\n\t * A snapshot persisted under yesterday's decision rules must keep loading\n\t * after a rule change (\"replay from zero equals snapshot plus tail\"). The\n\t * factory passes `trustInitialState: true` to the constructor, so\n\t * `validateState` does not run on the stored state; the aggregates guide\n\t * (\"Where Invariants Live\") states the rule and the factory shape. When\n\t * a factory without the option rejects the blob with a `DomainError`,\n\t * `reconstituteAggregateFromSnapshot` surfaces it as a\n\t * {@link SnapshotCorruptedError} so the documented load recipe can\n\t * discard the derived snapshot and refold from the stream; the load then\n\t * still succeeds, at the cost of a full replay on every hit.\n\t */\n\treconstitute(\n\t\tid: TAggregate[\"id\"],\n\t\tstate: TSnapshotState,\n\t\tversion: Version,\n\t): TAggregate;\n\n\t/** Upgrades an older stored DTO into the model's current DTO shape. */\n\treadonly migrate?: (\n\t\tstored: unknown,\n\t\tstoredSchemaVersion: number,\n\t) => TSnapshotState;\n}\n\n/** Type-inference helper for declaring an adapter-owned snapshot model. */\nexport function defineSnapshotModel<\n\tTAggregate extends SnapshotAggregate,\n\tTSnapshotState,\n>(\n\tmodel: SnapshotModel<TAggregate, TSnapshotState>,\n): SnapshotModel<TAggregate, TSnapshotState> {\n\t// Validated AFTER the spread, on what actually survives it: the spread\n\t// copies own enumerable properties only, so capture/reconstitute carried\n\t// on a prototype (class instance) vanish silently and would surface much\n\t// later as a raw TypeError outside the corruption channel.\n\tconst detached = Object.freeze({ ...model });\n\tassertSnapshotModel(detached);\n\treturn detached;\n}\n\n/**\n * Captures a detached persistence envelope at an application-supplied time.\n * The application decides when snapshotting is worthwhile; this function does\n * not read a clock or perform I/O. The envelope is deep-frozen, its `state`\n * and its `snapshotAt` included: a write into the captured state or a\n * `Date` mutator on the returned time throws. So a change between capture\n * and save cannot reach the store. The freeze walks the state DTO once per\n * capture; see {@link deepFreeze} for the built-ins it cannot seal.\n */\nexport function captureAggregateSnapshot<\n\tTAggregate extends SnapshotAggregate,\n\tTSnapshotState,\n>(\n\tmodel: SnapshotModel<TAggregate, TSnapshotState>,\n\taggregate: TAggregate,\n\tsnapshotAt: Date,\n): AggregateSnapshot<TSnapshotState> {\n\tassertSnapshotModel(model);\n\tconst recordedAt = copySnapshotAt(snapshotAt);\n\tconst state = detachState(model.capture(aggregate));\n\treturn deepFreeze({\n\t\tstate,\n\t\tversion: aggregate.version,\n\t\tsnapshotAt: recordedAt,\n\t\tschemaVersion: model.schemaVersion,\n\t});\n}\n\n/**\n * Reconstitutes a fresh aggregate from a stored snapshot through the owning\n * adapter model. A missing schema version denotes the original schema `1`.\n *\n * A `DomainError` thrown while interpreting the stored blob (the model's\n * `migrate`, or `validateState` inside a reconstitution factory that does\n * not pass `trustInitialState`) is surfaced as a {@link SnapshotCorruptedError}:\n * a snapshot is DERIVED data, so the caller's discard-and-refold branch must\n * see one catchable corruption channel instead of a raw domain rejection\n * escaping `getById` after a rule change. A stored version that is not a\n * valid `Version` is surfaced the same way. `SnapshotSchemaMismatchError`\n * (a configuration gap, not corruption) and non-domain throws propagate,\n * including an `InvalidVersionError` the factory itself throws. A factory\n * that returns an aggregate at a version other than the snapshot version\n * fails with a {@link SnapshotVersionNotRestoredError}.\n */\nexport function reconstituteAggregateFromSnapshot<\n\tTAggregate extends SnapshotAggregate,\n\tTSnapshotState,\n>(\n\tmodel: SnapshotModel<TAggregate, TSnapshotState>,\n\tid: TAggregate[\"id\"],\n\tsnapshot: AggregateSnapshot<unknown>,\n): TAggregate {\n\tassertSnapshotModel(model);\n\tconst storedSchemaVersion = snapshot.schemaVersion ?? 1;\n\t// A corrupt stored version is derived-data corruption like a bad blob:\n\t// surfaced as SnapshotCorruptedError so the load recipe discards and\n\t// refolds. Checked BEFORE the factory runs, so an InvalidVersionError\n\t// thrown by the factory itself (a wiring bug such as a restore below a\n\t// version the factory already advanced) propagates unwrapped, like the\n\t// version post-condition below.\n\tlet version: Version;\n\ttry {\n\t\tversion = toVersion(snapshot.version);\n\t} catch (error) {\n\t\tthrow new SnapshotCorruptedError(\n\t\t\t`Snapshot of ${model.aggregateType} ${String(id)} carries the ` +\n\t\t\t\t`invalid version ${String(snapshot.version)}. Discard the derived ` +\n\t\t\t\t\"snapshot and refold from the stream.\",\n\t\t\terror,\n\t\t);\n\t}\n\tlet aggregate: TAggregate;\n\ttry {\n\t\tlet state: TSnapshotState;\n\t\tif (storedSchemaVersion === model.schemaVersion) {\n\t\t\tstate = detachState(snapshot.state) as TSnapshotState;\n\t\t} else if (model.migrate) {\n\t\t\tstate = detachState(\n\t\t\t\tmodel.migrate(detachState(snapshot.state), storedSchemaVersion),\n\t\t\t);\n\t\t} else {\n\t\t\tthrow new SnapshotSchemaMismatchError({\n\t\t\t\taggregateType: model.aggregateType,\n\t\t\t\taggregateId: String(id),\n\t\t\t\texpectedSchemaVersion: model.schemaVersion,\n\t\t\t\tactualSchemaVersion: storedSchemaVersion,\n\t\t\t});\n\t\t}\n\t\taggregate = model.reconstitute(id, state, version);\n\t} catch (error) {\n\t\t// Copy-safe: the model factory may run in another loaded copy of the\n\t\t// kit (adapter package, dual CJS/ESM load), whose DomainError fails a\n\t\t// plain instanceof; the corruption channel must catch it regardless.\n\t\tif (isDomainErrorLike(error)) {\n\t\t\tthrow new SnapshotCorruptedError(\n\t\t\t\t`Snapshot of ${model.aggregateType} ${String(id)} (schema ` +\n\t\t\t\t\t`${storedSchemaVersion}, version ${String(snapshot.version)}) was ` +\n\t\t\t\t\t\"rejected during reconstitution. Discard the derived snapshot and \" +\n\t\t\t\t\t\"refold from the stream.\",\n\t\t\t\terror,\n\t\t\t);\n\t\t}\n\t\tthrow error;\n\t}\n\t// Post-condition, not corruption: a factory that ignores the version\n\t// parameter (a forgotten markReconstituted) is a deterministic model wiring\n\t// bug. Routing it into the discard-and-refold channel would mask it as\n\t// perpetual silent refolding, so it surfaces as a wiring error instead.\n\tif (aggregate.version !== snapshot.version) {\n\t\tthrow new SnapshotVersionNotRestoredError({\n\t\t\taggregateType: model.aggregateType,\n\t\t\taggregateId: String(id),\n\t\t\tsnapshotVersion: snapshot.version,\n\t\t\trestoredVersion: aggregate.version,\n\t\t});\n\t}\n\treturn aggregate;\n}\n\nfunction assertSnapshotModel(model: {\n\treadonly aggregateType: string;\n\treadonly schemaVersion: number;\n\treadonly capture: unknown;\n\treadonly reconstitute: unknown;\n\treadonly migrate?: unknown;\n}): void {\n\tif (\n\t\ttypeof model.aggregateType !== \"string\" ||\n\t\tmodel.aggregateType.trim().length === 0\n\t) {\n\t\tthrow new TypeError(\n\t\t\t\"SnapshotModel.aggregateType must be a non-empty string\",\n\t\t);\n\t}\n\tassertPositiveSafeInteger(\n\t\t\"SnapshotModel\",\n\t\t\"schemaVersion\",\n\t\tmodel.schemaVersion,\n\t);\n\tfor (const key of [\"capture\", \"reconstitute\"] as const) {\n\t\tif (typeof model[key] !== \"function\") {\n\t\t\tthrow new TypeError(\n\t\t\t\t`SnapshotModel.${key} is missing or not a function. ` +\n\t\t\t\t\t\"defineSnapshotModel copies own enumerable properties only; \" +\n\t\t\t\t\t\"prototype methods are not carried. Pass a plain object literal.\",\n\t\t\t);\n\t\t}\n\t}\n\tif (model.migrate !== undefined && typeof model.migrate !== \"function\") {\n\t\tthrow new TypeError(\"SnapshotModel.migrate must be a function when set\");\n\t}\n}\n\nfunction copySnapshotAt(snapshotAt: Date): Date {\n\tif (!(snapshotAt instanceof Date) || !Number.isFinite(snapshotAt.getTime())) {\n\t\tthrow new SnapshotTimeValidationError();\n\t}\n\treturn new Date(snapshotAt.getTime());\n}\n"],"mappings":"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"}
|