@shirudo/ddd-kit 0.9.1 → 0.9.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -70,30 +70,40 @@ interface DomainEvent<T extends string, P> {
70
70
  }
71
71
  /**
72
72
  * Marker interface for Aggregate Roots.
73
- * Aggregate Roots are the entry points for modifying aggregates in DDD.
74
- * They have identity (id) and version for optimistic concurrency control.
75
73
  *
76
- * In Domain-Driven Design, an Aggregate Root is the only entity that external
77
- * objects are allowed to hold references to. All access to entities within the
78
- * aggregate must go through the Aggregate Root.
74
+ * In Domain-Driven Design, an Aggregate Root is an Entity (the parent Entity of the aggregate).
75
+ * It represents the aggregate externally and is the only object that external code
76
+ * is allowed to hold references to. All access to child entities within the aggregate
77
+ * must go through the Aggregate Root.
79
78
  *
80
- * @template TId - The type of the aggregate identifier
79
+ * An Aggregate consists of:
80
+ * - One Aggregate Root (Entity with id + version)
81
+ * - Optional child entities (Entities with id, but no own version)
82
+ * - Optional value objects
83
+ *
84
+ * The Aggregate Root has identity (id) and version for optimistic concurrency control.
85
+ * Child entities exist only within the aggregate boundary and are versioned through
86
+ * the Aggregate Root.
87
+ *
88
+ * @template TId - The type of the aggregate root identifier
81
89
  *
82
90
  * @example
83
91
  * ```typescript
84
92
  * class Order extends AggregateBase<OrderState, OrderId> implements AggregateRoot<OrderId> {
85
- * // Order is an Aggregate Root
93
+ * // Order is an Aggregate Root (an Entity)
94
+ * // OrderState contains child entities (e.g., OrderItem) and value objects
86
95
  * }
87
96
  * ```
88
97
  */
89
98
  interface AggregateRoot<TId extends Id<string>> {
90
99
  /**
91
- * Unique identifier of the aggregate root.
100
+ * Unique identifier of the aggregate root entity.
92
101
  */
93
102
  readonly id: TId;
94
103
  /**
95
104
  * Version number for optimistic concurrency control.
96
105
  * Incremented on each state change to detect concurrent modifications.
106
+ * This version applies to the entire aggregate, including all child entities.
97
107
  */
98
108
  readonly version: Version;
99
109
  }
@@ -254,23 +264,35 @@ interface AggregateConfig {
254
264
  autoVersionBump?: boolean;
255
265
  }
256
266
  /**
257
- * Base class for Aggregates without Event Sourcing.
258
- * Provides core functionality for aggregates:
267
+ * Base class for creating Aggregate Roots (Entities) without Event Sourcing.
268
+ *
269
+ * This class creates an Entity that serves as the Aggregate Root. The Aggregate Root
270
+ * is the parent Entity of the aggregate and represents it externally. It has identity
271
+ * (id) and version for optimistic concurrency control.
272
+ *
273
+ * The aggregate state (`TState`) contains:
274
+ * - Child entities (Entities with id, but no own version)
275
+ * - Value objects (immutable objects)
276
+ *
277
+ * All changes to child entities are versioned through the Aggregate Root. The version
278
+ * applies to the entire aggregate, including all child entities.
279
+ *
280
+ * Provides core functionality:
259
281
  * - ID and Version management (for Optimistic Concurrency Control)
260
- * - State management
282
+ * - State management (containing child entities and value objects)
261
283
  * - Snapshot support for performance optimization
262
284
  *
263
- * Implements `AggregateRoot<TId>` to explicitly mark this as an Aggregate Root
264
- * in Domain-Driven Design terms.
285
+ * Implements `AggregateRoot<TId>` to mark this as an Aggregate Root Entity.
265
286
  *
266
287
  * Use this class when you don't need Event Sourcing but still want
267
288
  * aggregate patterns with versioning and state management.
268
289
  *
269
- * @template TState - The type of the aggregate state
270
- * @template TId - The type of the aggregate identifier
290
+ * @template TState - The type of the aggregate state (contains child entities and value objects)
291
+ * @template TId - The type of the aggregate root identifier
271
292
  *
272
293
  * @example
273
294
  * ```typescript
295
+ * // Order is an Aggregate Root (an Entity)
274
296
  * class Order extends AggregateBase<OrderState, OrderId> implements AggregateRoot<OrderId> {
275
297
  * constructor(id: OrderId, initialState: OrderState) {
276
298
  * super(id, initialState);
@@ -278,7 +300,7 @@ interface AggregateConfig {
278
300
  *
279
301
  * confirm(): void {
280
302
  * this._state = { ...this._state, status: "confirmed" };
281
- * this.bumpVersion();
303
+ * this.bumpVersion(); // Versions the entire aggregate
282
304
  * }
283
305
  * }
284
306
  * ```
@@ -433,6 +455,343 @@ declare function isOk<T, E>(result: Result<T, E>): result is Ok<T>;
433
455
  * ```
434
456
  */
435
457
  declare function isErr<T, E>(result: Result<T, E>): result is Err<E>;
