@rineex/ddd 1.6.1 → 2.1.0
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 +191 -19
- package/dist/index.d.mts +294 -73
- package/dist/index.d.ts +294 -73
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -1
package/dist/index.d.mts
CHANGED
|
@@ -197,7 +197,7 @@ interface DomainErrorMetadata {
|
|
|
197
197
|
* }
|
|
198
198
|
* }
|
|
199
199
|
*/
|
|
200
|
-
declare abstract class DomainError extends Error {
|
|
200
|
+
declare abstract class DomainError$1 extends Error {
|
|
201
201
|
/** Stable, machine-readable error code */
|
|
202
202
|
readonly code: string;
|
|
203
203
|
/** Structured, immutable domain metadata */
|
|
@@ -310,11 +310,11 @@ declare abstract class ValueObject<T> {
|
|
|
310
310
|
/**
|
|
311
311
|
* Custom error class for entity validation failures.
|
|
312
312
|
*/
|
|
313
|
-
declare class EntityValidationError extends DomainError {
|
|
313
|
+
declare class EntityValidationError extends DomainError$1 {
|
|
314
314
|
constructor(message: string, cause?: Error);
|
|
315
315
|
}
|
|
316
316
|
|
|
317
|
-
declare class InvalidValueObjectError extends DomainError {
|
|
317
|
+
declare class InvalidValueObjectError extends DomainError$1 {
|
|
318
318
|
constructor(message: string);
|
|
319
319
|
}
|
|
320
320
|
|
|
@@ -522,138 +522,359 @@ declare const HttpStatusMessage: {
|
|
|
522
522
|
type HttpStatusMessage = (typeof HttpStatusMessage)[keyof typeof HttpStatusMessage];
|
|
523
523
|
|
|
524
524
|
/**
|
|
525
|
-
*
|
|
526
|
-
*
|
|
525
|
+
* Strongly-typed domain error used in Result failures.
|
|
526
|
+
* Does NOT extend native Error on purpose — infrastructure maps to transport later.
|
|
527
527
|
*/
|
|
528
|
-
declare abstract class
|
|
529
|
-
abstract readonly code:
|
|
530
|
-
|
|
531
|
-
readonly metadata: Readonly<Record<string,
|
|
532
|
-
protected constructor(
|
|
528
|
+
declare abstract class DomainError {
|
|
529
|
+
abstract readonly code: DomainErrorCode;
|
|
530
|
+
readonly message: string;
|
|
531
|
+
readonly metadata: Readonly<Record<string, boolean | number | string>>;
|
|
532
|
+
protected constructor(params: {
|
|
533
|
+
message: string;
|
|
534
|
+
metadata?: Record<string, boolean | number | string>;
|
|
535
|
+
});
|
|
533
536
|
}
|
|
537
|
+
type DomainErrorCode = 'DOMAIN.INVALID_STATE' | 'DOMAIN.INVALID_VALUE';
|
|
534
538
|
|
|
535
539
|
/**
|
|
536
|
-
* Represents the
|
|
537
|
-
* without relying on exceptions for control flow.
|
|
540
|
+
* Represents the result of an operation, which can be either a success or a failure.
|
|
538
541
|
*
|
|
539
|
-
* This
|
|
540
|
-
*
|
|
542
|
+
* This is a functional programming pattern that helps avoid throwing exceptions
|
|
543
|
+
* and makes error handling explicit in the type system. It's commonly used in
|
|
544
|
+
* Domain-Driven Design (DDD) to represent domain operation outcomes.
|
|
541
545
|
*
|
|
542
|
-
*
|
|
543
|
-
*
|
|
544
|
-
* - A `Result` is **exactly one of**:
|
|
545
|
-
* - Success → contains a value
|
|
546
|
-
* - Failure → contains an error
|
|
547
|
-
* - Accessing the wrong side throws immediately (fail-fast).
|
|
546
|
+
* @template T The type of a successful result.
|
|
547
|
+
* @template E The type of the error in case of failure (defaults to DomainError).
|
|
548
548
|
*
|
|
549
|
-
* @
|
|
550
|
-
*
|
|
549
|
+
* @example
|
|
550
|
+
* ```typescript
|
|
551
|
+
* // Creating a successful result
|
|
552
|
+
* const success = Result.ok({ id: 1, name: 'John' });
|
|
553
|
+
* if (success.isSuccess) {
|
|
554
|
+
* const user = success.getValue(); // { id: 1, name: 'John' }
|
|
555
|
+
* }
|
|
556
|
+
*
|
|
557
|
+
* // Creating a failed result
|
|
558
|
+
* const failure = Result.fail(new InvalidUserError('User not found'));
|
|
559
|
+
* if (failure.isFailure) {
|
|
560
|
+
* const error = failure.getError(); // InvalidUserError instance
|
|
561
|
+
* }
|
|
562
|
+
* ```
|
|
551
563
|
*
|
|
552
564
|
* @example
|
|
553
|
-
* ```
|
|
554
|
-
*
|
|
555
|
-
*
|
|
565
|
+
* ```typescript
|
|
566
|
+
* // Using in a domain service
|
|
567
|
+
* function createUser(name: string): Result<User, DomainError> {
|
|
568
|
+
* if (!name || name.trim().length === 0) {
|
|
569
|
+
* return Result.fail(new InvalidValueError('Name cannot be empty'));
|
|
570
|
+
* }
|
|
556
571
|
*
|
|
557
|
-
*
|
|
558
|
-
*
|
|
572
|
+
* const user = new User(name);
|
|
573
|
+
* return Result.ok(user);
|
|
574
|
+
* }
|
|
575
|
+
*
|
|
576
|
+
* const result = createUser('John Doe');
|
|
577
|
+
* if (result.isSuccess) {
|
|
578
|
+
* console.log('User created:', result.getValue());
|
|
579
|
+
* } else {
|
|
580
|
+
* console.error('Failed:', result.getError()?.message);
|
|
581
|
+
* }
|
|
582
|
+
* ```
|
|
583
|
+
*
|
|
584
|
+
* @example
|
|
585
|
+
* ```typescript
|
|
586
|
+
* // Chaining operations
|
|
587
|
+
* function validateEmail(email: string): Result<string, DomainError> {
|
|
588
|
+
* if (!email.includes('@')) {
|
|
589
|
+
* return Result.fail(new InvalidValueError('Invalid email format'));
|
|
590
|
+
* }
|
|
591
|
+
* return Result.ok(email);
|
|
592
|
+
* }
|
|
593
|
+
*
|
|
594
|
+
* function createAccount(email: string): Result<Account, DomainError> {
|
|
595
|
+
* const emailResult = validateEmail(email);
|
|
596
|
+
* if (emailResult.isFailure) {
|
|
597
|
+
* return emailResult; // Forward the error
|
|
559
598
|
* }
|
|
560
599
|
*
|
|
561
|
-
*
|
|
600
|
+
* const account = new Account(emailResult.getValue()!);
|
|
601
|
+
* return Result.ok(account);
|
|
562
602
|
* }
|
|
603
|
+
* ```
|
|
563
604
|
*
|
|
564
|
-
*
|
|
605
|
+
* @example
|
|
606
|
+
* ```typescript
|
|
607
|
+
* // Working with async operations
|
|
608
|
+
* async function fetchUser(id: number): Promise<Result<User, DomainError>> {
|
|
609
|
+
* try {
|
|
610
|
+
* const user = await userRepository.findById(id);
|
|
611
|
+
* if (!user) {
|
|
612
|
+
* return Result.fail(new NotFoundError(`User ${id} not found`));
|
|
613
|
+
* }
|
|
614
|
+
* return Result.ok(user);
|
|
615
|
+
* } catch (error) {
|
|
616
|
+
* return Result.fail(new SystemError('Database connection failed'));
|
|
617
|
+
* }
|
|
618
|
+
* }
|
|
565
619
|
*
|
|
620
|
+
* const result = await fetchUser(123);
|
|
566
621
|
* if (result.isSuccess) {
|
|
567
|
-
*
|
|
622
|
+
* // Handle success
|
|
568
623
|
* } else {
|
|
569
|
-
*
|
|
624
|
+
* // Handle failure
|
|
570
625
|
* }
|
|
571
626
|
* ```
|
|
572
627
|
*/
|
|
573
628
|
declare class Result<T, E> {
|
|
574
|
-
private readonly _value?;
|
|
575
|
-
private readonly _error?;
|
|
576
629
|
/**
|
|
577
|
-
* Indicates
|
|
630
|
+
* Indicates if the result is a failure.
|
|
578
631
|
*
|
|
579
|
-
*
|
|
632
|
+
* @example
|
|
633
|
+
* ```typescript
|
|
634
|
+
* const result = Result.fail(new Error('Something went wrong'));
|
|
635
|
+
* if (result.isFailure) {
|
|
636
|
+
* // Handle error case
|
|
637
|
+
* console.error(result.getError());
|
|
638
|
+
* }
|
|
639
|
+
* ```
|
|
580
640
|
*/
|
|
581
641
|
readonly isFailure: boolean;
|
|
582
642
|
/**
|
|
583
|
-
* Indicates
|
|
643
|
+
* Indicates if the result is a success.
|
|
584
644
|
*
|
|
585
|
-
*
|
|
645
|
+
* @example
|
|
646
|
+
* ```typescript
|
|
647
|
+
* const result = Result.ok(42);
|
|
648
|
+
* if (result.isSuccess) {
|
|
649
|
+
* // Handle success case
|
|
650
|
+
* const value = result.getValue(); // 42
|
|
651
|
+
* }
|
|
652
|
+
* ```
|
|
586
653
|
*/
|
|
587
654
|
readonly isSuccess: boolean;
|
|
588
655
|
/**
|
|
589
|
-
*
|
|
590
|
-
*
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
*
|
|
595
|
-
* @
|
|
596
|
-
|
|
656
|
+
* The error, if any.
|
|
657
|
+
* @private
|
|
658
|
+
*/
|
|
659
|
+
private readonly _error?;
|
|
660
|
+
/**
|
|
661
|
+
* The value, if any.
|
|
662
|
+
* @private
|
|
663
|
+
*/
|
|
664
|
+
private readonly _value?;
|
|
665
|
+
/**
|
|
666
|
+
* Private constructor to enforce the use of static methods.
|
|
667
|
+
* @param params.value The value on success.
|
|
668
|
+
* @param params.error The error on failure.
|
|
669
|
+
* @private
|
|
597
670
|
*/
|
|
598
671
|
private constructor();
|
|
599
672
|
/**
|
|
600
|
-
* Creates a failed
|
|
673
|
+
* Creates a failed result.
|
|
601
674
|
*
|
|
602
|
-
* @
|
|
603
|
-
* @
|
|
675
|
+
* @template T The type of a successful result (never for failure).
|
|
676
|
+
* @template E The type of the error (defaults to DomainError).
|
|
677
|
+
* @param error The error object.
|
|
678
|
+
* @returns {Result<T, E>} A failed Result instance.
|
|
604
679
|
*
|
|
605
680
|
* @example
|
|
606
|
-
* ```
|
|
607
|
-
*
|
|
681
|
+
* ```typescript
|
|
682
|
+
* // With DomainError
|
|
683
|
+
* class InvalidValueError extends DomainError {
|
|
684
|
+
* public readonly code = 'DOMAIN.INVALID_VALUE' as const;
|
|
685
|
+
* constructor(message: string) {
|
|
686
|
+
* super({ message });
|
|
687
|
+
* }
|
|
688
|
+
* }
|
|
689
|
+
*
|
|
690
|
+
* const result = Result.fail(new InvalidValueError('Value must be positive'));
|
|
691
|
+
* // result.isFailure === true
|
|
692
|
+
* // result.getError() === InvalidValueError instance
|
|
693
|
+
* ```
|
|
694
|
+
*
|
|
695
|
+
* @example
|
|
696
|
+
* ```typescript
|
|
697
|
+
* // With custom error type
|
|
698
|
+
* interface ValidationError {
|
|
699
|
+
* field: string;
|
|
700
|
+
* message: string;
|
|
701
|
+
* }
|
|
702
|
+
*
|
|
703
|
+
* const result = Result.fail<never, ValidationError>({
|
|
704
|
+
* field: 'email',
|
|
705
|
+
* message: 'Invalid email format'
|
|
706
|
+
* });
|
|
707
|
+
* ```
|
|
708
|
+
*
|
|
709
|
+
* @example
|
|
710
|
+
* ```typescript
|
|
711
|
+
* // In a validation function
|
|
712
|
+
* function validateAge(age: number): Result<number, DomainError> {
|
|
713
|
+
* if (age < 0) {
|
|
714
|
+
* return Result.fail(new InvalidValueError('Age cannot be negative'));
|
|
715
|
+
* }
|
|
716
|
+
* if (age > 150) {
|
|
717
|
+
* return Result.fail(new InvalidValueError('Age seems unrealistic'));
|
|
718
|
+
* }
|
|
719
|
+
* return Result.ok(age);
|
|
720
|
+
* }
|
|
608
721
|
* ```
|
|
609
722
|
*/
|
|
610
|
-
static fail<T, E>(error: E): Result<T, E>;
|
|
723
|
+
static fail<T = never, E = DomainError>(error: E): Result<T, E>;
|
|
611
724
|
/**
|
|
612
|
-
* Creates a successful
|
|
725
|
+
* Creates a successful result.
|
|
726
|
+
*
|
|
727
|
+
* @template T The type of the successful result.
|
|
728
|
+
* @template E The type of the error (never for success).
|
|
729
|
+
* @param value The success value.
|
|
730
|
+
* @returns {Result<T, E>} A successful Result instance.
|
|
731
|
+
*
|
|
732
|
+
* @example
|
|
733
|
+
* ```typescript
|
|
734
|
+
* // With primitive value
|
|
735
|
+
* const result = Result.ok(42);
|
|
736
|
+
* // result.isSuccess === true
|
|
737
|
+
* // result.getValue() === 42
|
|
738
|
+
* ```
|
|
739
|
+
*
|
|
740
|
+
* @example
|
|
741
|
+
* ```typescript
|
|
742
|
+
* // With object
|
|
743
|
+
* const user = { id: 1, name: 'John', email: 'john@example.com' };
|
|
744
|
+
* const result = Result.ok(user);
|
|
745
|
+
* if (result.isSuccess) {
|
|
746
|
+
* const savedUser = result.getValue(); // { id: 1, name: 'John', ... }
|
|
747
|
+
* }
|
|
748
|
+
* ```
|
|
749
|
+
*
|
|
750
|
+
* @example
|
|
751
|
+
* ```typescript
|
|
752
|
+
* // With domain entity
|
|
753
|
+
* class User {
|
|
754
|
+
* constructor(public readonly id: number, public readonly name: string) {}
|
|
755
|
+
* }
|
|
756
|
+
*
|
|
757
|
+
* function createUser(name: string): Result<User, DomainError> {
|
|
758
|
+
* const user = new User(Date.now(), name);
|
|
759
|
+
* return Result.ok(user);
|
|
760
|
+
* }
|
|
613
761
|
*
|
|
614
|
-
*
|
|
615
|
-
*
|
|
762
|
+
* const result = createUser('Alice');
|
|
763
|
+
* if (result.isSuccess) {
|
|
764
|
+
* console.log(`Created user: ${result.getValue()?.name}`);
|
|
765
|
+
* }
|
|
766
|
+
* ```
|
|
616
767
|
*
|
|
617
768
|
* @example
|
|
618
|
-
* ```
|
|
619
|
-
* return
|
|
769
|
+
* ```typescript
|
|
770
|
+
* // With void/undefined (for operations that don't return a value)
|
|
771
|
+
* function deleteUser(id: number): Result<void, DomainError> {
|
|
772
|
+
* // ... deletion logic ...
|
|
773
|
+
* return Result.ok(undefined);
|
|
774
|
+
* }
|
|
775
|
+
*
|
|
776
|
+
* const result = deleteUser(123);
|
|
777
|
+
* if (result.isSuccess) {
|
|
778
|
+
* console.log('User deleted successfully');
|
|
779
|
+
* }
|
|
620
780
|
* ```
|
|
621
781
|
*/
|
|
622
|
-
static ok<T, E>(value: T): Result<T, E>;
|
|
782
|
+
static ok<T, E = never>(value: T): Result<T, E>;
|
|
623
783
|
/**
|
|
624
|
-
* Returns the
|
|
784
|
+
* Returns the error if present, otherwise undefined.
|
|
625
785
|
*
|
|
626
|
-
*
|
|
786
|
+
* **Note:** Always check `isFailure` before calling this method to ensure
|
|
787
|
+
* the result is actually a failure. This method will return `undefined` for
|
|
788
|
+
* successful results.
|
|
627
789
|
*
|
|
628
|
-
* @
|
|
629
|
-
* Thrown if this result represents a success.
|
|
630
|
-
* This is a fail-fast guard against incorrect usage.
|
|
790
|
+
* @returns {E | undefined} The error or undefined if successful.
|
|
631
791
|
*
|
|
632
792
|
* @example
|
|
633
|
-
* ```
|
|
793
|
+
* ```typescript
|
|
794
|
+
* const result = Result.fail(new InvalidValueError('Invalid input'));
|
|
795
|
+
*
|
|
634
796
|
* if (result.isFailure) {
|
|
635
797
|
* const error = result.getError();
|
|
798
|
+
* if (error) {
|
|
799
|
+
* console.error(`Error code: ${error.code}, Message: ${error.message}`);
|
|
800
|
+
* }
|
|
801
|
+
* }
|
|
802
|
+
* ```
|
|
803
|
+
*
|
|
804
|
+
* @example
|
|
805
|
+
* ```typescript
|
|
806
|
+
* // Safe error handling pattern
|
|
807
|
+
* function handleResult<T>(result: Result<T, DomainError>): void {
|
|
808
|
+
* if (result.isFailure) {
|
|
809
|
+
* const error = result.getError();
|
|
810
|
+
* if (error) {
|
|
811
|
+
* // Log error with metadata
|
|
812
|
+
* console.error({
|
|
813
|
+
* code: error.code,
|
|
814
|
+
* message: error.message,
|
|
815
|
+
* metadata: error.metadata
|
|
816
|
+
* });
|
|
817
|
+
* }
|
|
818
|
+
* }
|
|
636
819
|
* }
|
|
637
820
|
* ```
|
|
638
821
|
*/
|
|
639
|
-
getError(): E;
|
|
822
|
+
getError(): E | undefined;
|
|
640
823
|
/**
|
|
641
|
-
* Returns the
|
|
824
|
+
* Returns the value if present, otherwise undefined.
|
|
825
|
+
*
|
|
826
|
+
* **Note:** Always check `isSuccess` before calling this method to ensure
|
|
827
|
+
* the result is actually a success. This method will return `undefined` for
|
|
828
|
+
* failed results.
|
|
829
|
+
*
|
|
830
|
+
* @returns {T | undefined} The value or undefined if failed.
|
|
831
|
+
*
|
|
832
|
+
* @example
|
|
833
|
+
* ```typescript
|
|
834
|
+
* const result = Result.ok({ id: 1, name: 'John' });
|
|
642
835
|
*
|
|
643
|
-
*
|
|
836
|
+
* if (result.isSuccess) {
|
|
837
|
+
* const user = result.getValue();
|
|
838
|
+
* if (user) {
|
|
839
|
+
* console.log(`User: ${user.name} (ID: ${user.id})`);
|
|
840
|
+
* }
|
|
841
|
+
* }
|
|
842
|
+
* ```
|
|
644
843
|
*
|
|
645
|
-
* @
|
|
646
|
-
*
|
|
647
|
-
*
|
|
844
|
+
* @example
|
|
845
|
+
* ```typescript
|
|
846
|
+
* // Type-safe value extraction
|
|
847
|
+
* function processUser(result: Result<User, DomainError>): void {
|
|
848
|
+
* if (result.isSuccess) {
|
|
849
|
+
* const user = result.getValue();
|
|
850
|
+
* // TypeScript knows user is User | undefined here
|
|
851
|
+
* if (user) {
|
|
852
|
+
* // Process the user
|
|
853
|
+
* userRepository.save(user);
|
|
854
|
+
* }
|
|
855
|
+
* }
|
|
856
|
+
* }
|
|
857
|
+
* ```
|
|
648
858
|
*
|
|
649
859
|
* @example
|
|
650
|
-
* ```
|
|
860
|
+
* ```typescript
|
|
861
|
+
* // Using non-null assertion (use with caution)
|
|
862
|
+
* const result = Result.ok(42);
|
|
651
863
|
* if (result.isSuccess) {
|
|
652
|
-
* const value = result.getValue()
|
|
864
|
+
* const value = result.getValue()!; // Safe because we checked isSuccess
|
|
865
|
+
* console.log(value * 2); // 84
|
|
653
866
|
* }
|
|
654
867
|
* ```
|
|
655
868
|
*/
|
|
656
|
-
getValue(): T;
|
|
869
|
+
getValue(): T | undefined;
|
|
870
|
+
/**
|
|
871
|
+
* Type guard for failure.
|
|
872
|
+
*/
|
|
873
|
+
isFailureResult(): this is Result<never, E>;
|
|
874
|
+
/**
|
|
875
|
+
* Type guard for success.
|
|
876
|
+
*/
|
|
877
|
+
isSuccessResult(): this is Result<T, never>;
|
|
657
878
|
}
|
|
658
879
|
|
|
659
880
|
/**
|
|
@@ -717,4 +938,4 @@ type UnwrapValueObject<T> = T extends ValueObject<infer V> ? UnwrapValueObject<V
|
|
|
717
938
|
declare function unwrapValueObject<T>(input: T, seen?: WeakSet<object>): UnwrapValueObject<T>;
|
|
718
939
|
declare function ensureObject<T>(input: UnwrapValueObject<T>): object;
|
|
719
940
|
|
|
720
|
-
export { AggregateId, AggregateRoot, ApplicationError, type ApplicationServicePort, DomainError, type DomainErrorMetadata, DomainEvent, type DomainEventPayload,
|
|
941
|
+
export { AggregateId, AggregateRoot, ApplicationError, type ApplicationServicePort, DomainError$1 as DomainError, type DomainErrorMetadata, DomainEvent, type DomainEventPayload, Entity, type EntityId, type EntityProps, EntityValidationError, HttpStatus, type HttpStatusCode, HttpStatusMessage, InvalidValueObjectError, PrimitiveValueObject, type Props, Result, UUID, type UnixTimestampMillis, type UnwrapValueObject, ValueObject, deepFreeze, ensureObject, unwrapValueObject };
|