@shirudo/ddd-kit 3.0.0-rc.13 → 3.0.0-rc.15
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 +1 -1
- package/dist/chunks/kit-errors.d.ts +7 -7
- package/dist/chunks/kit-errors.js +8 -8
- package/dist/chunks/kit-errors.js.map +1 -1
- package/dist/chunks/read-stream-pages.js +52 -4
- package/dist/chunks/read-stream-pages.js.map +1 -1
- package/dist/chunks/snapshot-store.d.ts +78 -23
- package/dist/chunks/value-object.js +1 -1
- package/dist/chunks/value-object.js.map +1 -1
- package/dist/http.d.ts +1 -1
- package/dist/http.js +1 -1
- package/dist/http.js.map +1 -1
- package/dist/index.d.ts +48 -88
- package/dist/index.js +74 -50
- package/dist/index.js.map +1 -1
- package/dist/testing.d.ts +6 -6
- package/dist/testing.js +38 -12
- package/dist/testing.js.map +1 -1
- package/package.json +1 -1
|
@@ -193,15 +193,16 @@ type ClockFactory = () => Date;
|
|
|
193
193
|
/**
|
|
194
194
|
* Factory function producing a fresh, unique event identifier for each call.
|
|
195
195
|
*
|
|
196
|
-
* The library ships a default that
|
|
197
|
-
* (works on Node 19+, modern browsers in secure
|
|
198
|
-
* Cloudflare Workers, Vercel Edge, and any runtime that
|
|
199
|
-
* Crypto).
|
|
200
|
-
*
|
|
201
|
-
*
|
|
202
|
-
*
|
|
203
|
-
*
|
|
204
|
-
* KSUID, or another collision-safe format without mutating module
|
|
196
|
+
* The library ships a default that creates a time-ordered **UUID v7** from
|
|
197
|
+
* Web Crypto random bits (works on Node 19+, modern browsers in secure
|
|
198
|
+
* contexts, Deno, Bun, Cloudflare Workers, Vercel Edge, and any runtime that
|
|
199
|
+
* implements Web Crypto). A B-tree index on the eventId column stays
|
|
200
|
+
* clustered. The id is no ordering authority: ids from several processes
|
|
201
|
+
* interleave within one millisecond, and clock skew can invert them. Order
|
|
202
|
+
* events by aggregate version or stream position. Supply another generator
|
|
203
|
+
* to {@link createDomainEventFactory} to
|
|
204
|
+
* use ULID, KSUID, or another collision-safe format without mutating module
|
|
205
|
+
* state.
|
|
205
206
|
*/
|
|
206
207
|
type EventIdFactory = () => string;
|
|
207
208
|
/**
|
|
@@ -266,8 +267,8 @@ interface DomainEvent<T extends string, P = void> {
|
|
|
266
267
|
/**
|
|
267
268
|
* Unique identifier for this specific event instance. Used by idempotent
|
|
268
269
|
* consumers, outbox dispatch tracking, and as the target of
|
|
269
|
-
* `metadata.causationId`. Convenience constructors default to
|
|
270
|
-
*
|
|
270
|
+
* `metadata.causationId`. Convenience constructors default to a UUID v7;
|
|
271
|
+
* strict construction requires the caller to supply it.
|
|
271
272
|
*/
|
|
272
273
|
readonly eventId: string;
|
|
273
274
|
/**
|
|
@@ -291,7 +292,7 @@ interface DomainEvent<T extends string, P = void> {
|
|
|
291
292
|
*/
|
|
292
293
|
readonly payload: P;
|
|
293
294
|
/**
|
|
294
|
-
* Timestamp when the
|
|
295
|
+
* Timestamp when the application shell stamped the accepted fact.
|
|
295
296
|
* Put business-relevant time in the payload under a domain name.
|
|
296
297
|
*/
|
|
297
298
|
readonly occurredAt: Date;
|
|
@@ -342,10 +343,11 @@ type AnyUnstampedDomainEvent = UnstampedDomainEvent<string, unknown>;
|
|
|
342
343
|
type UnstampedDomainEventOf<TEvent extends AnyDomainEvent> = TEvent extends DomainEvent<infer TType, infer TPayload> ? UnstampedDomainEvent<TType, TPayload> : never;
|
|
343
344
|
/** An aggregate may hold unstamped decisions and already stamped events together. */
|
|
344
345
|
type PendingDomainEvent<TEvent extends AnyDomainEvent> = TEvent | UnstampedDomainEventOf<TEvent>;
|
|
345
|
-
/**
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
346
|
+
/**
|
|
347
|
+
* Options of `createEvent` in an aggregate. The aggregate fills its own
|
|
348
|
+
* identity, so only the schema version of the payload is left.
|
|
349
|
+
*/
|
|
350
|
+
interface CreateEventOptions {
|
|
349
351
|
readonly schemaVersion?: number;
|
|
350
352
|
}
|
|
351
353
|
/**
|
|
@@ -355,7 +357,7 @@ interface CreateDomainEventOptions {
|
|
|
355
357
|
/**
|
|
356
358
|
* Override for the auto-generated `eventId`. Pass an existing id (for
|
|
357
359
|
* replay, tests, or deterministic event sourcing) instead of letting the
|
|
358
|
-
* factory
|
|
360
|
+
* factory generate a UUID v7.
|
|
359
361
|
*/
|
|
360
362
|
eventId?: string;
|
|
361
363
|
/**
|
|
@@ -402,7 +404,7 @@ interface CreateDomainEventStampOptions {
|
|
|
402
404
|
}
|
|
403
405
|
/** Dependencies captured by one immutable domain-event factory instance. */
|
|
404
406
|
interface DomainEventFactoryOptions {
|
|
405
|
-
/** Event-id generator. Defaults to Web Crypto
|
|
407
|
+
/** Event-id generator. Defaults to a UUID v7 from Web Crypto random bits. */
|
|
406
408
|
readonly eventIdFactory?: EventIdFactory;
|
|
407
409
|
/** Event-recording clock. Defaults to `() => new Date()`. */
|
|
408
410
|
readonly clock?: ClockFactory;
|
|
@@ -442,7 +444,7 @@ interface DomainEventFactory {
|
|
|
442
444
|
* The supplied functions are read once and captured by value. The returned
|
|
443
445
|
* object is frozen, so another request, test, or library cannot replace its
|
|
444
446
|
* policy. Its {@link DomainEventFactory.createStamp} method is the
|
|
445
|
-
* application-shell bridge that
|
|
447
|
+
* application-shell bridge that stamps an accepted aggregate decision.
|
|
446
448
|
* Passing the factory through `AggregateConfig`
|
|
447
449
|
* enables the explicitly named convenience methods, whose defaults read time
|
|
448
450
|
* and randomness.
|
|
@@ -453,8 +455,7 @@ interface DomainEventFactory {
|
|
|
453
455
|
* eventIdFactory: () => uuidv7(),
|
|
454
456
|
* clock: () => new Date(),
|
|
455
457
|
* });
|
|
456
|
-
*
|
|
457
|
-
* stampPendingEvents(order, domainEvents);
|
|
458
|
+
* const uow = new UnitOfWork({ ...deps, eventStampFactory: domainEvents });
|
|
458
459
|
* ```
|
|
459
460
|
*/
|
|
460
461
|
declare function createDomainEventFactory(options?: DomainEventFactoryOptions): DomainEventFactory;
|
|
@@ -937,7 +938,7 @@ type Id<Tag extends string> = string & {
|
|
|
937
938
|
* The kit makes no attempt to dedupe or detect collisions: a collision
|
|
938
939
|
* silently overwrites earlier rows (under unique-key constraints) or
|
|
939
940
|
* silently aliases two different entities (without them). Safe choices:
|
|
940
|
-
* `crypto.randomUUID()` (UUIDv4
|
|
941
|
+
* UUIDv7 (the default for events), `crypto.randomUUID()` (UUIDv4), ULID,
|
|
941
942
|
* KSUID: all collision-resistant by design. Unsafe choices: `Date.now()`
|
|
942
943
|
* alone (duplicates within the same millisecond), a process-local
|
|
943
944
|
* counter without persistence (resets to 1 on restart, collides with
|
|
@@ -1396,6 +1397,43 @@ interface TransactionScope<TCtx> {
|
|
|
1396
1397
|
transactional<T>(fn: (ctx: TCtx) => Promise<T>, options?: TransactionalOptions): Promise<T>;
|
|
1397
1398
|
}
|
|
1398
1399
|
//#endregion
|
|
1400
|
+
//#region src/application/unit-of-work/stamp-pending-events.d.ts
|
|
1401
|
+
/** Minimal shell role accepted by {@link stampPendingEvents}. */
|
|
1402
|
+
type DomainEventStampFactory = Pick<DomainEventFactory, "createStamp">;
|
|
1403
|
+
/** Per-decision stamp provider for metadata that depends on the event. */
|
|
1404
|
+
type DomainEventStampProvider<TEvent extends AnyDomainEvent> = (event: UnstampedDomainEventOf<TEvent>, index: number) => DomainEventStamp;
|
|
1405
|
+
/**
|
|
1406
|
+
* Stamp options that every decision of one stamping shares: a stamp time
|
|
1407
|
+
* and metadata such as the correlation id of the request. An `eventId` is per
|
|
1408
|
+
* fact, so the factory creates it for each decision.
|
|
1409
|
+
*/
|
|
1410
|
+
type SharedDomainEventStampOptions = Omit<CreateDomainEventStampOptions, "eventId">;
|
|
1411
|
+
/**
|
|
1412
|
+
* Stamps every still-unstamped event accepted by an aggregate.
|
|
1413
|
+
*
|
|
1414
|
+
* The commit stamps every still-unstamped event when it registers the
|
|
1415
|
+
* aggregate, so a use case does not need this function. Call it first when
|
|
1416
|
+
* the metadata depends on the concrete decision, for an import, or for a test
|
|
1417
|
+
* that needs fixed ids. The commit keeps the stamps that this function set.
|
|
1418
|
+
*
|
|
1419
|
+
* The function is a command that also returns the stamped batch, a
|
|
1420
|
+
* deliberate exception to command-query separation: the caller hands the
|
|
1421
|
+
* batch on to persistence and needs no second read of `pendingEvents`.
|
|
1422
|
+
*
|
|
1423
|
+
* Stamping is atomic with respect to the aggregate's pending list: if stamp
|
|
1424
|
+
* creation or validation fails, every decision remains unstamped. A
|
|
1425
|
+
* successful second call returns the same event objects and does not read the
|
|
1426
|
+
* factory again, so an instance that a retried attempt registers again keeps
|
|
1427
|
+
* its event identities.
|
|
1428
|
+
*
|
|
1429
|
+
* Pass a `DomainEventFactory` (only its `createStamp` role is required) for one
|
|
1430
|
+
* uniform stamping policy. Add `stampOptions` for metadata that every
|
|
1431
|
+
* decision of the batch shares, such as the correlation id of the request.
|
|
1432
|
+
* Pass a callback instead when metadata depends on the concrete decision.
|
|
1433
|
+
*/
|
|
1434
|
+
declare function stampPendingEvents<TId extends Id<string>, TEvent extends AnyDomainEvent>(aggregate: Aggregate<TId, TEvent>, factory: DomainEventStampFactory, stampOptions?: SharedDomainEventStampOptions): ReadonlyArray<TEvent>;
|
|
1435
|
+
declare function stampPendingEvents<TId extends Id<string>, TEvent extends AnyDomainEvent>(aggregate: Aggregate<TId, TEvent>, createStamp: DomainEventStampProvider<TEvent>): ReadonlyArray<TEvent>;
|
|
1436
|
+
//#endregion
|
|
1399
1437
|
//#region src/application/cqrs/handler.d.ts
|
|
1400
1438
|
/** Dependencies for {@link withCommit}. */
|
|
1401
1439
|
interface WithCommitDeps<Evt extends AnyDomainEvent, TCtx> {
|
|
@@ -1459,6 +1497,19 @@ interface WithCommitDeps<Evt extends AnyDomainEvent, TCtx> {
|
|
|
1459
1497
|
* unless the scope honors the signal.
|
|
1460
1498
|
*/
|
|
1461
1499
|
signal?: AbortSignal;
|
|
1500
|
+
/**
|
|
1501
|
+
* Stamps every pending event that is still unstamped when its aggregate is
|
|
1502
|
+
* registered: the event id, the stamp time, and the metadata. Defaults to
|
|
1503
|
+
* `createDomainEventFactory()`, a UUID v7 from Web Crypto random bits and
|
|
1504
|
+
* the system clock. An event that is already stamped, for example by an
|
|
1505
|
+
* explicit `stampPendingEvents` call, keeps its stamp.
|
|
1506
|
+
*/
|
|
1507
|
+
eventStampFactory?: DomainEventStampFactory;
|
|
1508
|
+
/**
|
|
1509
|
+
* Stamp options that every event stamped in this commit shares, for
|
|
1510
|
+
* example the correlation id of the request.
|
|
1511
|
+
*/
|
|
1512
|
+
stampOptions?: SharedDomainEventStampOptions;
|
|
1462
1513
|
}
|
|
1463
1514
|
declare const aggregateCommitTokenBrand: unique symbol;
|
|
1464
1515
|
/**
|
|
@@ -2667,6 +2718,10 @@ interface EventStore<Evt extends AnyDomainEvent> extends EventStreamReader<Evt>
|
|
|
2667
2718
|
* proves the duplicate/gap rejection. The repository then calls
|
|
2668
2719
|
* `replayHistory`, whose replay guard rejects any event carrying an
|
|
2669
2720
|
* aggregate type or id that contradicts this stream key.
|
|
2721
|
+
* 7. **Stamped events only:** reject an event without an `eventId` with
|
|
2722
|
+
* a `TypeError`, before any write. A direct `withCommit` callback can
|
|
2723
|
+
* append before its registration stamps the events; this check makes
|
|
2724
|
+
* that mistake fail instead of storing ids that the outbox never sees.
|
|
2670
2725
|
*
|
|
2671
2726
|
* An empty `events` array is a no-op; implementations resolve without
|
|
2672
2727
|
* touching the store (an ES repository skips `append` for aggregates
|
|
@@ -2825,5 +2880,5 @@ interface SnapshotStore<TState = unknown> {
|
|
|
2825
2880
|
delete(identity: AggregateIdentity): Promise<void>;
|
|
2826
2881
|
}
|
|
2827
2882
|
//#endregion
|
|
2828
|
-
export {
|
|
2883
|
+
export { PublishOptions as $, JsonPrimitive as $t, IdempotentCommitRequest as A, CreateEventOptions as At, CommitRegistrationOptions as B, UnstampedDomainEventOf as Bt, IdempotencyClaim as C, CommittedDomainEvent as Ct, IdempotencyReconciliation as D, AnyUnstampedDomainEvent as Dt, IdempotencyOperationErrorContext as E, AnyDomainEvent as Et, DeadLetterDeadline as F, DomainEventStamp as Ft, DomainEventStampProvider as G, defaultDomainEventFactory as Gt, WithCommitWorkResult as H, createDomainEvent as Ht, DeadlineStore as I, EventIdFactory as It, TransactionScope as J, AggregateIdentity as Jt, SharedDomainEventStampOptions as K, mergeMetadata as Kt, DueDeadline as L, EventMetadata as Lt, IdempotentExecution as M, DomainEvent as Mt, WithIdempotentCommitDeps as N, DomainEventFactory as Nt, IdempotencyReconciliationDecision as O, CreateDomainEventOptions as Ot, withIdempotentCommit as P, DomainEventFactoryOptions as Pt, OnceOptions as Q, JsonObject as Qt, AggregateCommitToken as R, PendingDomainEvent as Rt, isPositionAfter as S, CommitPosition as St, IdempotencyLease as T, EventCommitCandidatePosition as Tt, withCommit as U, createDomainEventFactory as Ut, WithCommitDeps as V, copyMetadata as Vt, DomainEventStampFactory as W, createStampedDomainEvent as Wt, EventBus as X, CommandHandler as Xt, TransactionalOptions as Y, Command as Yt, EventHandler as Z, PublishedCommand as Zt, IdentityMap as _, DispatchTrackingOutbox as _t, EventStoreAppendOptions as a, toVersion as at, ProjectionCheckpointStore as b, OutboxWriter as bt, StreamReadResult as c, CommandCommitOriginCandidate as ct, RepositoryTracking as d, CommandOutboxCommitCandidate as dt, JsonValue as en, Aggregate as et, UnitOfWorkIdentityMap as f, CommandOutboxMapper as ft, AggregateClass as g, DeadLetterRecord as gt, PersistenceModel as h, routeEventsToCommandOutbox as ht, EventStore as i, sameVersion as it, IdempotentCommitResult as j, CreateStampedDomainEventOptions as jt, IdempotencyStore as k, CreateDomainEventStampOptions as kt, AggregatePersistenceWrite as l, CommandMessageContent as lt, PersistenceLifecycle as m, DurableCommandMessage as mt, ReplayableStreamPages as n, ReplayableAggregate as nt, EventStreamReader as o, Id as ot, PersistenceChanges as p, CommandOutboxWriter as pt, stampPendingEvents as q, ClockFactory as qt, reconstituteAggregateFromStreamPages as r, Version as rt, ReadStreamOptions as s, IdGenerator as st, SnapshotStore as t, AggregateSnapshot as tt, AggregateWriteIntent as u, CommandMessageRelationships as ut, Projection as v, Outbox as vt, IdempotencyClaimHandle as w, EventCommitCandidate as wt, ProjectionPosition as x, ExecutionContext as xt, ProjectionCheckpoint as y, OutboxRecord as yt, CommitRegistration as z, UnstampedDomainEvent as zt };
|
|
2829
2884
|
//# sourceMappingURL=snapshot-store.d.ts.map
|
|
@@ -492,7 +492,7 @@ function comparePlainObjects(objA, objB, visited) {
|
|
|
492
492
|
* path, so memoising the first path's result would be wrong. This is
|
|
493
493
|
* inherently exponential for diamond-shaped sharing (a node reachable
|
|
494
494
|
* via 2^n paths is cloned 2^n times); the walk aborts with a descriptive
|
|
495
|
-
* error after
|
|
495
|
+
* error after a fixed budget of node visits instead of
|
|
496
496
|
* hanging the process.
|
|
497
497
|
*
|
|
498
498
|
* **Prototype-pollution safety.** `__proto__` and `constructor` keys
|