458
+ /**
459
+ * Chains Result operations (flatMap/bind).
460
+ * If the result is Ok, applies the function to the value.
461
+ * If Err, returns the error unchanged.
462
+ *
463
+ * @param result - The result to chain
464
+ * @param fn - Function that takes the Ok value and returns a new Result
465
+ * @returns A new Result
466
+ *
467
+ * @example
468
+ * ```typescript
469
+ * const result = validateUserId("123")
470
+ * .andThen(userId => validateEmail("test@example.com")
471
+ * .map(email => ({ id: userId, email }))
472
+ * );
473
+ * ```
474
+ */
475
+ declare function andThen<T, E, U>(result: Result<T, E>, fn: (value: T) => Result<U, E>): Result<U, E>;
476
+ /**
477
+ * Transforms the Ok value using a function.
478
+ * If the result is Err, returns the error unchanged.
479
+ *
480
+ * @param result - The result to transform
481
+ * @param fn - Function to transform the Ok value
482
+ * @returns A new Result with transformed value
483
+ *
484
+ * @example
485
+ * ```typescript
486
+ * const result = ok(5);
487
+ * const doubled = map(result, x => x * 2); // Ok<10>
488
+ * ```
489
+ */
490
+ declare function map<T, E, U>(result: Result<T, E>, fn: (value: T) => U): Result<U, E>;
491
+ /**
492
+ * Transforms the Err value using a function.
493
+ * If the result is Ok, returns the value unchanged.
494
+ *
495
+ * @param result - The result to transform
496
+ * @param fn - Function to transform the Err value
497
+ * @returns A new Result with transformed error
498
+ *
499
+ * @example
500
+ * ```typescript
501
+ * const result = err("not found");
502
+ * const mapped = mapErr(result, e => `Error: ${e}`); // Err<"Error: not found">
503
+ * ```
504
+ */
505
+ declare function mapErr<T, E, F>(result: Result<T, E>, fn: (error: E) => F): Result<T, F>;
506
+ /**
507
+ * Returns the value if Ok, otherwise returns the default value.
508
+ *
509
+ * @param result - The result to unwrap
510
+ * @param defaultValue - Default value to return if Err
511
+ * @returns The Ok value or the default value
512
+ *
513
+ * @example
514
+ * ```typescript
515
+ * const result = validateUserId("123");
516
+ * const userId = unwrapOr(result, "default-id");
517
+ * ```
518
+ */
519
+ declare function unwrapOr<T, E>(result: Result<T, E>, defaultValue: T): T;
520
+ /**
521
+ * Returns the value if Ok, otherwise computes default from error.
522
+ *
523
+ * @param result - The result to unwrap
524
+ * @param fn - Function to compute default from error
525
+ * @returns The Ok value or computed default
526
+ *
527
+ * @example
528
+ * ```typescript
529
+ * const result = validateUserId("");
530
+ * const userId = unwrapOrElse(result, err => `fallback-${Date.now()}`);
531
+ * ```
532
+ */
533
+ declare function unwrapOrElse<T, E>(result: Result<T, E>, fn: (error: E) => T): T;
534
+ /**
535
+ * Pattern matching for Result.
536
+ * Applies one function if Ok, another if Err.
537
+ *
538
+ * @param result - The result to match
539
+ * @param onOk - Function to apply if Ok
540
+ * @param onErr - Function to apply if Err
541
+ * @returns The result of applying the appropriate function
542
+ *
543
+ * @example
544
+ * ```typescript
545
+ * const message = match(result,
546
+ * value => `Success: ${value}`,
547
+ * error => `Error: ${error}`
548
+ * );
549
+ * ```
550
+ *
551
+ * @example Using object syntax
552
+ * ```typescript
553
+ * const message = match(result, {
554
+ * ok: value => `Success: ${value}`,
555
+ * err: error => `Error: ${error}`
556
+ * });
557
+ * ```
558
+ */
559
+ declare function match<T, E, R>(result: Result<T, E>, onOk: (value: T) => R, onErr: (error: E) => R): R;
560
+ declare function match<T, E, R>(result: Result<T, E>, handlers: {
561
+ ok: (value: T) => R;
562
+ err: (error: E) => R;
563
+ }): R;
564
+ /**
565
+ * Async pattern matching for Result.
566
+ * Applies one async function if Ok, another if Err.
567
+ * Both handlers must return Promises.
568
+ *
569
+ * @param result - The result to match
570
+ * @param onOk - Async function to apply if Ok
571
+ * @param onErr - Async function to apply if Err
572
+ * @returns Promise resolving to the result of applying the appropriate function
573
+ *
574
+ * @example
575
+ * ```typescript
576
+ * const message = await matchAsync(result,
577
+ * async (value) => `Success: ${value}`,
578
+ * async (error) => `Error: ${error}`
579
+ * );
580
+ * ```
581
+ *
582
+ * @example Using object syntax
583
+ * ```typescript
584
+ * const message = await matchAsync(result, {
585
+ * ok: async (value) => `Success: ${value}`,
586
+ * err: async (error) => `Error: ${error}`
587
+ * });
588
+ * ```
589
+ */
590
+ declare function matchAsync<T, E, R>(result: Result<T, E>, onOk: (value: T) => Promise<R>, onErr: (error: E) => Promise<R>): Promise<R>;
591
+ declare function matchAsync<T, E, R>(result: Result<T, E>, handlers: {
592
+ ok: (value: T) => Promise<R>;
593
+ err: (error: E) => Promise<R>;
594
+ }): Promise<R>;
595
+
596
+ /**
597
+ * Base class for Result with method chaining support.
598
+ * Provides common methods for both Ok and Err classes.
599
+ */
600
+ declare abstract class ResultBase<T, E> {
601
+ protected readonly _result: Result<T, E>;
602
+ protected constructor(result: Result<T, E>);
603
+ /**
604
+ * Returns the value if Ok, otherwise throws an error.
605
+ * If error is an Error instance, throws it directly.
606
+ * Otherwise, wraps the error in a new Error.
607
+ *
608
+ * @throws Error if the result is Err
609
+ */
610
+ unwrap(): T;
611
+ /**
612
+ * Returns the value if Ok, otherwise returns the default value.
613
+ */
614
+ unwrapOr(defaultValue: T): T;
615
+ /**
616
+ * Returns the value if Ok, otherwise computes default from error.
617
+ */
618
+ unwrapOrElse(fn: (error: E) => T): T;
619
+ /**
620
+ * Pattern matching for Result.
621
+ * Applies one function if Ok, another if Err.
622
+ *
623
+ * @example
624
+ * ```typescript
625
+ * outcome.match(
626
+ * value => `Success: ${value}`,
627
+ * error => `Error: ${error}`
628
+ * );
629
+ * ```
630
+ *
631
+ * @example Using object syntax
632
+ * ```typescript
633
+ * outcome.match({
634
+ * ok: value => `Success: ${value}`,
635
+ * err: error => `Error: ${error}`
636
+ * });
637
+ * ```
638
+ */
639
+ match<R>(onOk: (value: T) => R, onErr: (error: E) => R): R;
640
+ match<R>(handlers: {
641
+ ok: (value: T) => R;
642
+ err: (error: E) => R;
643
+ }): R;
644
+ /**
645
+ * Async pattern matching for Result.
646
+ * Applies one async function if Ok, another if Err.
647
+ *
648
+ * @example
649
+ * ```typescript
650
+ * await outcome.matchAsync(
651
+ * async (value) => `Success: ${value}`,
652
+ * async (error) => `Error: ${error}`
653
+ * );
654
+ * ```
655
+ *
656
+ * @example Using object syntax
657
+ * ```typescript
658
+ * await outcome.matchAsync({
659
+ * ok: async (value) => `Success: ${value}`,
660
+ * err: async (error) => `Error: ${error}`
661
+ * });
662
+ * ```
663
+ */
664
+ matchAsync<R>(onOk: (value: T) => Promise<R>, onErr: (error: E) => Promise<R>): Promise<R>;
665
+ matchAsync<R>(handlers: {
666
+ ok: (value: T) => Promise<R>;
667
+ err: (error: E) => Promise<R>;
668
+ }): Promise<R>;
669
+ /**
670
+ * Type guard to check if the result is Ok.
671
+ */
672
+ isOk(): this is Success<T>;
673
+ /**
674
+ * Type guard to check if the result is Err.
675
+ */
676
+ isErr(): this is Erroneous<E>;
677
+ /**
678
+ * Gets the underlying Result value.
679
+ */
680
+ get result(): Result<T, E>;
681
+ }
682
+ /**
683
+ * Class representing a successful result with method chaining support.
684
+ * Use this for class-based API with method chaining.
685
+ *
686
+ * @example
687
+ * ```typescript
688
+ * const okResult = Ok(1);
689
+ * const doubled = okResult.map(x => x * 2).unwrap(); // 2
690
+ *
691
+ * const chained = Ok(5)
692
+ * .andThen(x => Ok(x * 2))
693
+ * .map(x => x + 1)
694
+ * .unwrap(); // 11
695
+ * ```
696
+ */
697
+ declare class Success<T> extends ResultBase<T, never> {
698
+ constructor(value: T);
699
+ /**
700
+ * Factory function to create an Ok instance.
701
+ * Can be called with or without `new`.
702
+ */
703
+ static of<T>(value: T): Success<T>;
704
+ /**
705
+ * Chains Result operations (flatMap/bind).
706
+ * If the result is Ok, applies the function to the value.
707
+ * If Err, returns the error unchanged.
708
+ */
709
+ andThen<U, E>(fn: (value: T) => Result<U, E>): Success<U> | Erroneous<E>;
710
+ /**
711
+ * Transforms the Ok value using a function.
712
+ * If the result is Err, returns the error unchanged.
713
+ */
714
+ map<U>(fn: (value: T) => U): Success<U>;
715
+ /**
716
+ * Transforms the Err value using a function.
717
+ * If the result is Ok, returns the value unchanged.
718
+ */
719
+ mapErr<F>(_fn: (error: never) => F): Success<T>;
720
+ }
721
+
722
+ /**
723
+ * Class representing an erroneous result with method chaining support.
724
+ * Use this for class-based API with method chaining.
725
+ *
726
+ * @example
727
+ * ```typescript
728
+ * const errResult = Err(new Error("error"));
729
+ * errResult.map(x => x * 2).unwrap(); // throws Error("error")
730
+ *
731
+ * const mapped = Err("original")
732
+ * .mapErr(e => `Error: ${e}`)
733
+ * .unwrap(); // throws Error("Error: original")
734
+ * ```
735
+ */
736
+ declare class Erroneous<E> extends ResultBase<never, E> {
737
+ constructor(error: E);
738
+ /**
739
+ * Factory function to create an Err instance.
740
+ * Can be called with or without `new`.
741
+ */
742
+ static of<E>(error: E): Erroneous<E>;
743
+ /**
744
+ * Chains Result operations (flatMap/bind).
745
+ * If the result is Ok, applies the function to the value.
746
+ * If Err, returns the error unchanged.
747
+ */
748
+ andThen<U>(_fn: (value: never) => Result<U, E>): Erroneous<E>;
749
+ /**
750
+ * Transforms the Ok value using a function.
751
+ * If the result is Err, returns the error unchanged.
752
+ */
753
+ map<U>(_fn: (value: never) => U): Erroneous<E>;
754
+ /**
755
+ * Transforms the Err value using a function.
756
+ * If the result is Ok, returns the value unchanged.
757
+ */
758
+ mapErr<F>(fn: (error: E) => F): Erroneous<F>;
759
+ }
760
+
761
+ /**
762
+ * Class-based API for Result with method chaining support.
763
+ * Provides an object-oriented alternative to the functional Result type.
764
+ * Use `Outcome.from()` to wrap an existing Result, or `Outcome.ok()` / `Outcome.err()` to create new instances.
765
+ *
766
+ * @example
767
+ * ```typescript
768
+ * // Wrap an existing Result
769
+ * const result = Outcome.from(ok(1));
770
+ * const doubled = result.map(x => x * 2).unwrap(); // 2
771
+ *
772
+ * // Create directly
773
+ * const outcome = Outcome.ok(42);
774
+ * const value = outcome.map(x => x + 1).unwrap(); // 43
775
+ * ```
776
+ */
777
+ declare class Outcome<T, E> extends ResultBase<T, E> {
778
+ private constructor();
779
+ /**
780
+ * Creates an Outcome from an Ok value.
781
+ */
782
+ static ok<T>(value: T): Success<T>;
783
+ /**
784
+ * Creates an Outcome from an Err value.
785
+ */
786
+ static err<E>(error: E): Erroneous<E>;
787
+ /**
788
+ * Creates an Outcome from a Result.
789
+ */
790
+ static from<T, E>(result: Result<T, E>): Outcome<T, E>;
791
+ andThen<U>(fn: (value: T) => Result<U, E>): Outcome<U, E>;
792
+ map<U>(fn: (value: T) => U): Outcome<U, E>;
793
+ mapErr<F>(fn: (error: E) => F): Outcome<T, F>;
794
+ }
436
795
 
