@shirudo/ddd-kit 0.16.0 → 1.0.0-rc.1
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 +61 -75
- package/dist/index.d.ts +324 -318
- package/dist/index.js +881 -1
- package/dist/index.js.map +1 -1
- package/dist/result.js +297 -1
- package/dist/result.js.map +1 -1
- package/dist/utils-array.js +241 -1
- package/dist/utils-array.js.map +1 -1
- package/dist/utils.js +1 -0
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -8,6 +8,138 @@ interface IdGenerator {
|
|
|
8
8
|
next: <T extends string>() => Id<T>;
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
+
/**
|
|
12
|
+
* Metadata associated with a domain event for traceability and correlation.
|
|
13
|
+
* Used in event-driven architectures to track event flow across services.
|
|
14
|
+
*/
|
|
15
|
+
interface EventMetadata {
|
|
16
|
+
/**
|
|
17
|
+
* Correlation ID for tracing events across multiple services/components.
|
|
18
|
+
* Typically used to group related events in a distributed system.
|
|
19
|
+
*/
|
|
20
|
+
correlationId?: string;
|
|
21
|
+
/**
|
|
22
|
+
* Causation ID referencing the event or command that caused this event.
|
|
23
|
+
* Used to build event chains and understand causality.
|
|
24
|
+
*/
|
|
25
|
+
causationId?: string;
|
|
26
|
+
/**
|
|
27
|
+
* User ID of the person or system that triggered the event.
|
|
28
|
+
*/
|
|
29
|
+
userId?: string;
|
|
30
|
+
/**
|
|
31
|
+
* Source service or component that produced the event.
|
|
32
|
+
*/
|
|
33
|
+
source?: string;
|
|
34
|
+
/**
|
|
35
|
+
* Additional custom metadata fields.
|
|
36
|
+
* Allows extensibility for domain-specific metadata.
|
|
37
|
+
*/
|
|
38
|
+
[key: string]: unknown;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Domain Event represents something meaningful that happened in the domain.
|
|
42
|
+
* Events are immutable and carry information about what occurred.
|
|
43
|
+
*
|
|
44
|
+
* @template T - The event type name (e.g., "OrderCreated")
|
|
45
|
+
* @template P - The event payload type
|
|
46
|
+
*/
|
|
47
|
+
interface DomainEvent<T extends string, P = void> {
|
|
48
|
+
/**
|
|
49
|
+
* The type of the event, used for routing and handling.
|
|
50
|
+
*/
|
|
51
|
+
type: T;
|
|
52
|
+
/**
|
|
53
|
+
* The event payload containing the domain data.
|
|
54
|
+
* Omitted when P is void (events without payload).
|
|
55
|
+
*/
|
|
56
|
+
payload: P;
|
|
57
|
+
/**
|
|
58
|
+
* Timestamp when the event occurred.
|
|
59
|
+
*/
|
|
60
|
+
occurredAt: Date;
|
|
61
|
+
/**
|
|
62
|
+
* Event schema version for handling schema evolution.
|
|
63
|
+
* Required for safe schema migration in event-sourced systems.
|
|
64
|
+
* Use 1 for the initial schema version.
|
|
65
|
+
*/
|
|
66
|
+
version: number;
|
|
67
|
+
/**
|
|
68
|
+
* Optional metadata for traceability, correlation, and auditing.
|
|
69
|
+
* Includes correlationId, causationId, userId, source, and custom fields.
|
|
70
|
+
*/
|
|
71
|
+
metadata?: EventMetadata;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Creates a domain event with default values.
|
|
75
|
+
* Sets occurredAt to current date and version to 1 if not provided.
|
|
76
|
+
*
|
|
77
|
+
* @param type - The event type
|
|
78
|
+
* @param payload - The event payload
|
|
79
|
+
* @param options - Optional event configuration
|
|
80
|
+
* @returns A domain event
|
|
81
|
+
*
|
|
82
|
+
* @example
|
|
83
|
+
* ```typescript
|
|
84
|
+
* const event = createDomainEvent("OrderCreated", { orderId: "123" });
|
|
85
|
+
* ```
|
|
86
|
+
*/
|
|
87
|
+
declare function createDomainEvent<T extends string>(type: T, payload?: undefined, options?: {
|
|
88
|
+
occurredAt?: Date;
|
|
89
|
+
version?: number;
|
|
90
|
+
metadata?: EventMetadata;
|
|
91
|
+
}): DomainEvent<T, void>;
|
|
92
|
+
declare function createDomainEvent<T extends string, P>(type: T, payload: P, options?: {
|
|
93
|
+
occurredAt?: Date;
|
|
94
|
+
version?: number;
|
|
95
|
+
metadata?: EventMetadata;
|
|
96
|
+
}): DomainEvent<T, P>;
|
|
97
|
+
/**
|
|
98
|
+
* Creates a domain event with metadata for traceability.
|
|
99
|
+
* Convenience function for creating events with correlation and causation IDs.
|
|
100
|
+
*
|
|
101
|
+
* @example
|
|
102
|
+
* ```typescript
|
|
103
|
+
* const event = createDomainEventWithMetadata(
|
|
104
|
+
* "OrderCreated",
|
|
105
|
+
* { orderId: "123" },
|
|
106
|
+
* { correlationId: "corr-123", causationId: "cmd-456", userId: "user-789" }
|
|
107
|
+
* );
|
|
108
|
+
* ```
|
|
109
|
+
*/
|
|
110
|
+
declare function createDomainEventWithMetadata<T extends string, P>(type: T, payload: P, metadata: EventMetadata, options?: {
|
|
111
|
+
occurredAt?: Date;
|
|
112
|
+
version?: number;
|
|
113
|
+
}): DomainEvent<T, P>;
|
|
114
|
+
/**
|
|
115
|
+
* Copies metadata from a source event to a new event.
|
|
116
|
+
* Useful for maintaining correlation chains in event-driven architectures.
|
|
117
|
+
*
|
|
118
|
+
* @example
|
|
119
|
+
* ```typescript
|
|
120
|
+
* const newEvent = createDomainEvent(
|
|
121
|
+
* "OrderShipped",
|
|
122
|
+
* { orderId: "123" },
|
|
123
|
+
* { metadata: copyMetadata(previousEvent, { causationId: previousEvent.type }) }
|
|
124
|
+
* );
|
|
125
|
+
* ```
|
|
126
|
+
*/
|
|
127
|
+
declare function copyMetadata(sourceEvent: DomainEvent<string, unknown>, additionalMetadata?: Partial<EventMetadata>): EventMetadata;
|
|
128
|
+
/**
|
|
129
|
+
* Merges multiple metadata objects into one.
|
|
130
|
+
* Later metadata objects override earlier ones for the same keys.
|
|
131
|
+
*
|
|
132
|
+
* @example
|
|
133
|
+
* ```typescript
|
|
134
|
+
* const metadata = mergeMetadata(
|
|
135
|
+
* { correlationId: "corr-123" },
|
|
136
|
+
* { userId: "user-456" },
|
|
137
|
+
* { source: "order-service" }
|
|
138
|
+
* );
|
|
139
|
+
* ```
|
|
140
|
+
*/
|
|
141
|
+
declare function mergeMetadata(...metadataObjects: Array<EventMetadata | undefined>): EventMetadata;
|
|
142
|
+
|
|
11
143
|
/**
|
|
12
144
|
* Functional definition of an Entity via its capability.
|
|
13
145
|
* An object is identifiable if it has an id.
|
|
@@ -292,33 +424,24 @@ interface AggregateConfig {
|
|
|
292
424
|
autoVersionBump?: boolean;
|
|
293
425
|
}
|
|
294
426
|
/**
|
|
295
|
-
* Base class for
|
|
427
|
+
* Base class for Aggregate Roots without Event Sourcing.
|
|
296
428
|
*
|
|
297
|
-
*
|
|
298
|
-
*
|
|
299
|
-
*
|
|
429
|
+
* In DDD (Evans), an Aggregate is a cluster of objects — root entity, child entities,
|
|
430
|
+
* and value objects — treated as a unit for consistency. The **Aggregate Root** is the
|
|
431
|
+
* root entity that represents the aggregate externally and is the only entry point
|
|
432
|
+
* for external code. This class serves as both: it IS the root entity and it contains
|
|
433
|
+
* the aggregate state (`TState`) which holds child entities and value objects.
|
|
300
434
|
*
|
|
301
|
-
*
|
|
302
|
-
* - Identity (id)
|
|
303
|
-
* -
|
|
304
|
-
* -
|
|
305
|
-
*
|
|
306
|
-
* Adds Aggregate Root specific functionality:
|
|
307
|
-
* - Version management (for Optimistic Concurrency Control)
|
|
308
|
-
* - Domain events tracking
|
|
435
|
+
* Provides:
|
|
436
|
+
* - Identity (id) and state management (via `Entity`)
|
|
437
|
+
* - Version management for optimistic concurrency control
|
|
438
|
+
* - Domain event tracking for side-effects
|
|
309
439
|
* - Snapshot support for performance optimization
|
|
310
440
|
*
|
|
311
|
-
*
|
|
312
|
-
*
|
|
313
|
-
* - Value objects (immutable objects)
|
|
441
|
+
* All changes to child entities within `TState` are versioned through this root.
|
|
442
|
+
* Use `setState()` for state mutations to ensure invariant validation.
|
|
314
443
|
*
|
|
315
|
-
*
|
|
316
|
-
* applies to the entire aggregate, including all child entities.
|
|
317
|
-
*
|
|
318
|
-
* Implements `IAggregateRoot<TId>` to mark this as an Aggregate Root Entity.
|
|
319
|
-
*
|
|
320
|
-
* Use this class when you don't need Event Sourcing but still want
|
|
321
|
-
* aggregate patterns with versioning and state management.
|
|
444
|
+
* For event sourcing, use `EventSourcedAggregate` instead.
|
|
322
445
|
*
|
|
323
446
|
* @template TState - The type of the aggregate state (contains child entities and value objects)
|
|
324
447
|
* @template TId - The type of the aggregate root identifier
|
|
@@ -333,14 +456,15 @@ interface AggregateConfig {
|
|
|
333
456
|
* }
|
|
334
457
|
*
|
|
335
458
|
* confirm(): void {
|
|
336
|
-
* this.
|
|
337
|
-
* this.bumpVersion(); // Versions the entire aggregate
|
|
459
|
+
* this.setState({ ...this.state, status: "confirmed" }, true);
|
|
338
460
|
* }
|
|
339
461
|
* }
|
|
340
462
|
* ```
|
|
341
463
|
*/
|
|
342
464
|
declare abstract class AggregateRoot<TState, TId extends Id<string>, TEvent = unknown> extends Entity<TState, TId> implements IAggregateRoot<TId> {
|
|
343
|
-
|
|
465
|
+
private _version;
|
|
466
|
+
get version(): Version;
|
|
467
|
+
protected setVersion(version: Version): void;
|
|
344
468
|
private readonly _config;
|
|
345
469
|
private readonly _autoVersionBump;
|
|
346
470
|
private _domainEvents;
|
|
@@ -417,7 +541,7 @@ declare abstract class AggregateRoot<TState, TId extends Id<string>, TEvent = un
|
|
|
417
541
|
* @template TId - The type of the aggregate root identifier
|
|
418
542
|
* @template TEvent - The union type of all domain events
|
|
419
543
|
*/
|
|
420
|
-
interface
|
|
544
|
+
interface IEventSourcedAggregate<TId extends Id<string>, TEvent extends DomainEvent<string, unknown>> extends IAggregateRoot<TId> {
|
|
421
545
|
/**
|
|
422
546
|
* Returns a read-only list of new, not-yet-persisted events.
|
|
423
547
|
*/
|
|
@@ -447,9 +571,9 @@ interface IAggregateEventSourced<TId extends Id<string>, TEvent extends DomainEv
|
|
|
447
571
|
}
|
|
448
572
|
type Handler<TState, TEvent> = (state: TState, event: TEvent) => TState;
|
|
449
573
|
/**
|
|
450
|
-
*
|
|
574
|
+
* Configuration options for EventSourcedAggregate behavior.
|
|
451
575
|
*/
|
|
452
|
-
interface
|
|
576
|
+
interface EventSourcedAggregateConfig {
|
|
453
577
|
/**
|
|
454
578
|
* Whether to automatically bump the version when applying new events.
|
|
455
579
|
* Defaults to true. Set to false to manually control versioning.
|
|
@@ -457,26 +581,15 @@ interface AggregateEventSourcedConfig extends AggregateConfig {
|
|
|
457
581
|
autoVersionBump?: boolean;
|
|
458
582
|
}
|
|
459
583
|
/**
|
|
460
|
-
* Base class for Event-Sourced Aggregate Roots (
|
|
461
|
-
*
|
|
462
|
-
* Extends `AggregateRoot` to create an Aggregate Root Entity with Event Sourcing capabilities.
|
|
463
|
-
* The Aggregate Root is the parent Entity of the aggregate and represents it externally.
|
|
464
|
-
*
|
|
465
|
-
* The aggregate state (`TState`) contains:
|
|
466
|
-
* - Child entities (Entities with id, but no own version)
|
|
467
|
-
* - Value objects (immutable objects)
|
|
584
|
+
* Base class for Event-Sourced Aggregate Roots (Vernon, IDDD Chapter 8).
|
|
468
585
|
*
|
|
469
|
-
*
|
|
470
|
-
*
|
|
586
|
+
* Like `AggregateRoot`, this is both the root entity and the aggregate boundary.
|
|
587
|
+
* The difference is persistence: state is derived from events, not stored directly.
|
|
588
|
+
* Events are the single source of truth — all state changes go through `apply()` → handler.
|
|
471
589
|
*
|
|
472
|
-
* Extends `AggregateRoot`
|
|
473
|
-
*
|
|
474
|
-
*
|
|
475
|
-
* - Event validation
|
|
476
|
-
* - History replay
|
|
477
|
-
*
|
|
478
|
-
* Use this class when you want Event Sourcing with full event tracking
|
|
479
|
-
* and replay capabilities.
|
|
590
|
+
* Extends `Entity` directly (not `AggregateRoot`) so that `setState()` and
|
|
591
|
+
* `addDomainEvent()` are not available. This enforces the event sourcing pattern
|
|
592
|
+
* at the type level — there is no way to mutate state without going through an event handler.
|
|
480
593
|
*
|
|
481
594
|
* @template TState - The type of the aggregate state (contains child entities and value objects)
|
|
482
595
|
* @template TEvent - The union type of all domain events
|
|
@@ -484,8 +597,7 @@ interface AggregateEventSourcedConfig extends AggregateConfig {
|
|
|
484
597
|
*
|
|
485
598
|
* @example
|
|
486
599
|
* ```typescript
|
|
487
|
-
*
|
|
488
|
-
* class Order extends AggregateEventSourced<OrderState, OrderEvent, OrderId> {
|
|
600
|
+
* class Order extends EventSourcedAggregate<OrderState, OrderEvent, OrderId> {
|
|
489
601
|
* confirm(): void {
|
|
490
602
|
* this.apply(createDomainEvent("OrderConfirmed", {}));
|
|
491
603
|
* }
|
|
@@ -499,58 +611,32 @@ interface AggregateEventSourcedConfig extends AggregateConfig {
|
|
|
499
611
|
* }
|
|
500
612
|
* ```
|
|
501
613
|
*/
|
|
502
|
-
declare abstract class
|
|
503
|
-
private
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
*/
|
|
614
|
+
declare abstract class EventSourcedAggregate<TState, TEvent extends DomainEvent<string, unknown>, TId extends Id<string>> extends Entity<TState, TId> implements IEventSourcedAggregate<TId, TEvent> {
|
|
615
|
+
private _version;
|
|
616
|
+
get version(): Version;
|
|
617
|
+
private setVersion;
|
|
618
|
+
private _pendingEvents;
|
|
619
|
+
private readonly _autoVersionBump;
|
|
509
620
|
get pendingEvents(): ReadonlyArray<TEvent>;
|
|
510
|
-
/**
|
|
511
|
-
* Clears the list of pending events.
|
|
512
|
-
* Typically called after the events have been persisted.
|
|
513
|
-
*/
|
|
514
621
|
clearPendingEvents(): void;
|
|
622
|
+
protected constructor(id: TId, initialState: TState, config?: EventSourcedAggregateConfig);
|
|
515
623
|
/**
|
|
516
624
|
* Validates an event before it is applied.
|
|
517
625
|
* Override this method to add custom validation logic.
|
|
518
626
|
* Return `ok(true)` if the event is valid, `err(message)` otherwise.
|
|
519
|
-
*
|
|
520
|
-
* @param event - The event to validate
|
|
521
|
-
* @returns Result indicating if the event is valid
|
|
522
|
-
*
|
|
523
|
-
* @example
|
|
524
|
-
* ```typescript
|
|
525
|
-
* protected validateEvent(event: OrderEvent): Result<true, string> {
|
|
526
|
-
* if (event.type === "OrderShipped" && this.state.status !== "confirmed") {
|
|
527
|
-
* return err("Order must be confirmed before shipping");
|
|
528
|
-
* }
|
|
529
|
-
* return ok(true);
|
|
530
|
-
* }
|
|
531
|
-
* ```
|
|
532
627
|
*/
|
|
533
628
|
protected validateEvent(_event: TEvent): Result<true, string>;
|
|
534
629
|
/**
|
|
535
|
-
* Applies an event to change the state and adds it
|
|
536
|
-
* to the list of pending events.
|
|
630
|
+
* Applies an event to change the state and adds it to pending events.
|
|
537
631
|
* Returns a Result type instead of throwing an error.
|
|
538
632
|
*
|
|
539
633
|
* @param event - The domain event to apply
|
|
540
|
-
* @param isNew -
|
|
541
|
-
* or if it is being loaded from history
|
|
542
|
-
* @returns Result<void, string> - ok if successful, err with error message if validation fails or handler is missing
|
|
634
|
+
* @param isNew - Whether the event is new (needs persisting) or from history replay
|
|
543
635
|
*/
|
|
544
636
|
protected apply(event: TEvent, isNew?: boolean): Result<void, string>;
|
|
545
637
|
/**
|
|
546
|
-
* Applies an event to change the state and adds it
|
|
547
|
-
* to the list of pending events.
|
|
638
|
+
* Applies an event to change the state and adds it to pending events.
|
|
548
639
|
* Throws an error if validation fails or handler is missing.
|
|
549
|
-
*
|
|
550
|
-
* @param event - The domain event to apply
|
|
551
|
-
* @param isNew - Indicates whether the event is new (and needs to be persisted)
|
|
552
|
-
* or if it is being loaded from history
|
|
553
|
-
* @throws Error if event validation fails or handler is missing
|
|
554
640
|
*/
|
|
555
641
|
protected applyUnsafe(event: TEvent, isNew?: boolean): void;
|
|
556
642
|
/**
|
|
@@ -561,41 +647,17 @@ declare abstract class AggregateEventSourced<TState, TEvent extends DomainEvent<
|
|
|
561
647
|
/**
|
|
562
648
|
* Reconstitutes the aggregate from an event history.
|
|
563
649
|
* Sets the version to the number of events in the history.
|
|
564
|
-
*
|
|
565
|
-
* @param history - An ordered list of past events
|
|
566
650
|
*/
|
|
567
651
|
loadFromHistory(history: TEvent[]): Result<void, string>;
|
|
568
|
-
/**
|
|
569
|
-
* Checks if the aggregate has any pending events.
|
|
570
|
-
*
|
|
571
|
-
* @returns true if there are pending events, false otherwise
|
|
572
|
-
*/
|
|
573
652
|
hasPendingEvents(): boolean;
|
|
574
|
-
/**
|
|
575
|
-
* Returns the number of pending events.
|
|
576
|
-
*
|
|
577
|
-
* @returns The count of pending events
|
|
578
|
-
*/
|
|
579
653
|
getEventCount(): number;
|
|
654
|
+
getLatestEvent(): TEvent | undefined;
|
|
580
655
|
/**
|
|
581
|
-
*
|
|
582
|
-
*
|
|
583
|
-
* @returns The most recent event or undefined if no events exist
|
|
656
|
+
* Creates a snapshot of the current aggregate state.
|
|
584
657
|
*/
|
|
585
|
-
|
|
658
|
+
createSnapshot(): AggregateSnapshot<TState>;
|
|
586
659
|
/**
|
|
587
|
-
* Restores the aggregate from a snapshot and applies events that occurred after
|
|
588
|
-
* This is more efficient than replaying all events from the beginning.
|
|
589
|
-
*
|
|
590
|
-
* @param snapshot - The snapshot to restore from
|
|
591
|
-
* @param eventsAfterSnapshot - Events that occurred after the snapshot was taken
|
|
592
|
-
*
|
|
593
|
-
* @example
|
|
594
|
-
* ```typescript
|
|
595
|
-
* const snapshot = await snapshotRepository.getLatest(aggregateId);
|
|
596
|
-
* const eventsAfter = await eventStore.getEventsAfter(aggregateId, snapshot.version);
|
|
597
|
-
* aggregate.restoreFromSnapshotWithEvents(snapshot, eventsAfter);
|
|
598
|
-
* ```
|
|
660
|
+
* Restores the aggregate from a snapshot and applies events that occurred after.
|
|
599
661
|
*/
|
|
600
662
|
restoreFromSnapshotWithEvents(snapshot: AggregateSnapshot<TState>, eventsAfterSnapshot: TEvent[]): Result<void, string>;
|
|
601
663
|
/**
|
|
@@ -613,170 +675,32 @@ type Version = number & {
|
|
|
613
675
|
readonly __v: true;
|
|
614
676
|
};
|
|
615
677
|
/**
|
|
616
|
-
*
|
|
617
|
-
*
|
|
618
|
-
*/
|
|
619
|
-
interface EventMetadata {
|
|
620
|
-
/**
|
|
621
|
-
* Correlation ID for tracing events across multiple services/components.
|
|
622
|
-
* Typically used to group related events in a distributed system.
|
|
623
|
-
*/
|
|
624
|
-
correlationId?: string;
|
|
625
|
-
/**
|
|
626
|
-
* Causation ID referencing the event or command that caused this event.
|
|
627
|
-
* Used to build event chains and understand causality.
|
|
628
|
-
*/
|
|
629
|
-
causationId?: string;
|
|
630
|
-
/**
|
|
631
|
-
* User ID of the person or system that triggered the event.
|
|
632
|
-
*/
|
|
633
|
-
userId?: string;
|
|
634
|
-
/**
|
|
635
|
-
* Source service or component that produced the event.
|
|
636
|
-
*/
|
|
637
|
-
source?: string;
|
|
638
|
-
/**
|
|
639
|
-
* Additional custom metadata fields.
|
|
640
|
-
* Allows extensibility for domain-specific metadata.
|
|
641
|
-
*/
|
|
642
|
-
[key: string]: unknown;
|
|
643
|
-
}
|
|
644
|
-
/**
|
|
645
|
-
* Domain Event represents something meaningful that happened in the domain.
|
|
646
|
-
* Events are immutable and carry information about what occurred.
|
|
678
|
+
* Lightweight functional aggregate state — state + version, no event sourcing.
|
|
679
|
+
* This is a data projection, not a full Aggregate (which requires identity via IAggregateRoot).
|
|
647
680
|
*
|
|
648
|
-
*
|
|
649
|
-
*
|
|
650
|
-
*/
|
|
651
|
-
interface DomainEvent<T extends string, P = void> {
|
|
652
|
-
/**
|
|
653
|
-
* The type of the event, used for routing and handling.
|
|
654
|
-
*/
|
|
655
|
-
type: T;
|
|
656
|
-
/**
|
|
657
|
-
* The event payload containing the domain data.
|
|
658
|
-
* Omitted when P is void (events without payload).
|
|
659
|
-
*/
|
|
660
|
-
payload: P;
|
|
661
|
-
/**
|
|
662
|
-
* Timestamp when the event occurred.
|
|
663
|
-
*/
|
|
664
|
-
occurredAt: Date;
|
|
665
|
-
/**
|
|
666
|
-
* Event schema version for handling schema evolution.
|
|
667
|
-
* Defaults to 1 if not specified. Higher versions indicate schema changes.
|
|
668
|
-
*/
|
|
669
|
-
version?: number;
|
|
670
|
-
/**
|
|
671
|
-
* Optional metadata for traceability, correlation, and auditing.
|
|
672
|
-
* Includes correlationId, causationId, userId, source, and custom fields.
|
|
673
|
-
*/
|
|
674
|
-
metadata?: EventMetadata;
|
|
675
|
-
}
|
|
676
|
-
|
|
677
|
-
/**
|
|
678
|
-
* Structural interface representing an aggregate with state and events.
|
|
679
|
-
* Used for type constraints in repositories and other infrastructure code.
|
|
681
|
+
* For event sourcing, use the class-based `EventSourcedAggregate` which enforces
|
|
682
|
+
* that state changes happen through event handlers.
|
|
680
683
|
*
|
|
681
684
|
* @template State - The type of the aggregate state
|
|
682
|
-
* @template Evt - The union type of all domain events
|
|
683
685
|
*/
|
|
684
|
-
interface
|
|
686
|
+
interface AggregateState<State> {
|
|
685
687
|
state: Readonly<State>;
|
|
686
688
|
version: Version;
|
|
687
|
-
pendingEvents: ReadonlyArray<Evt>;
|
|
688
689
|
}
|
|
689
|
-
declare function aggregate<State, Evt extends DomainEvent<string, unknown>>(state: State, version?: Version): Aggregate<State, Evt>;
|
|
690
|
-
declare function withEvent<S, E extends DomainEvent<string, unknown>>(agg: Aggregate<S, E>, evt: E): Aggregate<S, E>;
|
|
691
|
-
declare function bump<S, E extends DomainEvent<string, unknown>>(agg: Aggregate<S, E>): Aggregate<S, E>;
|
|
692
|
-
/**
|
|
693
|
-
* Creates a domain event with default values.
|
|
694
|
-
* Sets occurredAt to current date and version to 1 if not provided.
|
|
695
|
-
*
|
|
696
|
-
* @param type - The event type
|
|
697
|
-
* @param payload - The event payload
|
|
698
|
-
* @param options - Optional event configuration
|
|
699
|
-
* @returns A domain event
|
|
700
|
-
*
|
|
701
|
-
* @example
|
|
702
|
-
* ```typescript
|
|
703
|
-
* const event = createDomainEvent("OrderCreated", { orderId: "123" });
|
|
704
|
-
* ```
|
|
705
|
-
*/
|
|
706
|
-
declare function createDomainEvent<T extends string>(type: T, payload?: undefined, options?: {
|
|
707
|
-
occurredAt?: Date;
|
|
708
|
-
version?: number;
|
|
709
|
-
metadata?: EventMetadata;
|
|
710
|
-
}): DomainEvent<T, void>;
|
|
711
|
-
declare function createDomainEvent<T extends string, P>(type: T, payload: P, options?: {
|
|
712
|
-
occurredAt?: Date;
|
|
713
|
-
version?: number;
|
|
714
|
-
metadata?: EventMetadata;
|
|
715
|
-
}): DomainEvent<T, P>;
|
|
716
|
-
/**
|
|
717
|
-
* Creates a domain event with metadata for traceability.
|
|
718
|
-
* Convenience function for creating events with correlation and causation IDs.
|
|
719
|
-
*
|
|
720
|
-
* @param type - The event type
|
|
721
|
-
* @param payload - The event payload
|
|
722
|
-
* @param metadata - Event metadata for traceability
|
|
723
|
-
* @param options - Optional event configuration
|
|
724
|
-
* @returns A domain event with metadata
|
|
725
|
-
*
|
|
726
|
-
* @example
|
|
727
|
-
* ```typescript
|
|
728
|
-
* const event = createDomainEventWithMetadata(
|
|
729
|
-
* "OrderCreated",
|
|
730
|
-
* { orderId: "123" },
|
|
731
|
-
* {
|
|
732
|
-
* correlationId: "corr-123",
|
|
733
|
-
* causationId: "cmd-456",
|
|
734
|
-
* userId: "user-789"
|
|
735
|
-
* }
|
|
736
|
-
* );
|
|
737
|
-
* ```
|
|
738
|
-
*/
|
|
739
|
-
declare function createDomainEventWithMetadata<T extends string, P>(type: T, payload: P, metadata: EventMetadata, options?: {
|
|
740
|
-
occurredAt?: Date;
|
|
741
|
-
version?: number;
|
|
742
|
-
}): DomainEvent<T, P>;
|
|
743
690
|
/**
|
|
744
|
-
*
|
|
745
|
-
* Useful for maintaining correlation chains in event-driven architectures.
|
|
746
|
-
*
|
|
747
|
-
* @param sourceEvent - The source event to copy metadata from
|
|
748
|
-
* @param additionalMetadata - Additional metadata to merge in
|
|
749
|
-
* @returns Event metadata with copied and merged values
|
|
691
|
+
* Creates a lightweight functional aggregate state.
|
|
750
692
|
*
|
|
751
693
|
* @example
|
|
752
694
|
* ```typescript
|
|
753
|
-
* const
|
|
754
|
-
* "OrderShipped",
|
|
755
|
-
* { orderId: "123" },
|
|
756
|
-
* {
|
|
757
|
-
* metadata: copyMetadata(previousEvent, { causationId: previousEvent.type })
|
|
758
|
-
* }
|
|
759
|
-
* );
|
|
695
|
+
* const order = aggregate<OrderState>({ status: "draft", items: [] });
|
|
760
696
|
* ```
|
|
761
697
|
*/
|
|
762
|
-
declare function
|
|
698
|
+
declare function aggregate<State>(state: State, version?: Version): AggregateState<State>;
|
|
763
699
|
/**
|
|
764
|
-
*
|
|
765
|
-
*
|
|
766
|
-
*
|
|
767
|
-
* @param metadataObjects - Array of metadata objects to merge
|
|
768
|
-
* @returns Merged event metadata
|
|
769
|
-
*
|
|
770
|
-
* @example
|
|
771
|
-
* ```typescript
|
|
772
|
-
* const metadata = mergeMetadata(
|
|
773
|
-
* { correlationId: "corr-123" },
|
|
774
|
-
* { userId: "user-456" },
|
|
775
|
-
* { source: "order-service" }
|
|
776
|
-
* );
|
|
777
|
-
* ```
|
|
700
|
+
* Bumps the version of a functional aggregate state.
|
|
701
|
+
* Returns a new aggregate state with incremented version.
|
|
778
702
|
*/
|
|
779
|
-
declare function
|
|
703
|
+
declare function bump<S>(agg: AggregateState<S>): AggregateState<S>;
|
|
780
704
|
/**
|
|
781
705
|
* Snapshot of an aggregate state at a specific point in time.
|
|
782
706
|
* Used for optimizing event replay by starting from a snapshot
|
|
@@ -799,25 +723,24 @@ interface AggregateSnapshot<TState> {
|
|
|
799
723
|
snapshotAt: Date;
|
|
800
724
|
}
|
|
801
725
|
/**
|
|
802
|
-
* Checks if two aggregates are the same (same ID and version).
|
|
726
|
+
* Checks if two aggregates are at the same version (same ID and version).
|
|
803
727
|
* Useful for optimistic concurrency control checks.
|
|
804
728
|
*
|
|
805
|
-
*
|
|
806
|
-
*
|
|
807
|
-
* @returns true if both aggregates have the same ID and version
|
|
729
|
+
* Note: Two aggregates with the same ID ARE the same aggregate (identity).
|
|
730
|
+
* This function checks if they are at the same version — i.e., no concurrent modification.
|
|
808
731
|
*
|
|
809
732
|
* @example
|
|
810
733
|
* ```typescript
|
|
811
|
-
* const
|
|
734
|
+
* const before = await repository.getById(id);
|
|
812
735
|
* // ... some operations ...
|
|
813
|
-
* const
|
|
736
|
+
* const after = await repository.getById(id);
|
|
814
737
|
*
|
|
815
|
-
* if (!
|
|
738
|
+
* if (!sameVersion(before, after)) {
|
|
816
739
|
* throw new Error("Aggregate was modified by another process");
|
|
817
740
|
* }
|
|
818
741
|
* ```
|
|
819
742
|
*/
|
|
820
|
-
declare function
|
|
743
|
+
declare function sameVersion<TId extends Id<string>>(a: {
|
|
821
744
|
id: TId;
|
|
822
745
|
version: Version;
|
|
823
746
|
}, b: {
|
|
@@ -913,29 +836,58 @@ interface Command {
|
|
|
913
836
|
*/
|
|
914
837
|
type CommandHandler<C extends Command, R> = (cmd: C) => Promise<Result<R, string>>;
|
|
915
838
|
|
|
839
|
+
/**
|
|
840
|
+
* Type map for command types to their return types.
|
|
841
|
+
* Used to improve type inference in CommandBus.
|
|
842
|
+
*
|
|
843
|
+
* @example
|
|
844
|
+
* ```typescript
|
|
845
|
+
* type MyCommandMap = {
|
|
846
|
+
* CreateOrder: OrderId;
|
|
847
|
+
* CancelOrder: void;
|
|
848
|
+
* };
|
|
849
|
+
*
|
|
850
|
+
* const bus = new CommandBus<MyCommandMap>();
|
|
851
|
+
* const result = await bus.execute({ type: "CreateOrder", ... });
|
|
852
|
+
* // result: Result<OrderId, string> ← automatically inferred
|
|
853
|
+
* ```
|
|
854
|
+
*/
|
|
855
|
+
type CommandTypeMap = Record<string, unknown>;
|
|
916
856
|
/**
|
|
917
857
|
* Command Bus interface for dispatching commands to their handlers.
|
|
918
858
|
* Provides a centralized way to execute commands with handler registration.
|
|
919
859
|
*
|
|
860
|
+
* Supports an optional type map (`TMap`) for automatic return type inference.
|
|
861
|
+
* Without a type map, the return type must be specified manually or defaults to `unknown`.
|
|
862
|
+
*
|
|
863
|
+
* @template TMap - Optional mapping from command type strings to return types
|
|
864
|
+
*
|
|
920
865
|
* @example
|
|
921
866
|
* ```typescript
|
|
867
|
+
* // With type map (recommended) – return type is inferred
|
|
868
|
+
* type MyCommands = { CreateOrder: OrderId; CancelOrder: void };
|
|
869
|
+
* const bus = new CommandBus<MyCommands>();
|
|
870
|
+
* const result = await bus.execute({ type: "CreateOrder", ... });
|
|
871
|
+
* // result: Result<OrderId, string>
|
|
872
|
+
*
|
|
873
|
+
* // Without type map – works like before
|
|
922
874
|
* const bus = new CommandBus();
|
|
923
875
|
* bus.register("CreateOrder", createOrderHandler);
|
|
924
|
-
*
|
|
925
|
-
*
|
|
926
|
-
* type: "CreateOrder",
|
|
927
|
-
* customerId: "123",
|
|
928
|
-
* items: [...]
|
|
929
|
-
* });
|
|
876
|
+
* const result = await bus.execute({ type: "CreateOrder", ... });
|
|
877
|
+
* // result: Result<unknown, string>
|
|
930
878
|
* ```
|
|
931
879
|
*/
|
|
932
|
-
interface ICommandBus {
|
|
880
|
+
interface ICommandBus<TMap extends CommandTypeMap = CommandTypeMap> {
|
|
933
881
|
/**
|
|
934
882
|
* Executes a command by dispatching it to the registered handler.
|
|
883
|
+
* When a type map is provided, the return type is inferred from the command type.
|
|
935
884
|
*
|
|
936
885
|
* @param command - The command to execute
|
|
937
886
|
* @returns Result containing the success value or error message
|
|
938
887
|
*/
|
|
888
|
+
execute<C extends Command & {
|
|
889
|
+
type: keyof TMap & string;
|
|
890
|
+
}>(command: C): Promise<Result<TMap[C["type"]], string>>;
|
|
939
891
|
execute<C extends Command, R>(command: C): Promise<Result<R, string>>;
|
|
940
892
|
/**
|
|
941
893
|
* Registers a handler for a specific command type.
|
|
@@ -949,6 +901,10 @@ interface ICommandBus {
|
|
|
949
901
|
* Simple in-memory command bus implementation.
|
|
950
902
|
* Handlers are stored in a Map and dispatched based on command type.
|
|
951
903
|
*
|
|
904
|
+
* Supports an optional type map (`TMap`) for automatic return type inference.
|
|
905
|
+
* When `TMap` is provided, `execute()` infers the result type from the command type.
|
|
906
|
+
* Without `TMap`, it works like before (return type defaults to `unknown` or can be specified manually).
|
|
907
|
+
*
|
|
952
908
|
* **Note:** This is a basic implementation suitable for development and simple use cases.
|
|
953
909
|
* For production environments, consider implementing or using a more feature-rich bus that includes:
|
|
954
910
|
* - Middleware/Pipeline support (logging, validation, authorization)
|
|
@@ -961,20 +917,28 @@ interface ICommandBus {
|
|
|
961
917
|
* The `CommandHandler` type can still be used with external production-grade buses
|
|
962
918
|
* (e.g., RabbitMQ, AWS SQS) while maintaining type safety.
|
|
963
919
|
*
|
|
920
|
+
* @template TMap - Optional mapping from command type strings to return types
|
|
921
|
+
*
|
|
964
922
|
* @example
|
|
965
923
|
* ```typescript
|
|
966
|
-
*
|
|
967
|
-
*
|
|
968
|
-
*
|
|
969
|
-
*
|
|
970
|
-
*
|
|
924
|
+
* // With type map – full inference
|
|
925
|
+
* type Commands = { CreateOrder: OrderId; CancelOrder: void };
|
|
926
|
+
* const bus = new CommandBus<Commands>();
|
|
927
|
+
* const result = await bus.execute({ type: "CreateOrder", ... });
|
|
928
|
+
* // result: Result<OrderId, string>
|
|
971
929
|
*
|
|
930
|
+
* // Without type map – same as before
|
|
931
|
+
* const bus = new CommandBus();
|
|
932
|
+
* bus.register("CreateOrder", async (cmd) => ok(orderId));
|
|
972
933
|
* const result = await bus.execute({ type: "CreateOrder", ... });
|
|
973
934
|
* ```
|
|
974
935
|
*/
|
|
975
|
-
declare class CommandBus implements ICommandBus {
|
|
936
|
+
declare class CommandBus<TMap extends CommandTypeMap = CommandTypeMap> implements ICommandBus<TMap> {
|
|
976
937
|
private readonly handlers;
|
|
977
938
|
register<C extends Command, R>(commandType: C["type"], handler: CommandHandler<C, R>): void;
|
|
939
|
+
execute<C extends Command & {
|
|
940
|
+
type: keyof TMap & string;
|
|
941
|
+
}>(command: C): Promise<Result<TMap[C["type"]], string>>;
|
|
978
942
|
execute<C extends Command, R>(command: C): Promise<Result<R, string>>;
|
|
979
943
|
}
|
|
980
944
|
|
|
@@ -1007,7 +971,9 @@ type EventHandler<Evt> = (event: Evt) => Promise<void> | void;
|
|
|
1007
971
|
* await bus.publish([orderCreatedEvent, orderShippedEvent]);
|
|
1008
972
|
* ```
|
|
1009
973
|
*/
|
|
1010
|
-
interface EventBus<Evt
|
|
974
|
+
interface EventBus<Evt extends {
|
|
975
|
+
type: string;
|
|
976
|
+
}> {
|
|
1011
977
|
/**
|
|
1012
978
|
* Publishes events to all subscribed handlers.
|
|
1013
979
|
* All handlers for each event type will be called.
|
|
@@ -1033,7 +999,7 @@ interface EventBus<Evt> {
|
|
|
1033
999
|
* unsubscribe();
|
|
1034
1000
|
* ```
|
|
1035
1001
|
*/
|
|
1036
|
-
subscribe: <T extends Evt>(eventType:
|
|
1002
|
+
subscribe: <T extends Evt>(eventType: Evt["type"], handler: EventHandler<T>) => () => void;
|
|
1037
1003
|
/**
|
|
1038
1004
|
* Subscribes to the next occurrence of an event type.
|
|
1039
1005
|
* Returns a Promise that resolves with the event data.
|
|
@@ -1048,14 +1014,11 @@ interface EventBus<Evt> {
|
|
|
1048
1014
|
* console.log("Order created:", event.payload.orderId);
|
|
1049
1015
|
* ```
|
|
1050
1016
|
*/
|
|
1051
|
-
once: <T extends Evt>(eventType:
|
|
1017
|
+
once: <T extends Evt>(eventType: Evt["type"]) => Promise<T>;
|
|
1052
1018
|
}
|
|
1053
1019
|
interface Outbox<Evt> {
|
|
1054
1020
|
add: (events: ReadonlyArray<Evt>) => Promise<void>;
|
|
1055
1021
|
}
|
|
1056
|
-
interface Clock {
|
|
1057
|
-
now: () => Date;
|
|
1058
|
-
}
|
|
1059
1022
|
|
|
1060
1023
|
interface UnitOfWork {
|
|
1061
1024
|
transactional<T>(fn: () => Promise<T>): Promise<T>;
|
|
@@ -1085,7 +1048,9 @@ type RepoProvider<R> = (uow: UnitOfWork) => R;
|
|
|
1085
1048
|
* );
|
|
1086
1049
|
* ```
|
|
1087
1050
|
*/
|
|
1088
|
-
declare function withCommit<Evt
|
|
1051
|
+
declare function withCommit<Evt extends {
|
|
1052
|
+
type: string;
|
|
1053
|
+
}, R>(deps: {
|
|
1089
1054
|
outbox: Outbox<Evt>;
|
|
1090
1055
|
bus?: EventBus<Evt>;
|
|
1091
1056
|
uow: UnitOfWork;
|
|
@@ -1169,29 +1134,57 @@ interface Query {
|
|
|
1169
1134
|
*/
|
|
1170
1135
|
type QueryHandler<Q extends Query, R> = (query: Q) => Promise<R>;
|
|
1171
1136
|
|
|
1137
|
+
/**
|
|
1138
|
+
* Type map for query types to their return types.
|
|
1139
|
+
* Used to improve type inference in QueryBus.
|
|
1140
|
+
*
|
|
1141
|
+
* @example
|
|
1142
|
+
* ```typescript
|
|
1143
|
+
* type MyQueryMap = {
|
|
1144
|
+
* GetOrder: Order | null;
|
|
1145
|
+
* ListOrders: Order[];
|
|
1146
|
+
* };
|
|
1147
|
+
*
|
|
1148
|
+
* const bus = new QueryBus<MyQueryMap>();
|
|
1149
|
+
* const result = await bus.execute({ type: "GetOrder", orderId: "123" });
|
|
1150
|
+
* // result: Result<Order | null, string> ← automatically inferred
|
|
1151
|
+
* ```
|
|
1152
|
+
*/
|
|
1153
|
+
type QueryTypeMap = Record<string, unknown>;
|
|
1172
1154
|
/**
|
|
1173
1155
|
* Query Bus interface for dispatching queries to their handlers.
|
|
1174
1156
|
* Provides a centralized way to execute queries with handler registration.
|
|
1175
1157
|
*
|
|
1158
|
+
* Supports an optional type map (`TMap`) for automatic return type inference.
|
|
1159
|
+
* Without a type map, the return type must be specified manually or defaults to `unknown`.
|
|
1160
|
+
*
|
|
1161
|
+
* @template TMap - Optional mapping from query type strings to return types
|
|
1162
|
+
*
|
|
1176
1163
|
* @example
|
|
1177
1164
|
* ```typescript
|
|
1178
|
-
*
|
|
1179
|
-
*
|
|
1165
|
+
* // With type map (recommended) – return type is inferred
|
|
1166
|
+
* type MyQueries = { GetOrder: Order | null; ListOrders: Order[] };
|
|
1167
|
+
* const bus = new QueryBus<MyQueries>();
|
|
1168
|
+
* const result = await bus.execute({ type: "GetOrder", orderId: "123" });
|
|
1169
|
+
* // result: Result<Order | null, string>
|
|
1180
1170
|
*
|
|
1181
|
-
*
|
|
1182
|
-
*
|
|
1183
|
-
*
|
|
1184
|
-
*
|
|
1171
|
+
* // Without type map – works like before
|
|
1172
|
+
* const bus = new QueryBus();
|
|
1173
|
+
* const result = await bus.execute({ type: "GetOrder", orderId: "123" });
|
|
1174
|
+
* // result: Result<unknown, string>
|
|
1185
1175
|
* ```
|
|
1186
1176
|
*/
|
|
1187
|
-
interface IQueryBus {
|
|
1177
|
+
interface IQueryBus<TMap extends QueryTypeMap = QueryTypeMap> {
|
|
1188
1178
|
/**
|
|
1189
1179
|
* Executes a query by dispatching it to the registered handler.
|
|
1190
|
-
*
|
|
1180
|
+
* When a type map is provided, the return type is inferred from the query type.
|
|
1191
1181
|
*
|
|
1192
1182
|
* @param query - The query to execute
|
|
1193
|
-
* @returns Result containing the query result if successful, or an error message
|
|
1183
|
+
* @returns Result containing the query result if successful, or an error message
|
|
1194
1184
|
*/
|
|
1185
|
+
execute<Q extends Query & {
|
|
1186
|
+
type: keyof TMap & string;
|
|
1187
|
+
}>(query: Q): Promise<Result<TMap[Q["type"]], string>>;
|
|
1195
1188
|
execute<Q extends Query, R>(query: Q): Promise<Result<R, string>>;
|
|
1196
1189
|
/**
|
|
1197
1190
|
* Executes a query by dispatching it to the registered handler.
|
|
@@ -1201,6 +1194,9 @@ interface IQueryBus {
|
|
|
1201
1194
|
* @returns The query result
|
|
1202
1195
|
* @throws Error if no handler is registered for the query type
|
|
1203
1196
|
*/
|
|
1197
|
+
executeUnsafe<Q extends Query & {
|
|
1198
|
+
type: keyof TMap & string;
|
|
1199
|
+
}>(query: Q): Promise<TMap[Q["type"]]>;
|
|
1204
1200
|
executeUnsafe<Q extends Query, R>(query: Q): Promise<R>;
|
|
1205
1201
|
/**
|
|
1206
1202
|
* Registers a handler for a specific query type.
|
|
@@ -1210,15 +1206,14 @@ interface IQueryBus {
|
|
|
1210
1206
|
*/
|
|
1211
1207
|
register<Q extends Query, R>(queryType: Q["type"], handler: QueryHandler<Q, R>): void;
|
|
1212
1208
|
}
|
|
1213
|
-
/**
|
|
1214
|
-
* Type map for query types to their return types.
|
|
1215
|
-
* Used to improve type inference in QueryBus.
|
|
1216
|
-
*/
|
|
1217
|
-
type QueryTypeMap = Record<string, unknown>;
|
|
1218
1209
|
/**
|
|
1219
1210
|
* Simple in-memory query bus implementation.
|
|
1220
1211
|
* Handlers are stored in a Map and dispatched based on query type.
|
|
1221
1212
|
*
|
|
1213
|
+
* Supports an optional type map (`TMap`) for automatic return type inference.
|
|
1214
|
+
* When `TMap` is provided, `execute()` and `executeUnsafe()` infer the result type from the query type.
|
|
1215
|
+
* Without `TMap`, it works like before (return type defaults to `unknown` or can be specified manually).
|
|
1216
|
+
*
|
|
1222
1217
|
* **Note:** This is a basic implementation suitable for development and simple use cases.
|
|
1223
1218
|
* For production environments, consider implementing or using a more feature-rich bus that includes:
|
|
1224
1219
|
* - Middleware/Pipeline support (logging, caching, rate limiting)
|
|
@@ -1231,23 +1226,32 @@ type QueryTypeMap = Record<string, unknown>;
|
|
|
1231
1226
|
* The `QueryHandler` type can still be used with external production-grade buses
|
|
1232
1227
|
* (e.g., RabbitMQ, AWS SQS) while maintaining type safety.
|
|
1233
1228
|
*
|
|
1229
|
+
* @template TMap - Optional mapping from query type strings to return types
|
|
1230
|
+
*
|
|
1234
1231
|
* @example
|
|
1235
1232
|
* ```typescript
|
|
1236
|
-
*
|
|
1237
|
-
*
|
|
1238
|
-
*
|
|
1239
|
-
* });
|
|
1233
|
+
* // With type map – full inference
|
|
1234
|
+
* type Queries = { GetOrder: Order | null; ListOrders: Order[] };
|
|
1235
|
+
* const bus = new QueryBus<Queries>();
|
|
1236
|
+
* const result = await bus.execute({ type: "GetOrder", orderId: "123" });
|
|
1237
|
+
* // result: Result<Order | null, string>
|
|
1240
1238
|
*
|
|
1241
|
-
*
|
|
1239
|
+
* // Without type map – same as before
|
|
1240
|
+
* const bus = new QueryBus();
|
|
1241
|
+
* bus.register("GetOrder", async (query) => repository.getById(query.orderId));
|
|
1242
|
+
* const result = await bus.execute({ type: "GetOrder", orderId: "123" });
|
|
1242
1243
|
* ```
|
|
1243
1244
|
*/
|
|
1244
|
-
declare class QueryBus<TMap extends QueryTypeMap = QueryTypeMap> implements IQueryBus {
|
|
1245
|
+
declare class QueryBus<TMap extends QueryTypeMap = QueryTypeMap> implements IQueryBus<TMap> {
|
|
1245
1246
|
private readonly handlers;
|
|
1246
1247
|
register<Q extends Query, R>(queryType: Q["type"], handler: QueryHandler<Q, R>): void;
|
|
1247
1248
|
execute<Q extends Query & {
|
|
1248
|
-
type: keyof TMap;
|
|
1249
|
+
type: keyof TMap & string;
|
|
1249
1250
|
}>(query: Q): Promise<Result<TMap[Q["type"]], string>>;
|
|
1250
1251
|
execute<Q extends Query, R>(query: Q): Promise<Result<R, string>>;
|
|
1252
|
+
executeUnsafe<Q extends Query & {
|
|
1253
|
+
type: keyof TMap & string;
|
|
1254
|
+
}>(query: Q): Promise<TMap[Q["type"]]>;
|
|
1251
1255
|
executeUnsafe<Q extends Query, R>(query: Q): Promise<R>;
|
|
1252
1256
|
}
|
|
1253
1257
|
|
|
@@ -1293,17 +1297,21 @@ declare function guard(cond: boolean, error: string): Result<true, string>;
|
|
|
1293
1297
|
*/
|
|
1294
1298
|
declare class EventBusImpl<Evt extends DomainEvent<string, unknown>> implements EventBus<Evt> {
|
|
1295
1299
|
private readonly handlers;
|
|
1296
|
-
subscribe<T extends Evt>(eventType:
|
|
1297
|
-
once<T extends Evt>(eventType:
|
|
1300
|
+
subscribe<T extends Evt>(eventType: Evt["type"], handler: EventHandler<T>): () => void;
|
|
1301
|
+
once<T extends Evt>(eventType: Evt["type"]): Promise<T>;
|
|
1298
1302
|
publish(events: ReadonlyArray<Evt>): Promise<void>;
|
|
1299
1303
|
}
|
|
1300
1304
|
|
|
1305
|
+
declare const __specBrand: unique symbol;
|
|
1301
1306
|
/**
|
|
1302
1307
|
* A Specification is a named, standalone object that represents a business rule for a query.
|
|
1303
1308
|
* It is "translatable" into a concrete database query.
|
|
1309
|
+
*
|
|
1310
|
+
* Uses a branded type to carry the generic parameter without requiring
|
|
1311
|
+
* implementors to add a runtime field.
|
|
1304
1312
|
*/
|
|
1305
1313
|
interface ISpecification<T> {
|
|
1306
|
-
readonly
|
|
1314
|
+
readonly [__specBrand]?: T;
|
|
1307
1315
|
}
|
|
1308
1316
|
|
|
1309
1317
|
/**
|
|
@@ -1320,12 +1328,10 @@ interface ISpecification<T> {
|
|
|
1320
1328
|
* Child entities cannot be loaded or saved independently - they exist only
|
|
1321
1329
|
* within the aggregate boundary and are managed through the Aggregate Root.
|
|
1322
1330
|
*
|
|
1323
|
-
* @template
|
|
1324
|
-
* @template TEvent - The union type of all domain events
|
|
1325
|
-
* @template TAgg - The aggregate root type (must be an Aggregate Root Entity)
|
|
1331
|
+
* @template TAgg - The aggregate root type (must implement IAggregateRoot)
|
|
1326
1332
|
* @template TId - The type of the aggregate root identifier
|
|
1327
1333
|
*/
|
|
1328
|
-
interface IRepository<
|
|
1334
|
+
interface IRepository<TAgg extends IAggregateRoot<TId>, TId extends Id<string>> {
|
|
1329
1335
|
getById(id: TId): Promise<TAgg | null>;
|
|
1330
1336
|
findOne(spec: ISpecification<TAgg>): Promise<TAgg | null>;
|
|
1331
1337
|
find(spec: ISpecification<TAgg>): Promise<TAgg[]>;
|
|
@@ -1564,4 +1570,4 @@ declare abstract class ValueObject<T extends object> implements IValueObject<T>
|
|
|
1564
1570
|
toJSON(): Readonly<T>;
|
|
1565
1571
|
}
|
|
1566
1572
|
|
|
1567
|
-
export { type
|
|
1573
|
+
export { type AggregateConfig, AggregateRoot, type AggregateSnapshot, type AggregateState, type Command, CommandBus, type CommandHandler, type DomainEvent, Entity, type EventBus, EventBusImpl, type EventHandler, type EventMetadata, EventSourcedAggregate, type EventSourcedAggregateConfig, type IAggregateRoot, type ICommandBus, type IEntity, type IEventSourcedAggregate, type IQueryBus, type IRepository, type ISpecification, type IValueObject, type Id, type IdGenerator, type Identifiable, type Outbox, type Query, QueryBus, type QueryHandler, type RepoProvider, type UnitOfWork, type VO, ValueObject, type Version, aggregate, bump, copyMetadata, createDomainEvent, createDomainEventWithMetadata, deepFreeze, entityIds, findEntityById, guard, hasEntityId, mergeMetadata, removeEntityById, replaceEntityById, sameEntity, sameVersion, updateEntityById, vo, voEquals, voEqualsExcept, voWithValidation, voWithValidationUnsafe, withCommit };
|