437
796
  type Handler<TState, TEvent> = (state: TState, event: TEvent) => TState;
438
797
  /**
@@ -446,7 +805,18 @@ interface AggregateEventSourcedConfig extends AggregateConfig {
446
805
  autoVersionBump?: boolean;
447
806
  }
448
807
  /**
449
- * Base class for Event-Sourced Aggregates.
808
+ * Base class for Event-Sourced Aggregate Roots (Entities).
809
+ *
810
+ * Extends `AggregateBase` to create an Aggregate Root Entity with Event Sourcing capabilities.
811
+ * The Aggregate Root is the parent Entity of the aggregate and represents it externally.
812
+ *
813
+ * The aggregate state (`TState`) contains:
814
+ * - Child entities (Entities with id, but no own version)
815
+ * - Value objects (immutable objects)
816
+ *
817
+ * All changes to child entities are versioned through the Aggregate Root. The version
818
+ * applies to the entire aggregate, including all child entities.
819
+ *
450
820
  * Extends `AggregateBase` with Event Sourcing capabilities:
451
821
  * - Event tracking (pendingEvents)
452
822
  * - Event handlers for state transitions
@@ -456,12 +826,13 @@ interface AggregateEventSourcedConfig extends AggregateConfig {
456
826
  * Use this class when you want Event Sourcing with full event tracking
457
827
  * and replay capabilities.
458
828
  *
459
- * @template TState - The type of the aggregate state
829
+ * @template TState - The type of the aggregate state (contains child entities and value objects)
460
830
  * @template TEvent - The union type of all domain events
461
- * @template TId - The type of the aggregate identifier
831
+ * @template TId - The type of the aggregate root identifier
462
832
  *
463
833
  * @example
464
834
  * ```typescript
835
+ * // Order is an Aggregate Root (an Entity) with Event Sourcing
465
836
  * class Order extends AggregateEventSourced<OrderState, OrderEvent, OrderId> {
466
837
  * confirm(): void {
467
838
  * this.apply(createDomainEvent("OrderConfirmed", {}));
@@ -957,6 +1328,11 @@ interface IQueryBus {
957
1328
  */
958
1329
  register<Q extends Query, R>(queryType: Q["type"], handler: QueryHandler<Q, R>): void;
959
1330
  }
1331
+ /**
1332
+ * Type map for query types to their return types.
1333
+ * Used to improve type inference in QueryBus.
1334
+ */
1335
+ type QueryTypeMap = Record<string, unknown>;
960
1336
  /**
961
1337
  * Simple in-memory query bus implementation.
962
1338
  * Handlers are stored in a Map and dispatched based on query type.
@@ -983,9 +1359,12 @@ interface IQueryBus {
983
1359
  * const order = await bus.execute({ type: "GetOrder", orderId: "123" });
984
1360
  * ```
985
1361
  */
986
- declare class QueryBus implements IQueryBus {
1362
+ declare class QueryBus<TMap extends QueryTypeMap = QueryTypeMap> implements IQueryBus {
987
1363
  private readonly handlers;
988
1364
  register<Q extends Query, R>(queryType: Q["type"], handler: QueryHandler<Q, R>): void;
1365
+ execute<Q extends Query & {
1366
+ type: keyof TMap;
1367
+ }>(query: Q): Promise<Result<TMap[Q["type"]], string>>;
989
1368
  execute<Q extends Query, R>(query: Q): Promise<Result<R, string>>;
990
1369
  executeUnsafe<Q extends Query, R>(query: Q): Promise<R>;
991
1370
  }
@@ -1009,18 +1388,42 @@ declare class QueryBus implements IQueryBus {
1009
1388
  declare function guard(cond: boolean, error: string): Result<true, string>;
1010
1389
 
1011
1390
  /**
1012
- * Optional interface for entities with identity.
1013
- * Use this when you need explicit entity types for nested entities
1014
- * within aggregates or for entities that are not aggregate roots.
1391
+ * Interface for entities with identity.
1392
+ *
1393
+ * In Domain-Driven Design, there are two types of entities:
1394
+ *
1395
+ * 1. **Aggregate Root Entity**: The parent Entity of an aggregate.
1396
+ * - Has identity (id) and version
1397
+ * - Implemented by classes extending `AggregateBase` or `AggregateEventSourced`
1398
+ * - Represents the aggregate externally
1399
+ * - Loaded/saved through repositories
1400
+ *
1401
+ * 2. **Child Entities**: Entities within an aggregate.
1402
+ * - Have identity (id), but no own version
1403
+ * - Exist only within the aggregate boundary
1404
+ * - Versioned through the Aggregate Root
1405
+ * - Cannot be referenced directly from outside the aggregate
1406
+ *
1407
+ * This interface is used for child entities within aggregates. The Aggregate Root
1408
+ * also implements this interface (through `AggregateRoot<TId>`), but additionally
1409
+ * has version management.
1015
1410
  *
1016
1411
  * @template TId - The type of the entity identifier
1017
1412
  *
1018
1413
  * @example
1019
1414
  * ```typescript
1415
+ * // Child Entity within an aggregate
1020
1416
  * type OrderItem = Entity<ItemId> & {
1021
1417
  * productId: string;
1022
1418
  * quantity: number;
1023
1419
  * };
1420
+ *
1421
+ * // Aggregate Root (also an Entity, but with version)
1422
+ * class Order extends AggregateBase<OrderState, OrderId>
1423
+ * implements AggregateRoot<OrderId> {
1424
+ * // Order is an Entity (the Aggregate Root)
1425
+ * // OrderState contains OrderItem (child entities)
1426
+ * }
1024
1427
  * ```
1025
1428
  */
1026
1429
  interface Entity<TId> {
@@ -1222,16 +1625,23 @@ interface ISpecification<T> {
1222
1625
  }
1223
1626
 
1224
1627
  /**
1225
- * The Repository works only with Aggregate Roots.
1226
- * It encapsulates the complexity of the data source (DB, API, etc.).
1628
+ * Repository interface for Aggregate Roots (Entities).
1227
1629
  *
1228
- * Repositories work with Aggregate Roots, which are the entry points
1229
- * for modifying aggregates in Domain-Driven Design.
1630
+ * Repositories work exclusively with Aggregate Root Entities. The Aggregate Root
1631
+ * is the Entity that represents the aggregate externally and is the only object
1632
+ * that can be loaded/saved through repositories.
1230
1633
  *
1231
- * @template TState - The type of the aggregate state
1634
+ * When loading an Aggregate Root, all child entities and value objects within
1635
+ * the aggregate state are loaded as well. When saving, the entire aggregate
1636
+ * (including all child entities) is persisted as a unit.
1637
+ *
1638
+ * Child entities cannot be loaded or saved independently - they exist only
1639
+ * within the aggregate boundary and are managed through the Aggregate Root.
1640
+ *
1641
+ * @template TState - The type of the aggregate state (contains child entities and value objects)
1232
1642
  * @template TEvent - The union type of all domain events
1233
- * @template TAgg - The aggregate type (must be an Aggregate Root)
1234
- * @template TId - The type of the aggregate identifier
1643
+ * @template TAgg - The aggregate root type (must be an Aggregate Root Entity)
1644
+ * @template TId - The type of the aggregate root identifier
1235
1645
  */
1236
1646
  interface IRepository<TState, TEvent extends DomainEvent<string, unknown>, TAgg extends AggregateRoot<TId> & Aggregate<TState, TEvent>, TId extends Id<string>> {
1237
1647
  getById(id: TId): Promise<TAgg | null>;
@@ -1325,4 +1735,4 @@ declare function voWithValidation<T>(t: T, validate: (value: T) => boolean, erro
1325
1735
  */
1326
1736
  declare function voWithValidationUnsafe<T>(t: T, validate: (value: T) => boolean, errorMessage?: string): ValueObject<T>;
1327
1737
 
1328
- export { type Aggregate, AggregateBase, type AggregateConfig, AggregateEventSourced, type AggregateEventSourcedConfig, type AggregateRoot, type AggregateSnapshot, type Clock, type Command, CommandBus, type CommandHandler, type DomainEvent, type Entity, type Err, type EventBus, EventBusImpl, type EventHandler, type EventMetadata, type ICommandBus, type IQueryBus, type IRepository, type ISpecification, type Id, type IdGenerator, type Ok, type Outbox, type Query, QueryBus, type QueryHandler, type RepoProvider, type Result, type UnitOfWork, type ValueObject, type Version, aggregate, bump, copyMetadata, createDomainEvent, createDomainEventWithMetadata, entityIds, err, findEntityById, guard, hasEntityId, isErr, isOk, mergeMetadata, ok, removeEntityById, replaceEntityById, sameAggregate, sameEntity, updateEntityById, vo, voEquals, voWithValidation, voWithValidationUnsafe, withCommit, withEvent };
1738
+ export { type Aggregate, AggregateBase, type AggregateConfig, AggregateEventSourced, type AggregateEventSourcedConfig, type AggregateRoot, type AggregateSnapshot, type Clock, type Command, CommandBus, type CommandHandler, type DomainEvent, type Entity, type Err, Erroneous, type EventBus, EventBusImpl, type EventHandler, type EventMetadata, type ICommandBus, type IQueryBus, type IRepository, type ISpecification, type Id, type IdGenerator, type Ok, type Outbox, Outcome, type Query, QueryBus, type QueryHandler, type RepoProvider, type Result, Success, type UnitOfWork, type ValueObject, type Version, aggregate, andThen, bump, copyMetadata, createDomainEvent, createDomainEventWithMetadata, entityIds, err, findEntityById, guard, hasEntityId, isErr, isOk, map, mapErr, match, matchAsync, mergeMetadata, ok, removeEntityById, replaceEntityById, sameAggregate, sameEntity, unwrapOr, unwrapOrElse, updateEntityById, vo, voEquals, voWithValidation, voWithValidationUnsafe, withCommit, withEvent };
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- var c=Object.defineProperty;var o=(t,e)=>c(t,"name",{value:e,configurable:true});function T(t,e=0){return {state:t,version:e,pendingEvents:[]}}o(T,"aggregate");function E(t,e){return {...t,pendingEvents:[...t.pendingEvents,e]}}o(E,"withEvent");function h(t){return {...t,version:t.version+1}}o(h,"bump");function m(t,e,r){return {type:t,payload:e,occurredAt:r?.occurredAt??new Date,version:r?.version??1,metadata:r?.metadata}}o(m,"createDomainEvent");function x(t,e,r,n){return m(t,e,{...n,metadata:r})}o(x,"createDomainEventWithMetadata");function b(t,e){return {...t.metadata??{},...e??{}}}o(b,"copyMetadata");function I(...t){return Object.assign({},...t.filter(Boolean))}o(I,"mergeMetadata");function R(t,e){return t.id===e.id&&t.version===e.version}o(R,"sameAggregate");var d=class{static{o(this,"AggregateBase");}id;version=0;_config;_autoVersionBump;get state(){return this._state}_state;constructor(e,r,n){this.id=e,this._state=r,this._config=n??{},this._autoVersionBump=this._config.autoVersionBump??false;}bumpVersion(){this.version=this.version+1;}setState(e,r){this._state=e,(r??this._autoVersionBump)&&this.bumpVersion();}createSnapshot(){return {state:{...this._state},version:this.version,snapshotAt:new Date}}restoreFromSnapshot(e){this._state=e.state,this.version=e.version;}};function s(t){return {ok:true,value:t}}o(s,"ok");function a(t){return {ok:false,error:t}}o(a,"err");function _(t){return t.ok===true}o(_,"isOk");function w(t){return t.ok===false}o(w,"isErr");var u=class extends d{static{o(this,"AggregateEventSourced");}_eventConfig;_eventAutoVersionBump;_pendingEvents=[];constructor(e,r,n){super(e,r,n),this._eventConfig=n??{},this._eventAutoVersionBump=this._eventConfig.autoVersionBump??true;}get pendingEvents(){return this._pendingEvents}clearPendingEvents(){this._pendingEvents.length=0;}validateEvent(e){return s(true)}apply(e,r=true){let n=this.validateEvent(e);if(!n.ok)return a(`Event validation failed for ${e.type}: ${n.error}`);let i=this.handlers[e.type];return i?(this._state=i(this._state,e),r&&(this._pendingEvents.push(e),this._eventAutoVersionBump&&(this.version=this.version+1)),s()):a(`Missing handler for event type: ${e.type}`)}applyUnsafe(e,r=true){let n=this.validateEvent(e);if(!n.ok)throw new Error(`Event validation failed for ${e.type}: ${n.error}`);let i=this.handlers[e.type];if(!i)throw new Error(`Missing handler for event type: ${e.type}`);this._state=i(this._state,e),r&&(this._pendingEvents.push(e),this._eventAutoVersionBump&&(this.version=this.version+1));}bumpVersion(){this.version=this.version+1;}loadFromHistory(e){for(let r of e){let n=this.apply(r,false);if(!n.ok)return n}return this.version=e.length,s()}hasPendingEvents(){return this._pendingEvents.length>0}getEventCount(){return this._pendingEvents.length}getLatestEvent(){return this._pendingEvents[this._pendingEvents.length-1]}restoreFromSnapshotWithEvents(e,r){this._state=e.state,this.version=e.version;for(let n of r){let i=this.apply(n,false);if(!i.ok)return i}return this.version=e.version+r.length,s()}};var p=class{static{o(this,"CommandBus");}handlers=new Map;register(e,r){this.handlers.set(e,r);}async execute(e){let r=this.handlers.get(e.type);return r?r(e):a(`No handler registered for command type: ${e.type}`)}};function N(t,e){return t.uow.transactional(async()=>{let{result:r,events:n}=await e();return await t.outbox.add(n),t.bus&&await t.bus.publish(n),r})}o(N,"withCommit");var l=class{static{o(this,"QueryBus");}handlers=new Map;register(e,r){this.handlers.set(e,r);}async execute(e){let r=this.handlers.get(e.type);if(!r)return a(`No handler registered for query type: ${e.type}`);try{let n=await r(e);return s(n)}catch(n){return a(n instanceof Error?n.message:String(n))}}async executeUnsafe(e){let r=this.handlers.get(e.type);if(!r)throw new Error(`No handler registered for query type: ${e.type}`);return r(e)}};function z(t,e){return t?s(true):a(e)}o(z,"guard");function G(t,e){return t.id===e.id}o(G,"sameEntity");function X(t,e){return t.find(r=>r.id===e)}o(X,"findEntityById");function Y(t,e){return t.some(r=>r.id===e)}o(Y,"hasEntityId");function Z(t,e){return t.filter(r=>r.id!==e)}o(Z,"removeEntityById");function ee(t,e,r){return t.map(n=>n.id===e?r(n):n)}o(ee,"updateEntityById");function te(t,e,r){return t.map(n=>n.id===e?r:n)}o(te,"replaceEntityById");function re(t){return t.map(e=>e.id)}o(re,"entityIds");var g=class{static{o(this,"EventBusImpl");}handlers=new Map;subscribe(e,r){let n=e;this.handlers.has(n)||this.handlers.set(n,new Set);let i=this.handlers.get(n);return i.add(r),()=>{i.delete(r),i.size===0&&this.handlers.delete(n);}}async publish(e){for(let r of e){let n=this.handlers.get(r.type);n&&await Promise.all(Array.from(n).map(i=>i(r)));}}};function v(t,e=new WeakSet){if(t===null||typeof t!="object"||e.has(t))return t;e.add(t);let r=Object.getOwnPropertyNames(t);for(let n of r){let i=t[n];i&&(typeof i=="object"||Array.isArray(i))&&v(i,e);}return Object.freeze(t)}o(v,"deepFreeze");function f(t){return v({...t})}o(f,"vo");function de(t,e){return JSON.stringify(t)===JSON.stringify(e)}o(de,"voEquals");function ue(t,e,r){return e(t)?s(f(t)):a(r??`Validation failed for value object: ${JSON.stringify(t)}`)}o(ue,"voWithValidation");function pe(t,e,r){if(!e(t))throw new Error(r??`Validation failed for value object: ${JSON.stringify(t)}`);return f(t)}o(pe,"voWithValidationUnsafe");export{d as AggregateBase,u as AggregateEventSourced,p as CommandBus,g as EventBusImpl,l as QueryBus,T as aggregate,h as bump,b as copyMetadata,m as createDomainEvent,x as createDomainEventWithMetadata,re as entityIds,a as err,X as findEntityById,z as guard,Y as hasEntityId,w as isErr,_ as isOk,I as mergeMetadata,s as ok,Z as removeEntityById,te as replaceEntityById,R as sameAggregate,G as sameEntity,ee as updateEntityById,f as vo,de as voEquals,ue as voWithValidation,pe as voWithValidationUnsafe,N as withCommit,E as withEvent};//# sourceMappingURL=index.js.map
1
+ var _=Object.defineProperty;var n=(t,e)=>_(t,"name",{value:e,configurable:true});function V(t,e=0){return {state:t,version:e,pendingEvents:[]}}n(V,"aggregate");function Q(t,e){return {...t,pendingEvents:[...t.pendingEvents,e]}}n(Q,"withEvent");function C(t){return {...t,version:t.version+1}}n(C,"bump");function A(t,e,r){return {type:t,payload:e,occurredAt:r?.occurredAt??new Date,version:r?.version??1,metadata:r?.metadata}}n(A,"createDomainEvent");function U(t,e,r,o){return A(t,e,{...o,metadata:r})}n(U,"createDomainEventWithMetadata");function O(t,e){return {...t.metadata??{},...e??{}}}n(O,"copyMetadata");function B(...t){return Object.assign({},...t.filter(Boolean))}n(B,"mergeMetadata");function M(t,e){return t.id===e.id&&t.version===e.version}n(M,"sameAggregate");var d=class{static{n(this,"AggregateBase");}id;version=0;_config;_autoVersionBump;get state(){return this._state}_state;constructor(e,r,o){this.id=e,this._state=r,this._config=o??{},this._autoVersionBump=this._config.autoVersionBump??false;}bumpVersion(){this.version=this.version+1;}setState(e,r){this._state=e,(r??this._autoVersionBump)&&this.bumpVersion();}createSnapshot(){return {state:{...this._state},version:this.version,snapshotAt:new Date}}restoreFromSnapshot(e){this._state=e.state,this.version=e.version;}};function a(t){return {ok:true,value:t}}n(a,"ok");function i(t){return {ok:false,error:t}}n(i,"err");function v(t){return t.ok===true}n(v,"isOk");function g(t){return t.ok===false}n(g,"isErr");function l(t,e){return t.ok?e(t.value):t}n(l,"andThen");function c(t,e){return t.ok?a(e(t.value)):t}n(c,"map");function E(t,e){return t.ok?t:i(e(t.error))}n(E,"mapErr");function h(t,e){return t.ok?t.value:e}n(h,"unwrapOr");function y(t,e){return t.ok?t.value:e(t.error)}n(y,"unwrapOrElse");function T(t,e,r){return typeof e=="function"?t.ok?e(t.value):r(t.error):t.ok?e.ok(t.value):e.err(t.error)}n(T,"match");async function m(t,e,r){return typeof e=="function"?t.ok?e(t.value):r(t.error):t.ok?e.ok(t.value):e.err(t.error)}n(m,"matchAsync");var u=class{static{n(this,"ResultBase");}_result;constructor(e){this._result=e;}unwrap(){if(this._result.ok)return this._result.value;throw this._result.error instanceof Error?this._result.error:new Error(String(this._result.error))}unwrapOr(e){return h(this._result,e)}unwrapOrElse(e){return y(this._result,e)}match(e,r){return typeof e=="function"?T(this._result,e,r):T(this._result,e)}async matchAsync(e,r){return typeof e=="function"?m(this._result,e,r):m(this._result,e)}isOk(){return v(this._result)}isErr(){return g(this._result)}get result(){return this._result}},f=class t extends u{static{n(this,"Success");}constructor(e){super(a(e));}static of(e){return new t(e)}andThen(e){let r=l(this._result,e);return r.ok?new t(r.value):new p(r.error)}map(e){let r=c(this._result,e);if(r.ok)return new t(r.value);throw new Error("Unexpected error in Success.map")}mapErr(e){return this}};var p=class t extends u{static{n(this,"Erroneous");}constructor(e){super(i(e));}static of(e){return new t(e)}andThen(e){return this}map(e){return this}mapErr(e){let r=E(this._result,e);if(!r.ok)return new t(r.error);throw new Error("Unexpected ok in Erroneous.mapErr")}};var x=class t extends u{static{n(this,"Outcome");}constructor(e){super(e);}static ok(e){return new f(e)}static err(e){return new p(e)}static from(e){return new t(e)}andThen(e){return t.from(l(this._result,e))}map(e){return t.from(c(this._result,e))}mapErr(e){return t.from(E(this._result,e))}};var R=class extends d{static{n(this,"AggregateEventSourced");}_eventConfig;_eventAutoVersionBump;_pendingEvents=[];constructor(e,r,o){super(e,r,o),this._eventConfig=o??{},this._eventAutoVersionBump=this._eventConfig.autoVersionBump??true;}get pendingEvents(){return this._pendingEvents}clearPendingEvents(){this._pendingEvents.length=0;}validateEvent(e){return a(true)}apply(e,r=true){let o=this.validateEvent(e);if(!o.ok)return i(`Event validation failed for ${e.type}: ${o.error}`);let s=this.handlers[e.type];return s?(this._state=s(this._state,e),r&&(this._pendingEvents.push(e),this._eventAutoVersionBump&&(this.version=this.version+1)),a()):i(`Missing handler for event type: ${e.type}`)}applyUnsafe(e,r=true){let o=this.validateEvent(e);if(!o.ok)throw new Error(`Event validation failed for ${e.type}: ${o.error}`);let s=this.handlers[e.type];if(!s)throw new Error(`Missing handler for event type: ${e.type}`);this._state=s(this._state,e),r&&(this._pendingEvents.push(e),this._eventAutoVersionBump&&(this.version=this.version+1));}bumpVersion(){this.version=this.version+1;}loadFromHistory(e){for(let r of e){let o=this.apply(r,false);if(!o.ok)return o}return this.version=e.length,a()}hasPendingEvents(){return this._pendingEvents.length>0}getEventCount(){return this._pendingEvents.length}getLatestEvent(){return this._pendingEvents[this._pendingEvents.length-1]}restoreFromSnapshotWithEvents(e,r){this._state=e.state,this.version=e.version;for(let o of r){let s=this.apply(o,false);if(!s.ok)return s}return this.version=e.version+r.length,a()}};var k=class{static{n(this,"CommandBus");}handlers=new Map;register(e,r){this.handlers.set(e,r);}async execute(e){let r=this.handlers.get(e.type);return r?r(e):i(`No handler registered for command type: ${e.type}`)}};function ne(t,e){return t.uow.transactional(async()=>{let{result:r,events:o}=await e();return await t.outbox.add(o),t.bus&&await t.bus.publish(o),r})}n(ne,"withCommit");var w=class{static{n(this,"QueryBus");}handlers=new Map;register(e,r){this.handlers.set(e,r);}async execute(e){let r=this.handlers.get(e.type);if(!r)return i(`No handler registered for query type: ${e.type}`);try{let o=await r(e);return a(o)}catch(o){return i(o instanceof Error?o.message:String(o))}}async executeUnsafe(e){let r=this.handlers.get(e.type);if(!r)throw new Error(`No handler registered for query type: ${e.type}`);return r(e)}};function de(t,e){return t?a(true):i(e)}n(de,"guard");function Ee(t,e){return t.id===e.id}n(Ee,"sameEntity");function Te(t,e){return t.find(r=>r.id===e)}n(Te,"findEntityById");function me(t,e){return t.some(r=>r.id===e)}n(me,"hasEntityId");function fe(t,e){return t.filter(r=>r.id!==e)}n(fe,"removeEntityById");function ve(t,e,r){return t.map(o=>o.id===e?r(o):o)}n(ve,"updateEntityById");function ge(t,e,r){return t.map(o=>o.id===e?r:o)}n(ge,"replaceEntityById");function he(t){return t.map(e=>e.id)}n(he,"entityIds");var S=class{static{n(this,"EventBusImpl");}handlers=new Map;subscribe(e,r){let o=e;this.handlers.has(o)||this.handlers.set(o,new Set);let s=this.handlers.get(o);return s.add(r),()=>{s.delete(r),s.size===0&&this.handlers.delete(o);}}async publish(e){for(let r of e){let o=this.handlers.get(r.type);o&&await Promise.all(Array.from(o).map(s=>s(r)));}}};function b(t,e=new WeakSet){if(t===null||typeof t!="object"||e.has(t))return t;e.add(t);let r=Object.getOwnPropertyNames(t);for(let o of r){let s=t[o];s&&(typeof s=="object"||Array.isArray(s))&&b(s,e);}return Object.freeze(t)}n(b,"deepFreeze");function I(t){return b({...t})}n(I,"vo");function Se(t,e){return JSON.stringify(t)===JSON.stringify(e)}n(Se,"voEquals");function be(t,e,r){return e(t)?a(I(t)):i(r??`Validation failed for value object: ${JSON.stringify(t)}`)}n(be,"voWithValidation");function Ie(t,e,r){if(!e(t))throw new Error(r??`Validation failed for value object: ${JSON.stringify(t)}`);return I(t)}n(Ie,"voWithValidationUnsafe");export{d as AggregateBase,R as AggregateEventSourced,k as CommandBus,p as Erroneous,S as EventBusImpl,x as Outcome,w as QueryBus,f as Success,V as aggregate,l as andThen,C as bump,O as copyMetadata,A as createDomainEvent,U as createDomainEventWithMetadata,he as entityIds,i as err,Te as findEntityById,de as guard,me as hasEntityId,g as isErr,v as isOk,c as map,E as mapErr,T as match,m as matchAsync,B as mergeMetadata,a as ok,fe as removeEntityById,ge as replaceEntityById,M as sameAggregate,Ee as sameEntity,h as unwrapOr,y as unwrapOrElse,ve as updateEntityById,I as vo,Se as voEquals,be as voWithValidation,Ie as voWithValidationUnsafe,ne as withCommit,Q as withEvent};//# sourceMappingURL=index.js.map
2
2
  //# sourceMappingURL=index.js.map