@rineex/ddd 1.6.1 → 2.0.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 +1 -136
- package/dist/index.d.ts +1 -136
- 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 +1 -1
package/README.md
CHANGED
|
@@ -844,41 +844,185 @@ export abstract class ApplicationError extends Error {
|
|
|
844
844
|
#### `Result<T, E>`
|
|
845
845
|
|
|
846
846
|
Represents the outcome of an operation that can either succeed or fail, without
|
|
847
|
-
relying on exceptions for control flow.
|
|
847
|
+
relying on exceptions for control flow. This is a functional programming pattern
|
|
848
|
+
that makes error handling explicit in the type system and is commonly used in
|
|
849
|
+
Domain-Driven Design to represent domain operation outcomes.
|
|
850
|
+
|
|
851
|
+
**Key Features:**
|
|
852
|
+
|
|
853
|
+
- **Immutable**: Result instances are frozen to prevent accidental mutations
|
|
854
|
+
- **Type-Safe**: Full TypeScript support with generic types
|
|
855
|
+
- **Explicit Error Handling**: No hidden exceptions, all errors are explicit
|
|
856
|
+
- **DomainError Integration**: Works seamlessly with `DomainError` by default
|
|
848
857
|
|
|
849
858
|
```typescript
|
|
850
|
-
export class Result<T, E> {
|
|
859
|
+
export class Result<T, E = DomainError> {
|
|
851
860
|
readonly isSuccess: boolean;
|
|
852
861
|
readonly isFailure: boolean;
|
|
853
862
|
|
|
854
|
-
public static ok<T, E>(value: T): Result<T, E>;
|
|
855
|
-
public static fail<T, E>(error: E): Result<T, E>;
|
|
856
|
-
public getValue(): T;
|
|
857
|
-
public getError(): E;
|
|
863
|
+
public static ok<T, E = never>(value: T): Result<T, E>;
|
|
864
|
+
public static fail<T = never, E = DomainError>(error: E): Result<T, E>;
|
|
865
|
+
public getValue(): T | undefined;
|
|
866
|
+
public getError(): E | undefined;
|
|
867
|
+
public isSuccessResult(): this is Result<T, never>;
|
|
868
|
+
public isFailureResult(): this is Result<never, E>;
|
|
858
869
|
}
|
|
859
870
|
```
|
|
860
871
|
|
|
861
|
-
**Example:**
|
|
872
|
+
**Basic Example:**
|
|
862
873
|
|
|
863
874
|
```typescript
|
|
864
|
-
import { Result } from '@rineex/ddd';
|
|
875
|
+
import { Result, DomainError } from '@rineex/ddd';
|
|
865
876
|
|
|
866
|
-
|
|
877
|
+
class InvalidValueError extends DomainError {
|
|
878
|
+
public get code() {
|
|
879
|
+
return 'DOMAIN.INVALID_VALUE' as const;
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
constructor(message: string) {
|
|
883
|
+
super({ message });
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
function parseNumber(input: string): Result<number, DomainError> {
|
|
867
888
|
const value = Number(input);
|
|
868
889
|
if (Number.isNaN(value)) {
|
|
869
|
-
return Result.fail('Invalid number');
|
|
890
|
+
return Result.fail(new InvalidValueError('Invalid number'));
|
|
870
891
|
}
|
|
871
892
|
return Result.ok(value);
|
|
872
893
|
}
|
|
873
894
|
|
|
874
895
|
const result = parseNumber('42');
|
|
875
896
|
if (result.isSuccess) {
|
|
876
|
-
|
|
897
|
+
const value = result.getValue(); // number | undefined
|
|
898
|
+
console.log(value); // 42
|
|
877
899
|
} else {
|
|
878
|
-
|
|
900
|
+
const error = result.getError(); // DomainError | undefined
|
|
901
|
+
console.error(error?.message);
|
|
902
|
+
}
|
|
903
|
+
```
|
|
904
|
+
|
|
905
|
+
**Validation Pattern:**
|
|
906
|
+
|
|
907
|
+
```typescript
|
|
908
|
+
function validateAge(age: number): Result<number, DomainError> {
|
|
909
|
+
if (age < 0) {
|
|
910
|
+
return Result.fail(new InvalidValueError('Age cannot be negative'));
|
|
911
|
+
}
|
|
912
|
+
if (age > 150) {
|
|
913
|
+
return Result.fail(new InvalidValueError('Age seems unrealistic'));
|
|
914
|
+
}
|
|
915
|
+
return Result.ok(age);
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
const result = validateAge(25);
|
|
919
|
+
if (result.isSuccess) {
|
|
920
|
+
console.log('Valid age:', result.getValue());
|
|
921
|
+
}
|
|
922
|
+
```
|
|
923
|
+
|
|
924
|
+
**Chaining Pattern:**
|
|
925
|
+
|
|
926
|
+
```typescript
|
|
927
|
+
function validateEmail(email: string): Result<string, DomainError> {
|
|
928
|
+
if (!email.includes('@')) {
|
|
929
|
+
return Result.fail(new InvalidValueError('Invalid email format'));
|
|
930
|
+
}
|
|
931
|
+
return Result.ok(email);
|
|
932
|
+
}
|
|
933
|
+
|
|
934
|
+
function createAccount(email: string): Result<{ email: string }, DomainError> {
|
|
935
|
+
const emailResult = validateEmail(email);
|
|
936
|
+
if (emailResult.isFailureResult()) {
|
|
937
|
+
return emailResult; // Forward the error
|
|
938
|
+
}
|
|
939
|
+
|
|
940
|
+
const validatedEmail = emailResult.getValue()!;
|
|
941
|
+
return Result.ok({ email: validatedEmail });
|
|
942
|
+
}
|
|
943
|
+
```
|
|
944
|
+
|
|
945
|
+
**Using Type Guards:**
|
|
946
|
+
|
|
947
|
+
The `isSuccessResult()` and `isFailureResult()` methods provide type-safe
|
|
948
|
+
narrowing:
|
|
949
|
+
|
|
950
|
+
```typescript
|
|
951
|
+
function processResult<T>(result: Result<T, DomainError>): void {
|
|
952
|
+
if (result.isSuccessResult()) {
|
|
953
|
+
// TypeScript narrows result to Result<T, never>
|
|
954
|
+
const value = result.getValue();
|
|
955
|
+
if (value) {
|
|
956
|
+
// Process the value with full type safety
|
|
957
|
+
console.log('Success:', value);
|
|
958
|
+
}
|
|
959
|
+
} else if (result.isFailureResult()) {
|
|
960
|
+
// TypeScript narrows result to Result<never, DomainError>
|
|
961
|
+
const error = result.getError();
|
|
962
|
+
if (error) {
|
|
963
|
+
// Access error properties with full type safety
|
|
964
|
+
console.error('Error code:', error.code);
|
|
965
|
+
console.error('Error message:', error.message);
|
|
966
|
+
}
|
|
967
|
+
}
|
|
879
968
|
}
|
|
880
969
|
```
|
|
881
970
|
|
|
971
|
+
**Working with Domain Errors:**
|
|
972
|
+
|
|
973
|
+
```typescript
|
|
974
|
+
class InvalidStateError extends DomainError {
|
|
975
|
+
public get code() {
|
|
976
|
+
return 'DOMAIN.INVALID_STATE' as const;
|
|
977
|
+
}
|
|
978
|
+
|
|
979
|
+
constructor(
|
|
980
|
+
message: string,
|
|
981
|
+
metadata?: Record<string, boolean | number | string>,
|
|
982
|
+
) {
|
|
983
|
+
super({ message, metadata });
|
|
984
|
+
}
|
|
985
|
+
}
|
|
986
|
+
|
|
987
|
+
function processOrder(orderId: string): Result<Order, DomainError> {
|
|
988
|
+
const order = orderRepository.findById(orderId);
|
|
989
|
+
if (!order) {
|
|
990
|
+
return Result.fail(new InvalidValueError('Order not found', { orderId }));
|
|
991
|
+
}
|
|
992
|
+
if (order.status !== 'PENDING') {
|
|
993
|
+
return Result.fail(
|
|
994
|
+
new InvalidStateError('Order cannot be processed', {
|
|
995
|
+
orderId,
|
|
996
|
+
currentStatus: order.status,
|
|
997
|
+
}),
|
|
998
|
+
);
|
|
999
|
+
}
|
|
1000
|
+
return Result.ok(order);
|
|
1001
|
+
}
|
|
1002
|
+
```
|
|
1003
|
+
|
|
1004
|
+
**Void Operations:**
|
|
1005
|
+
|
|
1006
|
+
```typescript
|
|
1007
|
+
function deleteUser(id: number): Result<void, DomainError> {
|
|
1008
|
+
if (id <= 0) {
|
|
1009
|
+
return Result.fail(new InvalidValueError('Invalid user ID'));
|
|
1010
|
+
}
|
|
1011
|
+
// ... deletion logic ...
|
|
1012
|
+
return Result.ok(undefined);
|
|
1013
|
+
}
|
|
1014
|
+
```
|
|
1015
|
+
|
|
1016
|
+
**Best Practices:**
|
|
1017
|
+
|
|
1018
|
+
1. Always check `isSuccess` or `isFailure` before calling `getValue()` or
|
|
1019
|
+
`getError()`
|
|
1020
|
+
2. Use `isSuccessResult()` and `isFailureResult()` type guards for better type
|
|
1021
|
+
narrowing when you need TypeScript to narrow the result type
|
|
1022
|
+
3. Use `DomainError` for domain-specific errors to maintain consistency
|
|
1023
|
+
4. Forward errors in chaining operations rather than creating new ones
|
|
1024
|
+
5. Leverage TypeScript's type narrowing for safe value extraction
|
|
1025
|
+
|
|
882
1026
|
### Domain Violations
|
|
883
1027
|
|
|
884
1028
|
#### `DomainViolation`
|
|
@@ -1453,8 +1597,23 @@ try {
|
|
|
1453
1597
|
}
|
|
1454
1598
|
}
|
|
1455
1599
|
|
|
1456
|
-
// Using Result type (functional approach)
|
|
1457
|
-
|
|
1600
|
+
// Using Result type (functional approach with DomainError)
|
|
1601
|
+
class InvalidEmailError extends DomainError {
|
|
1602
|
+
public get code() {
|
|
1603
|
+
return 'DOMAIN.INVALID_VALUE' as const;
|
|
1604
|
+
}
|
|
1605
|
+
|
|
1606
|
+
constructor(message: string) {
|
|
1607
|
+
super({ message });
|
|
1608
|
+
}
|
|
1609
|
+
}
|
|
1610
|
+
|
|
1611
|
+
function createUser(email: string): Result<User, DomainError> {
|
|
1612
|
+
// Validate email format
|
|
1613
|
+
if (!email.includes('@')) {
|
|
1614
|
+
return Result.fail(new InvalidEmailError('Invalid email format'));
|
|
1615
|
+
}
|
|
1616
|
+
|
|
1458
1617
|
try {
|
|
1459
1618
|
const emailVO = Email.create(email);
|
|
1460
1619
|
const user = new User({
|
|
@@ -1464,19 +1623,32 @@ function createUser(email: string): Result<User, string> {
|
|
|
1464
1623
|
});
|
|
1465
1624
|
return Result.ok(user);
|
|
1466
1625
|
} catch (error) {
|
|
1626
|
+
if (error instanceof InvalidValueObjectError) {
|
|
1627
|
+
return Result.fail(new InvalidEmailError(error.message));
|
|
1628
|
+
}
|
|
1467
1629
|
return Result.fail(
|
|
1468
|
-
|
|
1630
|
+
new InvalidEmailError(
|
|
1631
|
+
error instanceof Error ? error.message : 'Unknown error',
|
|
1632
|
+
),
|
|
1469
1633
|
);
|
|
1470
1634
|
}
|
|
1471
1635
|
}
|
|
1472
1636
|
|
|
1473
1637
|
const result = createUser('user@example.com');
|
|
1474
|
-
if (result.
|
|
1638
|
+
if (result.isSuccessResult()) {
|
|
1475
1639
|
const user = result.getValue();
|
|
1476
|
-
|
|
1477
|
-
|
|
1640
|
+
if (user) {
|
|
1641
|
+
// Use user safely with full type safety
|
|
1642
|
+
console.log('User created:', user.id.toString());
|
|
1643
|
+
}
|
|
1644
|
+
} else if (result.isFailureResult()) {
|
|
1478
1645
|
const error = result.getError();
|
|
1479
|
-
|
|
1646
|
+
if (error) {
|
|
1647
|
+
// Handle error with full context and type safety
|
|
1648
|
+
console.error('Error code:', error.code);
|
|
1649
|
+
console.error('Error message:', error.message);
|
|
1650
|
+
console.error('Metadata:', error.metadata);
|
|
1651
|
+
}
|
|
1480
1652
|
}
|
|
1481
1653
|
```
|
|
1482
1654
|
|
package/dist/index.d.mts
CHANGED
|
@@ -521,141 +521,6 @@ declare const HttpStatusMessage: {
|
|
|
521
521
|
};
|
|
522
522
|
type HttpStatusMessage = (typeof HttpStatusMessage)[keyof typeof HttpStatusMessage];
|
|
523
523
|
|
|
524
|
-
/**
|
|
525
|
-
* Base class for Domain violations.
|
|
526
|
-
* Purposely does NOT extend native Error to avoid stack trace overhead in the domain.
|
|
527
|
-
*/
|
|
528
|
-
declare abstract class DomainViolation {
|
|
529
|
-
abstract readonly code: string;
|
|
530
|
-
abstract readonly message: string;
|
|
531
|
-
readonly metadata: Readonly<Record<string, unknown>>;
|
|
532
|
-
protected constructor(metadata?: Record<string, unknown>);
|
|
533
|
-
}
|
|
534
|
-
|
|
535
|
-
/**
|
|
536
|
-
* Represents the outcome of an operation that can either succeed or fail,
|
|
537
|
-
* without relying on exceptions for control flow.
|
|
538
|
-
*
|
|
539
|
-
* This pattern is commonly used in domain and application layers to make
|
|
540
|
-
* success and failure states explicit, predictable, and type-safe.
|
|
541
|
-
*
|
|
542
|
-
* ## Design guarantees
|
|
543
|
-
* - A `Result` is **immutable** once created.
|
|
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).
|
|
548
|
-
*
|
|
549
|
-
* @typeParam T - Type of the success value
|
|
550
|
-
* @typeParam E - Type of the failure error
|
|
551
|
-
*
|
|
552
|
-
* @example
|
|
553
|
-
* ```ts
|
|
554
|
-
* function parseNumber(input: string): Result<number, string> {
|
|
555
|
-
* const value = Number(input);
|
|
556
|
-
*
|
|
557
|
-
* if (Number.isNaN(value)) {
|
|
558
|
-
* return Result.fail('Invalid number');
|
|
559
|
-
* }
|
|
560
|
-
*
|
|
561
|
-
* return Result.ok(value);
|
|
562
|
-
* }
|
|
563
|
-
*
|
|
564
|
-
* const result = parseNumber('42');
|
|
565
|
-
*
|
|
566
|
-
* if (result.isSuccess) {
|
|
567
|
-
* console.log(result.getValue()); // 42
|
|
568
|
-
* } else {
|
|
569
|
-
* console.error(result.getError());
|
|
570
|
-
* }
|
|
571
|
-
* ```
|
|
572
|
-
*/
|
|
573
|
-
declare class Result<T, E> {
|
|
574
|
-
private readonly _value?;
|
|
575
|
-
private readonly _error?;
|
|
576
|
-
/**
|
|
577
|
-
* Indicates whether the result represents a failed outcome.
|
|
578
|
-
*
|
|
579
|
-
* This flag is mutually exclusive with {@link isSuccess}.
|
|
580
|
-
*/
|
|
581
|
-
readonly isFailure: boolean;
|
|
582
|
-
/**
|
|
583
|
-
* Indicates whether the result represents a successful outcome.
|
|
584
|
-
*
|
|
585
|
-
* This flag is mutually exclusive with {@link isFailure}.
|
|
586
|
-
*/
|
|
587
|
-
readonly isSuccess: boolean;
|
|
588
|
-
/**
|
|
589
|
-
* Creates a new {@link Result} instance.
|
|
590
|
-
*
|
|
591
|
-
* This constructor is private to enforce the use of
|
|
592
|
-
* {@link Result.ok} and {@link Result.fail} factory methods,
|
|
593
|
-
* preserving the success/failure invariants.
|
|
594
|
-
*
|
|
595
|
-
* @param _value - Success value (defined only for success results)
|
|
596
|
-
* @param _error - Failure error (defined only for failure results)
|
|
597
|
-
*/
|
|
598
|
-
private constructor();
|
|
599
|
-
/**
|
|
600
|
-
* Creates a failed {@link Result}.
|
|
601
|
-
*
|
|
602
|
-
* @param error - Error describing the failure
|
|
603
|
-
* @returns A failure {@link Result} containing the provided error
|
|
604
|
-
*
|
|
605
|
-
* @example
|
|
606
|
-
* ```ts
|
|
607
|
-
* return Result.fail(new ValidationError('Email is invalid'));
|
|
608
|
-
* ```
|
|
609
|
-
*/
|
|
610
|
-
static fail<T, E>(error: E): Result<T, E>;
|
|
611
|
-
/**
|
|
612
|
-
* Creates a successful {@link Result}.
|
|
613
|
-
*
|
|
614
|
-
* @param value - Value representing a successful outcome
|
|
615
|
-
* @returns A success {@link Result} containing the provided value
|
|
616
|
-
*
|
|
617
|
-
* @example
|
|
618
|
-
* ```ts
|
|
619
|
-
* return Result.ok(user);
|
|
620
|
-
* ```
|
|
621
|
-
*/
|
|
622
|
-
static ok<T, E>(value: T): Result<T, E>;
|
|
623
|
-
/**
|
|
624
|
-
* Returns the failure error.
|
|
625
|
-
*
|
|
626
|
-
* @returns The error associated with a failed result
|
|
627
|
-
*
|
|
628
|
-
* @throws {Error}
|
|
629
|
-
* Thrown if this result represents a success.
|
|
630
|
-
* This is a fail-fast guard against incorrect usage.
|
|
631
|
-
*
|
|
632
|
-
* @example
|
|
633
|
-
* ```ts
|
|
634
|
-
* if (result.isFailure) {
|
|
635
|
-
* const error = result.getError();
|
|
636
|
-
* }
|
|
637
|
-
* ```
|
|
638
|
-
*/
|
|
639
|
-
getError(): E;
|
|
640
|
-
/**
|
|
641
|
-
* Returns the success value.
|
|
642
|
-
*
|
|
643
|
-
* @returns The value associated with a successful result
|
|
644
|
-
*
|
|
645
|
-
* @throws {Error}
|
|
646
|
-
* Thrown if this result represents a failure.
|
|
647
|
-
* This is a fail-fast guard against incorrect usage.
|
|
648
|
-
*
|
|
649
|
-
* @example
|
|
650
|
-
* ```ts
|
|
651
|
-
* if (result.isSuccess) {
|
|
652
|
-
* const value = result.getValue();
|
|
653
|
-
* }
|
|
654
|
-
* ```
|
|
655
|
-
*/
|
|
656
|
-
getValue(): T;
|
|
657
|
-
}
|
|
658
|
-
|
|
659
524
|
/**
|
|
660
525
|
* Utility to deeply freeze objects to ensure immutability - handles nested objects and arrays.
|
|
661
526
|
*
|
|
@@ -717,4 +582,4 @@ type UnwrapValueObject<T> = T extends ValueObject<infer V> ? UnwrapValueObject<V
|
|
|
717
582
|
declare function unwrapValueObject<T>(input: T, seen?: WeakSet<object>): UnwrapValueObject<T>;
|
|
718
583
|
declare function ensureObject<T>(input: UnwrapValueObject<T>): object;
|
|
719
584
|
|
|
720
|
-
export { AggregateId, AggregateRoot, ApplicationError, type ApplicationServicePort, DomainError, type DomainErrorMetadata, DomainEvent, type DomainEventPayload,
|
|
585
|
+
export { AggregateId, AggregateRoot, ApplicationError, type ApplicationServicePort, DomainError, type DomainErrorMetadata, DomainEvent, type DomainEventPayload, Entity, type EntityId, type EntityProps, EntityValidationError, HttpStatus, type HttpStatusCode, HttpStatusMessage, InvalidValueObjectError, PrimitiveValueObject, type Props, UUID, type UnixTimestampMillis, type UnwrapValueObject, ValueObject, deepFreeze, ensureObject, unwrapValueObject };
|
package/dist/index.d.ts
CHANGED
|
@@ -521,141 +521,6 @@ declare const HttpStatusMessage: {
|
|
|
521
521
|
};
|
|
522
522
|
type HttpStatusMessage = (typeof HttpStatusMessage)[keyof typeof HttpStatusMessage];
|
|
523
523
|
|
|
524
|
-
/**
|
|
525
|
-
* Base class for Domain violations.
|
|
526
|
-
* Purposely does NOT extend native Error to avoid stack trace overhead in the domain.
|
|
527
|
-
*/
|
|
528
|
-
declare abstract class DomainViolation {
|
|
529
|
-
abstract readonly code: string;
|
|
530
|
-
abstract readonly message: string;
|
|
531
|
-
readonly metadata: Readonly<Record<string, unknown>>;
|
|
532
|
-
protected constructor(metadata?: Record<string, unknown>);
|
|
533
|
-
}
|
|
534
|
-
|
|
535
|
-
/**
|
|
536
|
-
* Represents the outcome of an operation that can either succeed or fail,
|
|
537
|
-
* without relying on exceptions for control flow.
|
|
538
|
-
*
|
|
539
|
-
* This pattern is commonly used in domain and application layers to make
|
|
540
|
-
* success and failure states explicit, predictable, and type-safe.
|
|
541
|
-
*
|
|
542
|
-
* ## Design guarantees
|
|
543
|
-
* - A `Result` is **immutable** once created.
|
|
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).
|
|
548
|
-
*
|
|
549
|
-
* @typeParam T - Type of the success value
|
|
550
|
-
* @typeParam E - Type of the failure error
|
|
551
|
-
*
|
|
552
|
-
* @example
|
|
553
|
-
* ```ts
|
|
554
|
-
* function parseNumber(input: string): Result<number, string> {
|
|
555
|
-
* const value = Number(input);
|
|
556
|
-
*
|
|
557
|
-
* if (Number.isNaN(value)) {
|
|
558
|
-
* return Result.fail('Invalid number');
|
|
559
|
-
* }
|
|
560
|
-
*
|
|
561
|
-
* return Result.ok(value);
|
|
562
|
-
* }
|
|
563
|
-
*
|
|
564
|
-
* const result = parseNumber('42');
|
|
565
|
-
*
|
|
566
|
-
* if (result.isSuccess) {
|
|
567
|
-
* console.log(result.getValue()); // 42
|
|
568
|
-
* } else {
|
|
569
|
-
* console.error(result.getError());
|
|
570
|
-
* }
|
|
571
|
-
* ```
|
|
572
|
-
*/
|
|
573
|
-
declare class Result<T, E> {
|
|
574
|
-
private readonly _value?;
|
|
575
|
-
private readonly _error?;
|
|
576
|
-
/**
|
|
577
|
-
* Indicates whether the result represents a failed outcome.
|
|
578
|
-
*
|
|
579
|
-
* This flag is mutually exclusive with {@link isSuccess}.
|
|
580
|
-
*/
|
|
581
|
-
readonly isFailure: boolean;
|
|
582
|
-
/**
|
|
583
|
-
* Indicates whether the result represents a successful outcome.
|
|
584
|
-
*
|
|
585
|
-
* This flag is mutually exclusive with {@link isFailure}.
|
|
586
|
-
*/
|
|
587
|
-
readonly isSuccess: boolean;
|
|
588
|
-
/**
|
|
589
|
-
* Creates a new {@link Result} instance.
|
|
590
|
-
*
|
|
591
|
-
* This constructor is private to enforce the use of
|
|
592
|
-
* {@link Result.ok} and {@link Result.fail} factory methods,
|
|
593
|
-
* preserving the success/failure invariants.
|
|
594
|
-
*
|
|
595
|
-
* @param _value - Success value (defined only for success results)
|
|
596
|
-
* @param _error - Failure error (defined only for failure results)
|
|
597
|
-
*/
|
|
598
|
-
private constructor();
|
|
599
|
-
/**
|
|
600
|
-
* Creates a failed {@link Result}.
|
|
601
|
-
*
|
|
602
|
-
* @param error - Error describing the failure
|
|
603
|
-
* @returns A failure {@link Result} containing the provided error
|
|
604
|
-
*
|
|
605
|
-
* @example
|
|
606
|
-
* ```ts
|
|
607
|
-
* return Result.fail(new ValidationError('Email is invalid'));
|
|
608
|
-
* ```
|
|
609
|
-
*/
|
|
610
|
-
static fail<T, E>(error: E): Result<T, E>;
|
|
611
|
-
/**
|
|
612
|
-
* Creates a successful {@link Result}.
|
|
613
|
-
*
|
|
614
|
-
* @param value - Value representing a successful outcome
|
|
615
|
-
* @returns A success {@link Result} containing the provided value
|
|
616
|
-
*
|
|
617
|
-
* @example
|
|
618
|
-
* ```ts
|
|
619
|
-
* return Result.ok(user);
|
|
620
|
-
* ```
|
|
621
|
-
*/
|
|
622
|
-
static ok<T, E>(value: T): Result<T, E>;
|
|
623
|
-
/**
|
|
624
|
-
* Returns the failure error.
|
|
625
|
-
*
|
|
626
|
-
* @returns The error associated with a failed result
|
|
627
|
-
*
|
|
628
|
-
* @throws {Error}
|
|
629
|
-
* Thrown if this result represents a success.
|
|
630
|
-
* This is a fail-fast guard against incorrect usage.
|
|
631
|
-
*
|
|
632
|
-
* @example
|
|
633
|
-
* ```ts
|
|
634
|
-
* if (result.isFailure) {
|
|
635
|
-
* const error = result.getError();
|
|
636
|
-
* }
|
|
637
|
-
* ```
|
|
638
|
-
*/
|
|
639
|
-
getError(): E;
|
|
640
|
-
/**
|
|
641
|
-
* Returns the success value.
|
|
642
|
-
*
|
|
643
|
-
* @returns The value associated with a successful result
|
|
644
|
-
*
|
|
645
|
-
* @throws {Error}
|
|
646
|
-
* Thrown if this result represents a failure.
|
|
647
|
-
* This is a fail-fast guard against incorrect usage.
|
|
648
|
-
*
|
|
649
|
-
* @example
|
|
650
|
-
* ```ts
|
|
651
|
-
* if (result.isSuccess) {
|
|
652
|
-
* const value = result.getValue();
|
|
653
|
-
* }
|
|
654
|
-
* ```
|
|
655
|
-
*/
|
|
656
|
-
getValue(): T;
|
|
657
|
-
}
|
|
658
|
-
|
|
659
524
|
/**
|
|
660
525
|
* Utility to deeply freeze objects to ensure immutability - handles nested objects and arrays.
|
|
661
526
|
*
|
|
@@ -717,4 +582,4 @@ type UnwrapValueObject<T> = T extends ValueObject<infer V> ? UnwrapValueObject<V
|
|
|
717
582
|
declare function unwrapValueObject<T>(input: T, seen?: WeakSet<object>): UnwrapValueObject<T>;
|
|
718
583
|
declare function ensureObject<T>(input: UnwrapValueObject<T>): object;
|
|
719
584
|
|
|
720
|
-
export { AggregateId, AggregateRoot, ApplicationError, type ApplicationServicePort, DomainError, type DomainErrorMetadata, DomainEvent, type DomainEventPayload,
|
|
585
|
+
export { AggregateId, AggregateRoot, ApplicationError, type ApplicationServicePort, DomainError, type DomainErrorMetadata, DomainEvent, type DomainEventPayload, Entity, type EntityId, type EntityProps, EntityValidationError, HttpStatus, type HttpStatusCode, HttpStatusMessage, InvalidValueObjectError, PrimitiveValueObject, type Props, UUID, type UnixTimestampMillis, type UnwrapValueObject, ValueObject, deepFreeze, ensureObject, unwrapValueObject };
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var
|
|
1
|
+
var w=Object.create;var s=Object.defineProperty;var V=Object.getOwnPropertyDescriptor;var L=Object.getOwnPropertyNames,A=Object.getOwnPropertySymbols,M=Object.getPrototypeOf,N=Object.prototype.hasOwnProperty,C=Object.prototype.propertyIsEnumerable;var D=(e,t,r)=>t in e?s(e,t,{enumerable:!0,configurable:!0,writable:!0,value:r}):e[t]=r,O=(e,t)=>{for(var r in t||(t={}))N.call(t,r)&&D(e,r,t[r]);if(A)for(var r of A(t))C.call(t,r)&&D(e,r,t[r]);return e};var j=(e,t)=>{for(var r in t)s(e,r,{get:t[r],enumerable:!0})},_=(e,t,r,a)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of L(t))!N.call(e,n)&&n!==r&&s(e,n,{get:()=>t[n],enumerable:!(a=V(t,n))||a.enumerable});return e};var S=(e,t,r)=>(r=e!=null?w(M(e)):{},_(t||!e||!e.__esModule?s(r,"default",{value:e,enumerable:!0}):r,e)),H=e=>_(s({},"__esModule",{value:!0}),e);var q={};j(q,{AggregateId:()=>g,AggregateRoot:()=>f,ApplicationError:()=>b,DomainError:()=>o,DomainEvent:()=>I,Entity:()=>d,EntityValidationError:()=>y,HttpStatus:()=>k,HttpStatusMessage:()=>R,InvalidValueObjectError:()=>E,PrimitiveValueObject:()=>c,UUID:()=>p,ValueObject:()=>u,deepFreeze:()=>l,ensureObject:()=>G,unwrapValueObject:()=>i});module.exports=H(q);var d=class{constructor(t){var r;this.id=t.id,this.createdAt=(r=t.createdAt)!=null?r:new Date}equals(t){return t==null?!1:this===t?!0:this.id.equals(t.id)}};var f=class extends d{constructor(){super(...arguments);this._domainEvents=[]}get domainEvents(){return[...this._domainEvents]}addEvent(r){this._domainEvents.push(r)}pullDomainEvents(){let r=[...this._domainEvents];return this._domainEvents.length=0,r}};var F=e=>e instanceof Error?{cause:{message:e.message,stack:e.stack,name:e.name}}:e?{cause:e}:{},o=class extends Error{constructor(t,r,a={}){super(t,O({},F(a.cause))),Object.setPrototypeOf(this,new.target.prototype),this.name=new.target.name,this.code=r,this.metadata=Object.freeze(O({},a))}};var c=class{constructor(t){this.validate(t),this.value=t}equals(t){return t==null||Object.getPrototypeOf(this)!==Object.getPrototypeOf(t)?!1:this.value===t.value}getValue(){return this.value}toJSON(){return this.value}toString(){return String(this.value)}};var P=S(require("fast-deep-equal/es6"));function l(e,t=new WeakSet){if(e==null||typeof e!="object"&&!Array.isArray(e)||Object.isFrozen(e)||t.has(e))return e;if(t.add(e),Array.isArray(e))e.forEach(r=>l(r,t));else for(let r in e)Object.hasOwn(e,r)&&l(e[r],t);return Object.freeze(e)}var u=class e{get value(){return this.props}constructor(t){this.validate(t),this.props=l(t)}static is(t){return t instanceof e}equals(t){return t==null||Object.getPrototypeOf(this)!==Object.getPrototypeOf(t)?!1:(0,P.default)(this.props,t.props)}toJSON(){return this.props}toString(){return JSON.stringify(this.props)}};var y=class extends o{constructor(t,r){super(t,"ENTITY_VALIDATION_ERROR",{cause:r})}};var E=class extends o{constructor(t){super(t,"INVALID_VALUE_OBJECT")}};var U=require("crypto"),I=class{constructor(t){var r;this.id=(r=t.id)!=null?r:(0,U.randomUUID)(),this.aggregateId=t.aggregateId,this.schemaVersion=t.schemaVersion,this.occurredAt=t.occurredAt,this.payload=Object.freeze(t.payload)}toPrimitives(){return{aggregateId:this.aggregateId.toString(),schemaVersion:this.schemaVersion,occurredAt:this.occurredAt,eventName:this.eventName,payload:this.payload,id:this.id}}};var h=require("uuid"),v=S(require("zod"));var T=class T extends c{constructor(t){super(t),this.validate(t)}static fromString(t){return new this(t)}static generate(){return new this((0,h.v4)())}validate(t){let r=T.schema.safeParse(t);if(!r.success)throw new E(`Invalid UUID: ${r.error.message}`)}};T.schema=v.default.uuid();var p=T;var g=class extends p{};var k=Object.freeze({REQUEST_HEADER_FIELDS_TOO_LARGE:431,NETWORK_AUTHENTICATION_REQUIRED:511,NON_AUTHORITATIVE_INFORMATION:203,PROXY_AUTHENTICATION_REQUIRED:407,UNAVAILABLE_FOR_LEGAL_REASONS:451,HTTP_VERSION_NOT_SUPPORTED:505,BANDWIDTH_LIMIT_EXCEEDED:509,VARIANT_ALSO_NEGOTIATES:506,UNSUPPORTED_MEDIA_TYPE:415,RANGE_NOT_SATISFIABLE:416,PRECONDITION_REQUIRED:428,INTERNAL_SERVER_ERROR:500,UNPROCESSABLE_ENTITY:422,INSUFFICIENT_STORAGE:507,SWITCHING_PROTOCOLS:101,PRECONDITION_FAILED:412,MISDIRECTED_REQUEST:421,SERVICE_UNAVAILABLE:503,TEMPORARY_REDIRECT:307,PERMANENT_REDIRECT:308,METHOD_NOT_ALLOWED:405,EXPECTATION_FAILED:417,MOVED_PERMANENTLY:301,PAYLOAD_TOO_LARGE:413,FAILED_DEPENDENCY:424,TOO_MANY_REQUESTS:429,ALREADY_REPORTED:208,MULTIPLE_CHOICES:300,PAYMENT_REQUIRED:402,UPGRADE_REQUIRED:426,PARTIAL_CONTENT:206,REQUEST_TIMEOUT:408,LENGTH_REQUIRED:411,NOT_IMPLEMENTED:501,GATEWAY_TIMEOUT:504,NOT_ACCEPTABLE:406,RESET_CONTENT:205,LOOP_DETECTED:508,MULTI_STATUS:207,NOT_MODIFIED:304,UNAUTHORIZED:401,URI_TOO_LONG:414,NOT_EXTENDED:510,EARLY_HINTS:103,BAD_REQUEST:400,IM_A_TEAPOT:418,BAD_GATEWAY:502,PROCESSING:102,NO_CONTENT:204,SEE_OTHER:303,USE_PROXY:305,FORBIDDEN:403,NOT_FOUND:404,TOO_EARLY:425,CONTINUE:100,ACCEPTED:202,CONFLICT:409,CREATED:201,IM_USED:226,LOCKED:423,FOUND:302,GONE:410,OK:200}),R={431:"Request Header Fields Too Large",511:"Network Authentication Required",203:"Non-Authoritative Information",407:"Proxy Authentication Required",451:"Unavailable For Legal Reasons",505:"HTTP Version Not Supported",509:"Bandwidth Limit Exceeded",506:"Variant Also Negotiates",415:"Unsupported Media Type",416:"Range Not Satisfiable",428:"Precondition Required",500:"Internal Server Error",422:"Unprocessable Entity",507:"Insufficient Storage",101:"Switching Protocols",412:"Precondition Failed",421:"Misdirected Request",503:"Service Unavailable",307:"Temporary Redirect",308:"Permanent Redirect",405:"Method Not Allowed",417:"Expectation Failed",301:"Moved Permanently",413:"Payload Too Large",424:"Failed Dependency",429:"Too Many Requests",208:"Already Reported",300:"Multiple Choices",402:"Payment Required",426:"Upgrade Required",206:"Partial Content",408:"Request Timeout",411:"Length Required",501:"Not Implemented",504:"Gateway Timeout",406:"Not Acceptable",205:"Reset Content",508:"Loop Detected",207:"Multi-Status",304:"Not Modified",401:"Unauthorized",414:"URI Too Long",418:"I'm a Teapot",510:"Not Extended",103:"Early Hints",400:"Bad Request",502:"Bad Gateway",102:"Processing",204:"No Content",303:"See Other",305:"Use Proxy",403:"Forbidden",404:"Not Found",425:"Too Early",100:"Continue",202:"Accepted",226:"I'm Used",409:"Conflict",201:"Created",423:"Locked",302:"Found",410:"Gone",200:"OK"};var b=class extends Error{constructor({code:t=R[500],isOperational:r=!1,status:a=500,metadata:n,message:m,cause:x}){super(m),this.name=new.target.name,this.code=t,this.status=a,this.isOperational=r,this.metadata=n,this.cause=x,Error.captureStackTrace(this,new.target)}};function i(e,t=new WeakSet){if(e==null||typeof e!="object")return e;if(t.has(e))throw new Error("Circular reference detected in ValueObject unwrap");if(t.add(e),Array.isArray(e)){let a=e.map(n=>i(n,t));return t.delete(e),a}if(e instanceof u){let a=i(e.value,t);return t.delete(e),a}if(e instanceof Date)return t.delete(e),e.toISOString();if(e instanceof Map){let a=new Map;return e.forEach((n,m)=>{a.set(m,i(n,t))}),t.delete(e),a}if(e instanceof Set){let a=new Set(Array.from(e.values()).map(n=>i(n,t)));return t.delete(e),a}let r={};for(let a in e)Object.hasOwn(e,a)&&(r[a]=i(e[a],t));return t.delete(e),r}function G(e){return e==null?{}:typeof e=="object"?e:{value:e}}0&&(module.exports={AggregateId,AggregateRoot,ApplicationError,DomainError,DomainEvent,Entity,EntityValidationError,HttpStatus,HttpStatusMessage,InvalidValueObjectError,PrimitiveValueObject,UUID,ValueObject,deepFreeze,ensureObject,unwrapValueObject});
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/domain/entities/entity.ts","../src/domain/aggregates/aggregate-root.ts","../src/domain/base/domain.error.ts","../src/domain/base/primitive-vo.ts","../src/domain/base/vo.ts","../src/utils/deep-freeze.util.ts","../src/domain/errors/entity-validation.error.ts","../src/domain/errors/invalid-vo.error.ts","../src/domain/events/domain.event.ts","../src/domain/value-objects/id.vo.ts","../src/domain/value-objects/aggregate-id.vo.ts","../src/gateway/constants/http-code.ts","../src/shared/domain/domain.violation.ts","../src/shared/domain/result.ts","../src/utils/errors/application.error.ts","../src/utils/unwrap-vo.util.ts"],"sourcesContent":["export * from './application';\nexport * from './domain/aggregates';\nexport * from './domain/base/domain.error';\nexport * from './domain/base/primitive-vo';\nexport * from './domain/base/vo';\nexport * from './domain/entities';\nexport * from './domain/errors/entity-validation.error';\nexport * from './domain/errors/invalid-vo.error';\nexport * from './domain/events';\nexport * from './domain/types';\nexport * from './domain/value-objects/aggregate-id.vo';\nexport * from './domain/value-objects/id.vo';\nexport * from './gateway/constants/http-code';\nexport * from './shared/domain';\nexport * from './utils';\n","import { EntityId } from '../types';\n\n/**\n * Configuration for the base Entity constructor.\n * Forces a single-object argument pattern to avoid positional argument errors.\n * @template ID - A type satisfying the EntityId interface.\n */\nexport interface EntityProps<ID extends EntityId, Props> {\n /** The unique identity of the entity */\n readonly id: ID;\n /** Optional creation timestamp; defaults to 'now' if not provided */\n readonly createdAt?: Date;\n\n readonly props: Props;\n}\n\n/**\n * Abstract Base Entity for Domain-Driven Design (DDD).\n * This class provides the standard contract for entity equality and identity.\n * It intentionally avoids \"magic\" property bags to ensure V8 engine optimization\n * and better IDE intellisense.\n * @template ID - The specific Identity Value Object type.\n */\nexport abstract class Entity<ID extends EntityId, Props> {\n /** The timestamp when this entity was first instantiated/created */\n public readonly createdAt: Date;\n /** The immutable unique identifier for this entity */\n public readonly id: ID;\n\n /**\n * Protected constructor to be called by subclasses.\n * @param props - Initial identity and metadata.\n */\n protected constructor(props: EntityProps<ID, Props>) {\n this.id = props.id;\n this.createdAt = props.createdAt ?? new Date();\n }\n\n /**\n * Compares entities by identity.\n * In DDD, two entities are considered equal if their IDs match,\n * regardless of their other properties.\n * @param other - The entity to compare against.\n * @returns True if IDs are equal.\n */\n public equals(other?: Entity<ID, Props>): boolean {\n if (other == null) return false;\n if (this === other) return true;\n return this.id.equals(other.id);\n }\n\n /**\n * Converts the Entity into a plain Javascript object.\n * Subclasses must implement this to explicitly control serialization,\n * @returns A plain object representation of the entity.\n */\n public abstract toObject(): Record<string, unknown>;\n\n /**\n * Validates the current state of the entity against domain invariants.\n * This method should be called after construction and any mutation.\n * @throws {Error} Should throw a specific DomainError if validation fails.\n */\n public abstract validate(): void;\n}\n","import { Entity, EntityProps } from '../entities/entity';\nimport { DomainEvent } from '../events';\nimport { EntityId } from '../types';\n\n/**\n * Interface for AggregateRoot to ensure type safety and extensibility.\n */\nexport interface Props<P> extends EntityProps<EntityId, P> {\n readonly domainEvents: readonly DomainEvent[];\n /**\n * Adds a domain event to the aggregate.\n * @param event The domain event to add.\n */\n addEvent: (event: DomainEvent) => void;\n\n /**\n * Retrieves and clears all domain events recorded by this aggregate.\n *\n * Domain events represent facts that occurred as a result of state changes\n * within the aggregate. This method transfers ownership of those events\n * to the application layer for further processing (e.g. publishing).\n *\n * Calling this method has the side effect of clearing the aggregate's\n * internal event collection to prevent duplicate handling.\n *\n * This method is intended to be invoked by application services\n * after the aggregate has been successfully persisted.\n *\n * @returns A read-only list of domain events raised by this aggregate.\n */\n pullDomainEvents: () => readonly DomainEvent[];\n}\n\n/**\n * Base class for aggregate roots in DDD, encapsulating domain events and validation.\n * @template EntityProps The type of the entity's properties.\n */\nexport abstract class AggregateRoot<ID extends EntityId, P> extends Entity<\n ID,\n P\n> {\n /**\n * Gets a read-only copy of the domain events.\n */\n get domainEvents(): readonly DomainEvent[] {\n return [...this._domainEvents];\n }\n\n /**\n * Internal list of domain events.\n */\n private readonly _domainEvents: DomainEvent[] = [];\n\n /**\n * Adds a domain event to the aggregate after validating invariants.\n * @param domainEvent The domain event to add.\n * @throws {EntityValidationError} If invariants are not met.\n */\n addEvent(domainEvent: DomainEvent): void {\n this._domainEvents.push(domainEvent);\n }\n\n public pullDomainEvents(): readonly DomainEvent[] {\n const events = [...this._domainEvents];\n this._domainEvents.length = 0;\n return events;\n }\n}\n","export interface DomainErrorMetadata {\n cause?: { name: string; message: string; stack?: string };\n [key: string]: unknown;\n}\n\nconst getCauseInfo = (cause: Error | undefined) => {\n // 1. Handle Error objects specifically\n if (cause instanceof Error) {\n return {\n cause: {\n message: cause.message,\n stack: cause.stack,\n name: cause.name,\n },\n };\n }\n\n // 2. Handle other existing values\n if (cause) {\n return { cause };\n }\n\n // 3. Default to empty\n return {};\n};\n\n/**\n * Base class for all Domain Errors in the application.\n *\n * This class ensures:\n * 1. Serializable and structured for logs or API responses.\n * 2. Identifiable via stable error codes (not just class names).\n * 3. Contextual with optional structured metadata.\n * 4. Supports error chaining (cause) and stack trace preservation.\n *\n * @example\n * export class InsufficientFundsError extends DomainError {\n * constructor(accountId: string, currentBalance: number) {\n * super(\n * `Account ${accountId} has insufficient funds.`,\n * 'INSUFFICIENT_FUNDS',\n * { accountId, currentBalance }\n * );\n * }\n * }\n */\nexport abstract class DomainError extends Error {\n /** Stable, machine-readable error code */\n public readonly code: string;\n /** Structured, immutable domain metadata */\n public readonly metadata: Readonly<DomainErrorMetadata>;\n\n /**\n * @param message - Human-readable error message\n * @param code - Stable error code\n * @param metadata - Domain-specific structured data; optional `cause` can be included\n */\n protected constructor(\n message: string,\n code: string,\n metadata: DomainErrorMetadata = {},\n ) {\n super(message, { ...getCauseInfo(metadata.cause) });\n\n // Restore prototype chain for proper `instanceof` checks\n Object.setPrototypeOf(this, new.target.prototype);\n\n this.name = new.target.name;\n this.code = code;\n this.metadata = Object.freeze({ ...metadata });\n }\n}\n","import { EntityId } from '../types';\n\ntype Primitive = boolean | number | string;\n\n/**\n * Base class for primitive-based Value Objects.\n *\n * This class is intended for Value Objects that are represented by\n * a single primitive value (string, number, or boolean).\n *\n * Characteristics:\n * - Immutable by construction\n * - Cheap equality comparison\n * - No deep cloning or freezing\n * - Safe for serialization and logging\n *\n * Examples:\n * - AggregateId\n * - EmailAddress\n * - Username\n * - Slug\n */\nexport abstract class PrimitiveValueObject<\n T extends Primitive,\n> implements EntityId {\n /**\n * The underlying primitive value.\n * Guaranteed to be valid after construction.\n */\n protected readonly value: T;\n\n /**\n * Constructs a new PrimitiveValueObject.\n *\n * @param value - The primitive value to wrap\n * @throws Error if validation fails\n */\n protected constructor(value: T) {\n this.validate(value);\n this.value = value;\n }\n\n /**\n * Compares two Value Objects for equality.\n *\n * Equality rules:\n * - Same concrete class\n * - Same primitive value (===)\n *\n * @param other - Another Value Object\n */\n public equals(other?: PrimitiveValueObject<T> | null | undefined): boolean {\n if (other === undefined || other === null) return false;\n\n if (Object.getPrototypeOf(this) !== Object.getPrototypeOf(other)) {\n return false;\n }\n\n return this.value === other.value;\n }\n\n /**\n * Returns the primitive value.\n * Prefer explicit access over implicit coercion.\n */\n public getValue(): T {\n return this.value;\n }\n\n /**\n * JSON serialization hook.\n * Produces the raw primitive value.\n */\n public toJSON(): T {\n return this.value;\n }\n\n /**\n * String representation.\n * Useful for logging and debugging.\n */\n public toString(): string {\n return String(this.value);\n }\n\n /**\n * Domain invariant validation.\n * Must throw if the value is invalid.\n *\n * @param value - The value to validate\n */\n protected abstract validate(value: T): void;\n}\n","import deepEqual from 'fast-deep-equal/es6';\n\nimport { deepFreeze } from '@/utils/deep-freeze.util';\n\nexport abstract class ValueObject<T> {\n get value(): T {\n return this.props;\n }\n\n protected readonly props: Readonly<T>;\n\n protected constructor(props: T) {\n this.validate(props);\n this.props = deepFreeze(props);\n }\n\n /**\n * Type guard to check if an unknown object is an instance of ValueObject.\n * This is useful for runtime type checking.\n *\n * @param vo The object to check.\n * @returns True if the object is a ValueObject instance, false otherwise.\n */\n public static is(vo: unknown): vo is ValueObject<unknown> {\n return vo instanceof ValueObject;\n }\n\n /**\n * Deep equality comparison of ValueObjects\n */\n public equals(other?: ValueObject<T>): boolean {\n if (other === null || other === undefined) return false;\n\n // Check if they share the same constructor (Type check)\n if (Object.getPrototypeOf(this) !== Object.getPrototypeOf(other)) {\n return false;\n }\n\n return deepEqual(this.props, other.props);\n }\n\n /**\n * Standard for clean API integration and logging.\n */\n public toJSON(): T {\n return this.props;\n }\n\n /**\n * Useful for debugging and string-based indexing.\n */\n public toString(): string {\n return JSON.stringify(this.props);\n }\n\n /**\n * Validates the value object props\n * @throws InvalidValueObjectError if validation fails\n */\n protected abstract validate(props: T): void;\n}\n","/**\n * Utility to deeply freeze objects to ensure immutability - handles nested objects and arrays.\n *\n * @param obj - The object to be deeply frozen.\n * @param seen - A WeakSet to track already processed objects (for circular references).\n * @returns A deeply frozen version of the input object.\n */\nexport function deepFreeze<T>(\n obj: T,\n seen = new WeakSet<object>(),\n): Readonly<T> {\n // Handle null, undefined, or non-object types\n if (obj == null || (typeof obj !== 'object' && !Array.isArray(obj))) {\n return obj;\n }\n\n // Skip if already frozen\n if (Object.isFrozen(obj)) {\n return obj as Readonly<T>;\n }\n\n // Handle circular references\n if (seen.has(obj as object)) {\n return obj as Readonly<T>;\n }\n\n seen.add(obj as object);\n\n // Handle arrays explicitly\n if (Array.isArray(obj)) {\n obj.forEach(item => deepFreeze(item, seen));\n } else {\n // Handle plain objects\n for (const key in obj) {\n if (Object.hasOwn(obj, key)) {\n deepFreeze((obj as Record<string, unknown>)[key], seen);\n }\n }\n }\n\n return Object.freeze(obj) as Readonly<T>;\n}\n","import { DomainError } from '../base/domain.error';\n\n/**\n * Custom error class for entity validation failures.\n */\nexport class EntityValidationError extends DomainError {\n constructor(message: string, cause?: Error) {\n super(message, 'ENTITY_VALIDATION_ERROR', { cause });\n }\n}\n","import { DomainError } from '../base/domain.error';\n\nexport class InvalidValueObjectError extends DomainError {\n constructor(message: string) {\n super(message, 'INVALID_VALUE_OBJECT');\n }\n}\n","import { randomUUID } from 'node:crypto';\n\nimport { EntityId } from '../types';\n\ntype Primitive = boolean | number | string | null;\n\ntype Serializable =\n | Primitive\n | Serializable[]\n | { [key: string]: Serializable };\n\nexport type DomainEventPayload = Record<string, Serializable>;\n\nexport type UnixTimestampMillis = number;\n\ntype DomainEventProps<AggregateId extends EntityId, Payload> = {\n id?: string;\n aggregateId: AggregateId;\n schemaVersion: number;\n occurredAt: UnixTimestampMillis;\n payload: Payload;\n};\n\n// Abstract base class for domain events\nexport abstract class DomainEvent<\n AggregateId extends EntityId = EntityId,\n T extends DomainEventPayload = DomainEventPayload,\n> {\n public readonly aggregateId: AggregateId;\n\n public abstract readonly eventName: string;\n public readonly id: string;\n public readonly occurredAt: number;\n public readonly payload: Readonly<T>;\n public readonly schemaVersion: number;\n\n protected constructor(props: DomainEventProps<AggregateId, T>) {\n this.id = props.id ?? randomUUID();\n this.aggregateId = props.aggregateId;\n this.schemaVersion = props.schemaVersion;\n this.occurredAt = props.occurredAt;\n this.payload = Object.freeze(props.payload);\n }\n\n public toPrimitives(): Readonly<{\n id: string;\n eventName: string;\n aggregateId: string;\n schemaVersion: number;\n occurredAt: UnixTimestampMillis;\n payload: T;\n }> {\n return {\n aggregateId: this.aggregateId.toString(),\n schemaVersion: this.schemaVersion,\n occurredAt: this.occurredAt,\n eventName: this.eventName,\n payload: this.payload,\n id: this.id,\n };\n }\n}\n","import { v4 } from 'uuid';\nimport z from 'zod';\n\nimport { InvalidValueObjectError } from '../errors/invalid-vo.error';\nimport { PrimitiveValueObject } from '../base/primitive-vo';\n\n/**\n * Represents a UUID (Universally Unique Identifier) value object.\n *\n * This class extends PrimitiveValueObject to provide type-safe UUID handling\n * with validation using Zod schema. UUIDs are immutable and can be generated\n * randomly or created from string values.\n *\n * @example\n * // Generate a new random UUID\n * const id = UUID.generate();\n *\n * @example\n * // Create UUID from an existing string\n * const id = UUID.fromString('550e8400-e29b-41d4-a716-446655440000');\n *\n * @throws {InvalidValueObjectError} When the provided string is not a valid UUID format\n */\nexport class UUID extends PrimitiveValueObject<string> {\n private static readonly schema = z.uuid();\n\n public constructor(value: string) {\n super(value);\n this.validate(value);\n }\n\n /**\n * Creates an UUID from an external string.\n * Use only for untrusted input.\n *\n * @param value - UUID string\n */\n public static fromString(value: string): UUID {\n return new this(value);\n }\n\n /**\n * Generates a new AggregateId.\n */\n public static generate<T extends typeof UUID>(this: T): InstanceType<T> {\n return new this(v4()) as InstanceType<T>;\n }\n\n protected validate(value: string): void {\n const result = UUID.schema.safeParse(value);\n\n if (!result.success) {\n throw new InvalidValueObjectError(\n `Invalid UUID: ${result.error.message}`,\n );\n }\n }\n}\n","import { UUID } from './id.vo';\n\n/**\n * AggregateId represents a strongly-typed aggregate identifier.\n *\n * - Backed by UUID v4\n * - Immutable\n * - Comparable only to AggregateId\n */\nexport class AggregateId extends UUID {}\n","/**\n * HTTP status code catalog.\n *\n * This object provides a typed, immutable map of standard HTTP status names\n * to their numeric codes. Designed for server-side frameworks such as Fastify.\n *\n * - All identifiers use clear, canonical semantic names.\n * - Values are numeric status codes.\n * - Frozen to prevent runtime mutation.\n * - Exporting `HttpStatus` ensures type-safe usage across the codebase.\n * Usage:\n * ```ts\n * import { HttpStatus } from 'path-to-this-file';\n *\n * function handleRequest() {\n * return {\n * statusCode: HttpStatus.OK,\n * body: 'Success',\n * };\n * }\n * ```\n */\nexport const HttpStatus = Object.freeze({\n REQUEST_HEADER_FIELDS_TOO_LARGE: 431,\n NETWORK_AUTHENTICATION_REQUIRED: 511,\n NON_AUTHORITATIVE_INFORMATION: 203,\n PROXY_AUTHENTICATION_REQUIRED: 407,\n\n UNAVAILABLE_FOR_LEGAL_REASONS: 451,\n HTTP_VERSION_NOT_SUPPORTED: 505,\n BANDWIDTH_LIMIT_EXCEEDED: 509,\n VARIANT_ALSO_NEGOTIATES: 506,\n UNSUPPORTED_MEDIA_TYPE: 415,\n RANGE_NOT_SATISFIABLE: 416,\n PRECONDITION_REQUIRED: 428,\n INTERNAL_SERVER_ERROR: 500,\n UNPROCESSABLE_ENTITY: 422,\n INSUFFICIENT_STORAGE: 507,\n\n SWITCHING_PROTOCOLS: 101,\n PRECONDITION_FAILED: 412,\n MISDIRECTED_REQUEST: 421,\n SERVICE_UNAVAILABLE: 503,\n TEMPORARY_REDIRECT: 307,\n PERMANENT_REDIRECT: 308,\n METHOD_NOT_ALLOWED: 405,\n EXPECTATION_FAILED: 417,\n\n MOVED_PERMANENTLY: 301,\n PAYLOAD_TOO_LARGE: 413,\n FAILED_DEPENDENCY: 424,\n TOO_MANY_REQUESTS: 429,\n ALREADY_REPORTED: 208,\n MULTIPLE_CHOICES: 300,\n PAYMENT_REQUIRED: 402,\n UPGRADE_REQUIRED: 426,\n PARTIAL_CONTENT: 206,\n REQUEST_TIMEOUT: 408,\n LENGTH_REQUIRED: 411,\n NOT_IMPLEMENTED: 501,\n GATEWAY_TIMEOUT: 504,\n NOT_ACCEPTABLE: 406,\n RESET_CONTENT: 205,\n LOOP_DETECTED: 508,\n MULTI_STATUS: 207,\n NOT_MODIFIED: 304,\n UNAUTHORIZED: 401,\n URI_TOO_LONG: 414,\n NOT_EXTENDED: 510,\n EARLY_HINTS: 103,\n BAD_REQUEST: 400,\n IM_A_TEAPOT: 418,\n BAD_GATEWAY: 502,\n PROCESSING: 102,\n NO_CONTENT: 204,\n SEE_OTHER: 303,\n USE_PROXY: 305,\n\n FORBIDDEN: 403,\n NOT_FOUND: 404,\n TOO_EARLY: 425,\n CONTINUE: 100,\n ACCEPTED: 202,\n CONFLICT: 409,\n CREATED: 201,\n IM_USED: 226,\n LOCKED: 423,\n FOUND: 302,\n GONE: 410,\n OK: 200,\n} as const);\n\n/**\n * HTTP status messages mapped by numeric code.\n * Use for sending descriptive text in responses or logging.\n */\nexport const HttpStatusMessage = {\n 431: 'Request Header Fields Too Large',\n 511: 'Network Authentication Required',\n 203: 'Non-Authoritative Information',\n 407: 'Proxy Authentication Required',\n 451: 'Unavailable For Legal Reasons',\n 505: 'HTTP Version Not Supported',\n 509: 'Bandwidth Limit Exceeded',\n 506: 'Variant Also Negotiates',\n 415: 'Unsupported Media Type',\n 416: 'Range Not Satisfiable',\n 428: 'Precondition Required',\n 500: 'Internal Server Error',\n 422: 'Unprocessable Entity',\n 507: 'Insufficient Storage',\n 101: 'Switching Protocols',\n 412: 'Precondition Failed',\n 421: 'Misdirected Request',\n 503: 'Service Unavailable',\n 307: 'Temporary Redirect',\n 308: 'Permanent Redirect',\n 405: 'Method Not Allowed',\n 417: 'Expectation Failed',\n 301: 'Moved Permanently',\n 413: 'Payload Too Large',\n 424: 'Failed Dependency',\n 429: 'Too Many Requests',\n 208: 'Already Reported',\n 300: 'Multiple Choices',\n 402: 'Payment Required',\n 426: 'Upgrade Required',\n 206: 'Partial Content',\n 408: 'Request Timeout',\n 411: 'Length Required',\n 501: 'Not Implemented',\n 504: 'Gateway Timeout',\n 406: 'Not Acceptable',\n 205: 'Reset Content',\n 508: 'Loop Detected',\n 207: 'Multi-Status',\n 304: 'Not Modified',\n 401: 'Unauthorized',\n 414: 'URI Too Long',\n 418: \"I'm a Teapot\",\n 510: 'Not Extended',\n 103: 'Early Hints',\n 400: 'Bad Request',\n 502: 'Bad Gateway',\n 102: 'Processing',\n 204: 'No Content',\n 303: 'See Other',\n 305: 'Use Proxy',\n 403: 'Forbidden',\n 404: 'Not Found',\n 425: 'Too Early',\n 100: 'Continue',\n 202: 'Accepted',\n 226: \"I'm Used\",\n 409: 'Conflict',\n 201: 'Created',\n 423: 'Locked',\n 302: 'Found',\n 410: 'Gone',\n 200: 'OK',\n} as const;\n\nexport type HttpStatusCode = keyof typeof HttpStatusMessage;\n\nexport type HttpStatusMessage =\n (typeof HttpStatusMessage)[keyof typeof HttpStatusMessage];\n","/**\n * Base class for Domain violations.\n * Purposely does NOT extend native Error to avoid stack trace overhead in the domain.\n */\nexport abstract class DomainViolation {\n public abstract readonly code: string;\n public abstract readonly message: string;\n public readonly metadata: Readonly<Record<string, unknown>>;\n\n protected constructor(metadata: Record<string, unknown> = {}) {\n this.metadata = Object.freeze(metadata);\n }\n}\n","/**\n * Represents the outcome of an operation that can either succeed or fail,\n * without relying on exceptions for control flow.\n *\n * This pattern is commonly used in domain and application layers to make\n * success and failure states explicit, predictable, and type-safe.\n *\n * ## Design guarantees\n * - A `Result` is **immutable** once created.\n * - A `Result` is **exactly one of**:\n * - Success → contains a value\n * - Failure → contains an error\n * - Accessing the wrong side throws immediately (fail-fast).\n *\n * @typeParam T - Type of the success value\n * @typeParam E - Type of the failure error\n *\n * @example\n * ```ts\n * function parseNumber(input: string): Result<number, string> {\n * const value = Number(input);\n *\n * if (Number.isNaN(value)) {\n * return Result.fail('Invalid number');\n * }\n *\n * return Result.ok(value);\n * }\n *\n * const result = parseNumber('42');\n *\n * if (result.isSuccess) {\n * console.log(result.getValue()); // 42\n * } else {\n * console.error(result.getError());\n * }\n * ```\n */\nexport class Result<T, E> {\n /**\n * Indicates whether the result represents a failed outcome.\n *\n * This flag is mutually exclusive with {@link isSuccess}.\n */\n public readonly isFailure: boolean;\n /**\n * Indicates whether the result represents a successful outcome.\n *\n * This flag is mutually exclusive with {@link isFailure}.\n */\n public readonly isSuccess: boolean;\n\n /**\n * Creates a new {@link Result} instance.\n *\n * This constructor is private to enforce the use of\n * {@link Result.ok} and {@link Result.fail} factory methods,\n * preserving the success/failure invariants.\n *\n * @param _value - Success value (defined only for success results)\n * @param _error - Failure error (defined only for failure results)\n */\n private constructor(\n private readonly _value?: T,\n private readonly _error?: E,\n ) {\n this.isSuccess = _error === undefined;\n this.isFailure = !this.isSuccess;\n Object.freeze(this);\n }\n\n /**\n * Creates a failed {@link Result}.\n *\n * @param error - Error describing the failure\n * @returns A failure {@link Result} containing the provided error\n *\n * @example\n * ```ts\n * return Result.fail(new ValidationError('Email is invalid'));\n * ```\n */\n public static fail<T, E>(error: E): Result<T, E> {\n return new Result<T, E>(undefined, error);\n }\n\n /**\n * Creates a successful {@link Result}.\n *\n * @param value - Value representing a successful outcome\n * @returns A success {@link Result} containing the provided value\n *\n * @example\n * ```ts\n * return Result.ok(user);\n * ```\n */\n public static ok<T, E>(value: T): Result<T, E> {\n return new Result<T, E>(value);\n }\n\n /**\n * Returns the failure error.\n *\n * @returns The error associated with a failed result\n *\n * @throws {Error}\n * Thrown if this result represents a success.\n * This is a fail-fast guard against incorrect usage.\n *\n * @example\n * ```ts\n * if (result.isFailure) {\n * const error = result.getError();\n * }\n * ```\n */\n public getError(): E {\n if (this.isSuccess) {\n throw new Error('Result: Cannot get error of a success.');\n }\n\n return this._error as E;\n }\n\n /**\n * Returns the success value.\n *\n * @returns The value associated with a successful result\n *\n * @throws {Error}\n * Thrown if this result represents a failure.\n * This is a fail-fast guard against incorrect usage.\n *\n * @example\n * ```ts\n * if (result.isSuccess) {\n * const value = result.getValue();\n * }\n * ```\n */\n public getValue(): T {\n if (this.isFailure) {\n throw new Error('Result: Cannot get value of a failure.');\n }\n\n return this._value as T;\n }\n}\n","import {\n HttpStatusCode,\n HttpStatusMessage,\n} from '@/gateway/constants/http-code';\n\ninterface ErrorParams {\n message: string;\n code: HttpStatusMessage;\n status?: HttpStatusCode;\n metadata?: Record<string, unknown> | undefined;\n isOperational?: boolean;\n cause?: Error | undefined;\n}\n\n/**\n * Abstract base class for application-level errors with structured error handling.\n *\n * Extends the native Error class to provide machine-readable error codes, HTTP status codes,\n * operational error classification, and optional metadata for better error tracking and client communication.\n *\n * @abstract\n * @extends {Error}\n *\n * @example\n * ```typescript\n * class UserNotFoundError extends ApplicationError {\n * constructor(userId: string) {\n * super({\n * code: HttpStatusMessage['404'],\n * status: 404,\n * isOperational: true,\n * message: `User with id ${userId} not found`,\n * metadata: { userId }\n * });\n * }\n * }\n * ```\n */\nexport abstract class ApplicationError extends Error {\n /** Optional cause (linked error) */\n public readonly cause?: Error | undefined;\n /** Machine-readable error code (e.g. `OTP_LOCKED`, `USER_NOT_FOUND`) */\n public readonly code: HttpStatusMessage;\n /** Operational vs programmer error flag */\n public readonly isOperational: boolean;\n /** Optional structured metadata for debugging or clients */\n public readonly metadata?: Record<string, unknown> | undefined;\n /** HTTP status code intended for response layer */\n public readonly status: HttpStatusCode;\n\n constructor({\n code = HttpStatusMessage['500'],\n isOperational = false,\n status = 500,\n metadata,\n message,\n cause,\n }: ErrorParams) {\n super(message);\n\n this.name = new.target.name;\n this.code = code;\n this.status = status;\n this.isOperational = isOperational;\n this.metadata = metadata;\n this.cause = cause;\n\n Error.captureStackTrace(this, new.target);\n }\n}\n","import { ValueObject } from '@/domain/base/vo';\n\nexport type UnwrapValueObject<T> =\n T extends ValueObject<infer V>\n ? UnwrapValueObject<V>\n : T extends (infer U)[]\n ? UnwrapValueObject<U>[]\n : T extends Map<infer K, infer V>\n ? Map<K, UnwrapValueObject<V>>\n : T extends Set<infer V>\n ? Set<UnwrapValueObject<V>>\n : T extends Date\n ? string\n : T extends object\n ? { [K in keyof T]: UnwrapValueObject<T[K]> }\n : T;\n\nexport function unwrapValueObject<T>(\n input: T,\n seen = new WeakSet(),\n): UnwrapValueObject<T> {\n if (input === null || input === undefined) {\n return input as UnwrapValueObject<T>;\n }\n\n if (typeof input !== 'object') {\n return input as UnwrapValueObject<T>;\n }\n\n if (seen.has(input)) {\n // Prevent circular reference infinite recursion, just return input or throw\n throw new Error('Circular reference detected in ValueObject unwrap');\n }\n\n seen.add(input);\n\n if (Array.isArray(input)) {\n const result = input.map(item => unwrapValueObject(item, seen));\n seen.delete(input);\n return result as UnwrapValueObject<T>;\n }\n\n if (input instanceof ValueObject) {\n const result = unwrapValueObject(input.value, seen);\n seen.delete(input);\n return result as UnwrapValueObject<T>;\n }\n\n if (input instanceof Date) {\n seen.delete(input);\n return input.toISOString() as UnwrapValueObject<T>;\n }\n\n if (input instanceof Map) {\n const result = new Map();\n input.forEach((value, key) => {\n result.set(key, unwrapValueObject(value, seen));\n });\n seen.delete(input);\n return result as UnwrapValueObject<T>;\n }\n\n if (input instanceof Set) {\n const result = new Set(\n Array.from(input.values()).map(v => unwrapValueObject(v, seen)),\n );\n seen.delete(input);\n return result as UnwrapValueObject<T>;\n }\n\n // generic object\n const result: Record<string, unknown> = {};\n\n for (const key in input) {\n if (Object.hasOwn(input, key)) {\n result[key] = unwrapValueObject((input as any)[key], seen);\n }\n }\n\n seen.delete(input);\n return result as UnwrapValueObject<T>;\n}\n\nexport function ensureObject<T>(input: UnwrapValueObject<T>): object {\n if (input === null || input === undefined) {\n return {};\n }\n if (typeof input === 'object') {\n return input;\n }\n\n // for primitives, wrap inside object with default key (or throw)\n return { value: input };\n}\n"],"mappings":"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","names":["index_exports","__export","AggregateId","AggregateRoot","ApplicationError","DomainError","DomainEvent","DomainViolation","Entity","EntityValidationError","HttpStatus","HttpStatusMessage","InvalidValueObjectError","PrimitiveValueObject","Result","UUID","ValueObject","deepFreeze","ensureObject","unwrapValueObject","__toCommonJS","Entity","props","_a","other","AggregateRoot","Entity","domainEvent","events","getCauseInfo","cause","DomainError","message","code","metadata","__spreadValues","PrimitiveValueObject","value","other","import_es6","deepFreeze","obj","seen","item","key","ValueObject","_ValueObject","props","deepFreeze","vo","other","deepEqual","EntityValidationError","DomainError","message","cause","InvalidValueObjectError","DomainError","message","import_node_crypto","DomainEvent","props","_a","import_uuid","import_zod","_UUID","PrimitiveValueObject","value","result","InvalidValueObjectError","z","UUID","AggregateId","UUID","HttpStatus","HttpStatusMessage","DomainViolation","metadata","Result","_Result","_value","_error","error","value","ApplicationError","code","HttpStatusMessage","isOperational","status","metadata","message","cause","unwrapValueObject","input","seen","result","item","ValueObject","value","key","v","ensureObject"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/domain/entities/entity.ts","../src/domain/aggregates/aggregate-root.ts","../src/domain/base/domain.error.ts","../src/domain/base/primitive-vo.ts","../src/domain/base/vo.ts","../src/utils/deep-freeze.util.ts","../src/domain/errors/entity-validation.error.ts","../src/domain/errors/invalid-vo.error.ts","../src/domain/events/domain.event.ts","../src/domain/value-objects/id.vo.ts","../src/domain/value-objects/aggregate-id.vo.ts","../src/gateway/constants/http-code.ts","../src/utils/errors/application.error.ts","../src/utils/unwrap-vo.util.ts"],"sourcesContent":["export * from './application';\nexport * from './domain/aggregates';\nexport * from './domain/base/domain.error';\nexport * from './domain/base/primitive-vo';\nexport * from './domain/base/vo';\nexport * from './domain/entities';\nexport * from './domain/errors/entity-validation.error';\nexport * from './domain/errors/invalid-vo.error';\nexport * from './domain/events';\nexport * from './domain/types';\nexport * from './domain/value-objects/aggregate-id.vo';\nexport * from './domain/value-objects/id.vo';\nexport * from './gateway/constants/http-code';\nexport * from './utils';\n","import { EntityId } from '../types';\n\n/**\n * Configuration for the base Entity constructor.\n * Forces a single-object argument pattern to avoid positional argument errors.\n * @template ID - A type satisfying the EntityId interface.\n */\nexport interface EntityProps<ID extends EntityId, Props> {\n /** The unique identity of the entity */\n readonly id: ID;\n /** Optional creation timestamp; defaults to 'now' if not provided */\n readonly createdAt?: Date;\n\n readonly props: Props;\n}\n\n/**\n * Abstract Base Entity for Domain-Driven Design (DDD).\n * This class provides the standard contract for entity equality and identity.\n * It intentionally avoids \"magic\" property bags to ensure V8 engine optimization\n * and better IDE intellisense.\n * @template ID - The specific Identity Value Object type.\n */\nexport abstract class Entity<ID extends EntityId, Props> {\n /** The timestamp when this entity was first instantiated/created */\n public readonly createdAt: Date;\n /** The immutable unique identifier for this entity */\n public readonly id: ID;\n\n /**\n * Protected constructor to be called by subclasses.\n * @param props - Initial identity and metadata.\n */\n protected constructor(props: EntityProps<ID, Props>) {\n this.id = props.id;\n this.createdAt = props.createdAt ?? new Date();\n }\n\n /**\n * Compares entities by identity.\n * In DDD, two entities are considered equal if their IDs match,\n * regardless of their other properties.\n * @param other - The entity to compare against.\n * @returns True if IDs are equal.\n */\n public equals(other?: Entity<ID, Props>): boolean {\n if (other == null) return false;\n if (this === other) return true;\n return this.id.equals(other.id);\n }\n\n /**\n * Converts the Entity into a plain Javascript object.\n * Subclasses must implement this to explicitly control serialization,\n * @returns A plain object representation of the entity.\n */\n public abstract toObject(): Record<string, unknown>;\n\n /**\n * Validates the current state of the entity against domain invariants.\n * This method should be called after construction and any mutation.\n * @throws {Error} Should throw a specific DomainError if validation fails.\n */\n public abstract validate(): void;\n}\n","import { Entity, EntityProps } from '../entities/entity';\nimport { DomainEvent } from '../events';\nimport { EntityId } from '../types';\n\n/**\n * Interface for AggregateRoot to ensure type safety and extensibility.\n */\nexport interface Props<P> extends EntityProps<EntityId, P> {\n readonly domainEvents: readonly DomainEvent[];\n /**\n * Adds a domain event to the aggregate.\n * @param event The domain event to add.\n */\n addEvent: (event: DomainEvent) => void;\n\n /**\n * Retrieves and clears all domain events recorded by this aggregate.\n *\n * Domain events represent facts that occurred as a result of state changes\n * within the aggregate. This method transfers ownership of those events\n * to the application layer for further processing (e.g. publishing).\n *\n * Calling this method has the side effect of clearing the aggregate's\n * internal event collection to prevent duplicate handling.\n *\n * This method is intended to be invoked by application services\n * after the aggregate has been successfully persisted.\n *\n * @returns A read-only list of domain events raised by this aggregate.\n */\n pullDomainEvents: () => readonly DomainEvent[];\n}\n\n/**\n * Base class for aggregate roots in DDD, encapsulating domain events and validation.\n * @template EntityProps The type of the entity's properties.\n */\nexport abstract class AggregateRoot<ID extends EntityId, P> extends Entity<\n ID,\n P\n> {\n /**\n * Gets a read-only copy of the domain events.\n */\n get domainEvents(): readonly DomainEvent[] {\n return [...this._domainEvents];\n }\n\n /**\n * Internal list of domain events.\n */\n private readonly _domainEvents: DomainEvent[] = [];\n\n /**\n * Adds a domain event to the aggregate after validating invariants.\n * @param domainEvent The domain event to add.\n * @throws {EntityValidationError} If invariants are not met.\n */\n addEvent(domainEvent: DomainEvent): void {\n this._domainEvents.push(domainEvent);\n }\n\n public pullDomainEvents(): readonly DomainEvent[] {\n const events = [...this._domainEvents];\n this._domainEvents.length = 0;\n return events;\n }\n}\n","export interface DomainErrorMetadata {\n cause?: { name: string; message: string; stack?: string };\n [key: string]: unknown;\n}\n\nconst getCauseInfo = (cause: Error | undefined) => {\n // 1. Handle Error objects specifically\n if (cause instanceof Error) {\n return {\n cause: {\n message: cause.message,\n stack: cause.stack,\n name: cause.name,\n },\n };\n }\n\n // 2. Handle other existing values\n if (cause) {\n return { cause };\n }\n\n // 3. Default to empty\n return {};\n};\n\n/**\n * Base class for all Domain Errors in the application.\n *\n * This class ensures:\n * 1. Serializable and structured for logs or API responses.\n * 2. Identifiable via stable error codes (not just class names).\n * 3. Contextual with optional structured metadata.\n * 4. Supports error chaining (cause) and stack trace preservation.\n *\n * @example\n * export class InsufficientFundsError extends DomainError {\n * constructor(accountId: string, currentBalance: number) {\n * super(\n * `Account ${accountId} has insufficient funds.`,\n * 'INSUFFICIENT_FUNDS',\n * { accountId, currentBalance }\n * );\n * }\n * }\n */\nexport abstract class DomainError extends Error {\n /** Stable, machine-readable error code */\n public readonly code: string;\n /** Structured, immutable domain metadata */\n public readonly metadata: Readonly<DomainErrorMetadata>;\n\n /**\n * @param message - Human-readable error message\n * @param code - Stable error code\n * @param metadata - Domain-specific structured data; optional `cause` can be included\n */\n protected constructor(\n message: string,\n code: string,\n metadata: DomainErrorMetadata = {},\n ) {\n super(message, { ...getCauseInfo(metadata.cause) });\n\n // Restore prototype chain for proper `instanceof` checks\n Object.setPrototypeOf(this, new.target.prototype);\n\n this.name = new.target.name;\n this.code = code;\n this.metadata = Object.freeze({ ...metadata });\n }\n}\n","import { EntityId } from '../types';\n\ntype Primitive = boolean | number | string;\n\n/**\n * Base class for primitive-based Value Objects.\n *\n * This class is intended for Value Objects that are represented by\n * a single primitive value (string, number, or boolean).\n *\n * Characteristics:\n * - Immutable by construction\n * - Cheap equality comparison\n * - No deep cloning or freezing\n * - Safe for serialization and logging\n *\n * Examples:\n * - AggregateId\n * - EmailAddress\n * - Username\n * - Slug\n */\nexport abstract class PrimitiveValueObject<\n T extends Primitive,\n> implements EntityId {\n /**\n * The underlying primitive value.\n * Guaranteed to be valid after construction.\n */\n protected readonly value: T;\n\n /**\n * Constructs a new PrimitiveValueObject.\n *\n * @param value - The primitive value to wrap\n * @throws Error if validation fails\n */\n protected constructor(value: T) {\n this.validate(value);\n this.value = value;\n }\n\n /**\n * Compares two Value Objects for equality.\n *\n * Equality rules:\n * - Same concrete class\n * - Same primitive value (===)\n *\n * @param other - Another Value Object\n */\n public equals(other?: PrimitiveValueObject<T> | null | undefined): boolean {\n if (other === undefined || other === null) return false;\n\n if (Object.getPrototypeOf(this) !== Object.getPrototypeOf(other)) {\n return false;\n }\n\n return this.value === other.value;\n }\n\n /**\n * Returns the primitive value.\n * Prefer explicit access over implicit coercion.\n */\n public getValue(): T {\n return this.value;\n }\n\n /**\n * JSON serialization hook.\n * Produces the raw primitive value.\n */\n public toJSON(): T {\n return this.value;\n }\n\n /**\n * String representation.\n * Useful for logging and debugging.\n */\n public toString(): string {\n return String(this.value);\n }\n\n /**\n * Domain invariant validation.\n * Must throw if the value is invalid.\n *\n * @param value - The value to validate\n */\n protected abstract validate(value: T): void;\n}\n","import deepEqual from 'fast-deep-equal/es6';\n\nimport { deepFreeze } from '@/utils/deep-freeze.util';\n\nexport abstract class ValueObject<T> {\n get value(): T {\n return this.props;\n }\n\n protected readonly props: Readonly<T>;\n\n protected constructor(props: T) {\n this.validate(props);\n this.props = deepFreeze(props);\n }\n\n /**\n * Type guard to check if an unknown object is an instance of ValueObject.\n * This is useful for runtime type checking.\n *\n * @param vo The object to check.\n * @returns True if the object is a ValueObject instance, false otherwise.\n */\n public static is(vo: unknown): vo is ValueObject<unknown> {\n return vo instanceof ValueObject;\n }\n\n /**\n * Deep equality comparison of ValueObjects\n */\n public equals(other?: ValueObject<T>): boolean {\n if (other === null || other === undefined) return false;\n\n // Check if they share the same constructor (Type check)\n if (Object.getPrototypeOf(this) !== Object.getPrototypeOf(other)) {\n return false;\n }\n\n return deepEqual(this.props, other.props);\n }\n\n /**\n * Standard for clean API integration and logging.\n */\n public toJSON(): T {\n return this.props;\n }\n\n /**\n * Useful for debugging and string-based indexing.\n */\n public toString(): string {\n return JSON.stringify(this.props);\n }\n\n /**\n * Validates the value object props\n * @throws InvalidValueObjectError if validation fails\n */\n protected abstract validate(props: T): void;\n}\n","/**\n * Utility to deeply freeze objects to ensure immutability - handles nested objects and arrays.\n *\n * @param obj - The object to be deeply frozen.\n * @param seen - A WeakSet to track already processed objects (for circular references).\n * @returns A deeply frozen version of the input object.\n */\nexport function deepFreeze<T>(\n obj: T,\n seen = new WeakSet<object>(),\n): Readonly<T> {\n // Handle null, undefined, or non-object types\n if (obj == null || (typeof obj !== 'object' && !Array.isArray(obj))) {\n return obj;\n }\n\n // Skip if already frozen\n if (Object.isFrozen(obj)) {\n return obj as Readonly<T>;\n }\n\n // Handle circular references\n if (seen.has(obj as object)) {\n return obj as Readonly<T>;\n }\n\n seen.add(obj as object);\n\n // Handle arrays explicitly\n if (Array.isArray(obj)) {\n obj.forEach(item => deepFreeze(item, seen));\n } else {\n // Handle plain objects\n for (const key in obj) {\n if (Object.hasOwn(obj, key)) {\n deepFreeze((obj as Record<string, unknown>)[key], seen);\n }\n }\n }\n\n return Object.freeze(obj) as Readonly<T>;\n}\n","import { DomainError } from '../base/domain.error';\n\n/**\n * Custom error class for entity validation failures.\n */\nexport class EntityValidationError extends DomainError {\n constructor(message: string, cause?: Error) {\n super(message, 'ENTITY_VALIDATION_ERROR', { cause });\n }\n}\n","import { DomainError } from '../base/domain.error';\n\nexport class InvalidValueObjectError extends DomainError {\n constructor(message: string) {\n super(message, 'INVALID_VALUE_OBJECT');\n }\n}\n","import { randomUUID } from 'node:crypto';\n\nimport { EntityId } from '../types';\n\ntype Primitive = boolean | number | string | null;\n\ntype Serializable =\n | Primitive\n | Serializable[]\n | { [key: string]: Serializable };\n\nexport type DomainEventPayload = Record<string, Serializable>;\n\nexport type UnixTimestampMillis = number;\n\ntype DomainEventProps<AggregateId extends EntityId, Payload> = {\n id?: string;\n aggregateId: AggregateId;\n schemaVersion: number;\n occurredAt: UnixTimestampMillis;\n payload: Payload;\n};\n\n// Abstract base class for domain events\nexport abstract class DomainEvent<\n AggregateId extends EntityId = EntityId,\n T extends DomainEventPayload = DomainEventPayload,\n> {\n public readonly aggregateId: AggregateId;\n\n public abstract readonly eventName: string;\n public readonly id: string;\n public readonly occurredAt: number;\n public readonly payload: Readonly<T>;\n public readonly schemaVersion: number;\n\n protected constructor(props: DomainEventProps<AggregateId, T>) {\n this.id = props.id ?? randomUUID();\n this.aggregateId = props.aggregateId;\n this.schemaVersion = props.schemaVersion;\n this.occurredAt = props.occurredAt;\n this.payload = Object.freeze(props.payload);\n }\n\n public toPrimitives(): Readonly<{\n id: string;\n eventName: string;\n aggregateId: string;\n schemaVersion: number;\n occurredAt: UnixTimestampMillis;\n payload: T;\n }> {\n return {\n aggregateId: this.aggregateId.toString(),\n schemaVersion: this.schemaVersion,\n occurredAt: this.occurredAt,\n eventName: this.eventName,\n payload: this.payload,\n id: this.id,\n };\n }\n}\n","import { v4 } from 'uuid';\nimport z from 'zod';\n\nimport { InvalidValueObjectError } from '../errors/invalid-vo.error';\nimport { PrimitiveValueObject } from '../base/primitive-vo';\n\n/**\n * Represents a UUID (Universally Unique Identifier) value object.\n *\n * This class extends PrimitiveValueObject to provide type-safe UUID handling\n * with validation using Zod schema. UUIDs are immutable and can be generated\n * randomly or created from string values.\n *\n * @example\n * // Generate a new random UUID\n * const id = UUID.generate();\n *\n * @example\n * // Create UUID from an existing string\n * const id = UUID.fromString('550e8400-e29b-41d4-a716-446655440000');\n *\n * @throws {InvalidValueObjectError} When the provided string is not a valid UUID format\n */\nexport class UUID extends PrimitiveValueObject<string> {\n private static readonly schema = z.uuid();\n\n public constructor(value: string) {\n super(value);\n this.validate(value);\n }\n\n /**\n * Creates an UUID from an external string.\n * Use only for untrusted input.\n *\n * @param value - UUID string\n */\n public static fromString(value: string): UUID {\n return new this(value);\n }\n\n /**\n * Generates a new AggregateId.\n */\n public static generate<T extends typeof UUID>(this: T): InstanceType<T> {\n return new this(v4()) as InstanceType<T>;\n }\n\n protected validate(value: string): void {\n const result = UUID.schema.safeParse(value);\n\n if (!result.success) {\n throw new InvalidValueObjectError(\n `Invalid UUID: ${result.error.message}`,\n );\n }\n }\n}\n","import { UUID } from './id.vo';\n\n/**\n * AggregateId represents a strongly-typed aggregate identifier.\n *\n * - Backed by UUID v4\n * - Immutable\n * - Comparable only to AggregateId\n */\nexport class AggregateId extends UUID {}\n","/**\n * HTTP status code catalog.\n *\n * This object provides a typed, immutable map of standard HTTP status names\n * to their numeric codes. Designed for server-side frameworks such as Fastify.\n *\n * - All identifiers use clear, canonical semantic names.\n * - Values are numeric status codes.\n * - Frozen to prevent runtime mutation.\n * - Exporting `HttpStatus` ensures type-safe usage across the codebase.\n * Usage:\n * ```ts\n * import { HttpStatus } from 'path-to-this-file';\n *\n * function handleRequest() {\n * return {\n * statusCode: HttpStatus.OK,\n * body: 'Success',\n * };\n * }\n * ```\n */\nexport const HttpStatus = Object.freeze({\n REQUEST_HEADER_FIELDS_TOO_LARGE: 431,\n NETWORK_AUTHENTICATION_REQUIRED: 511,\n NON_AUTHORITATIVE_INFORMATION: 203,\n PROXY_AUTHENTICATION_REQUIRED: 407,\n\n UNAVAILABLE_FOR_LEGAL_REASONS: 451,\n HTTP_VERSION_NOT_SUPPORTED: 505,\n BANDWIDTH_LIMIT_EXCEEDED: 509,\n VARIANT_ALSO_NEGOTIATES: 506,\n UNSUPPORTED_MEDIA_TYPE: 415,\n RANGE_NOT_SATISFIABLE: 416,\n PRECONDITION_REQUIRED: 428,\n INTERNAL_SERVER_ERROR: 500,\n UNPROCESSABLE_ENTITY: 422,\n INSUFFICIENT_STORAGE: 507,\n\n SWITCHING_PROTOCOLS: 101,\n PRECONDITION_FAILED: 412,\n MISDIRECTED_REQUEST: 421,\n SERVICE_UNAVAILABLE: 503,\n TEMPORARY_REDIRECT: 307,\n PERMANENT_REDIRECT: 308,\n METHOD_NOT_ALLOWED: 405,\n EXPECTATION_FAILED: 417,\n\n MOVED_PERMANENTLY: 301,\n PAYLOAD_TOO_LARGE: 413,\n FAILED_DEPENDENCY: 424,\n TOO_MANY_REQUESTS: 429,\n ALREADY_REPORTED: 208,\n MULTIPLE_CHOICES: 300,\n PAYMENT_REQUIRED: 402,\n UPGRADE_REQUIRED: 426,\n PARTIAL_CONTENT: 206,\n REQUEST_TIMEOUT: 408,\n LENGTH_REQUIRED: 411,\n NOT_IMPLEMENTED: 501,\n GATEWAY_TIMEOUT: 504,\n NOT_ACCEPTABLE: 406,\n RESET_CONTENT: 205,\n LOOP_DETECTED: 508,\n MULTI_STATUS: 207,\n NOT_MODIFIED: 304,\n UNAUTHORIZED: 401,\n URI_TOO_LONG: 414,\n NOT_EXTENDED: 510,\n EARLY_HINTS: 103,\n BAD_REQUEST: 400,\n IM_A_TEAPOT: 418,\n BAD_GATEWAY: 502,\n PROCESSING: 102,\n NO_CONTENT: 204,\n SEE_OTHER: 303,\n USE_PROXY: 305,\n\n FORBIDDEN: 403,\n NOT_FOUND: 404,\n TOO_EARLY: 425,\n CONTINUE: 100,\n ACCEPTED: 202,\n CONFLICT: 409,\n CREATED: 201,\n IM_USED: 226,\n LOCKED: 423,\n FOUND: 302,\n GONE: 410,\n OK: 200,\n} as const);\n\n/**\n * HTTP status messages mapped by numeric code.\n * Use for sending descriptive text in responses or logging.\n */\nexport const HttpStatusMessage = {\n 431: 'Request Header Fields Too Large',\n 511: 'Network Authentication Required',\n 203: 'Non-Authoritative Information',\n 407: 'Proxy Authentication Required',\n 451: 'Unavailable For Legal Reasons',\n 505: 'HTTP Version Not Supported',\n 509: 'Bandwidth Limit Exceeded',\n 506: 'Variant Also Negotiates',\n 415: 'Unsupported Media Type',\n 416: 'Range Not Satisfiable',\n 428: 'Precondition Required',\n 500: 'Internal Server Error',\n 422: 'Unprocessable Entity',\n 507: 'Insufficient Storage',\n 101: 'Switching Protocols',\n 412: 'Precondition Failed',\n 421: 'Misdirected Request',\n 503: 'Service Unavailable',\n 307: 'Temporary Redirect',\n 308: 'Permanent Redirect',\n 405: 'Method Not Allowed',\n 417: 'Expectation Failed',\n 301: 'Moved Permanently',\n 413: 'Payload Too Large',\n 424: 'Failed Dependency',\n 429: 'Too Many Requests',\n 208: 'Already Reported',\n 300: 'Multiple Choices',\n 402: 'Payment Required',\n 426: 'Upgrade Required',\n 206: 'Partial Content',\n 408: 'Request Timeout',\n 411: 'Length Required',\n 501: 'Not Implemented',\n 504: 'Gateway Timeout',\n 406: 'Not Acceptable',\n 205: 'Reset Content',\n 508: 'Loop Detected',\n 207: 'Multi-Status',\n 304: 'Not Modified',\n 401: 'Unauthorized',\n 414: 'URI Too Long',\n 418: \"I'm a Teapot\",\n 510: 'Not Extended',\n 103: 'Early Hints',\n 400: 'Bad Request',\n 502: 'Bad Gateway',\n 102: 'Processing',\n 204: 'No Content',\n 303: 'See Other',\n 305: 'Use Proxy',\n 403: 'Forbidden',\n 404: 'Not Found',\n 425: 'Too Early',\n 100: 'Continue',\n 202: 'Accepted',\n 226: \"I'm Used\",\n 409: 'Conflict',\n 201: 'Created',\n 423: 'Locked',\n 302: 'Found',\n 410: 'Gone',\n 200: 'OK',\n} as const;\n\nexport type HttpStatusCode = keyof typeof HttpStatusMessage;\n\nexport type HttpStatusMessage =\n (typeof HttpStatusMessage)[keyof typeof HttpStatusMessage];\n","import {\n HttpStatusCode,\n HttpStatusMessage,\n} from '@/gateway/constants/http-code';\n\ninterface ErrorParams {\n message: string;\n code: HttpStatusMessage;\n status?: HttpStatusCode;\n metadata?: Record<string, unknown> | undefined;\n isOperational?: boolean;\n cause?: Error | undefined;\n}\n\n/**\n * Abstract base class for application-level errors with structured error handling.\n *\n * Extends the native Error class to provide machine-readable error codes, HTTP status codes,\n * operational error classification, and optional metadata for better error tracking and client communication.\n *\n * @abstract\n * @extends {Error}\n *\n * @example\n * ```typescript\n * class UserNotFoundError extends ApplicationError {\n * constructor(userId: string) {\n * super({\n * code: HttpStatusMessage['404'],\n * status: 404,\n * isOperational: true,\n * message: `User with id ${userId} not found`,\n * metadata: { userId }\n * });\n * }\n * }\n * ```\n */\nexport abstract class ApplicationError extends Error {\n /** Optional cause (linked error) */\n public readonly cause?: Error | undefined;\n /** Machine-readable error code (e.g. `OTP_LOCKED`, `USER_NOT_FOUND`) */\n public readonly code: HttpStatusMessage;\n /** Operational vs programmer error flag */\n public readonly isOperational: boolean;\n /** Optional structured metadata for debugging or clients */\n public readonly metadata?: Record<string, unknown> | undefined;\n /** HTTP status code intended for response layer */\n public readonly status: HttpStatusCode;\n\n constructor({\n code = HttpStatusMessage['500'],\n isOperational = false,\n status = 500,\n metadata,\n message,\n cause,\n }: ErrorParams) {\n super(message);\n\n this.name = new.target.name;\n this.code = code;\n this.status = status;\n this.isOperational = isOperational;\n this.metadata = metadata;\n this.cause = cause;\n\n Error.captureStackTrace(this, new.target);\n }\n}\n","import { ValueObject } from '@/domain/base/vo';\n\nexport type UnwrapValueObject<T> =\n T extends ValueObject<infer V>\n ? UnwrapValueObject<V>\n : T extends (infer U)[]\n ? UnwrapValueObject<U>[]\n : T extends Map<infer K, infer V>\n ? Map<K, UnwrapValueObject<V>>\n : T extends Set<infer V>\n ? Set<UnwrapValueObject<V>>\n : T extends Date\n ? string\n : T extends object\n ? { [K in keyof T]: UnwrapValueObject<T[K]> }\n : T;\n\nexport function unwrapValueObject<T>(\n input: T,\n seen = new WeakSet(),\n): UnwrapValueObject<T> {\n if (input === null || input === undefined) {\n return input as UnwrapValueObject<T>;\n }\n\n if (typeof input !== 'object') {\n return input as UnwrapValueObject<T>;\n }\n\n if (seen.has(input)) {\n // Prevent circular reference infinite recursion, just return input or throw\n throw new Error('Circular reference detected in ValueObject unwrap');\n }\n\n seen.add(input);\n\n if (Array.isArray(input)) {\n const result = input.map(item => unwrapValueObject(item, seen));\n seen.delete(input);\n return result as UnwrapValueObject<T>;\n }\n\n if (input instanceof ValueObject) {\n const result = unwrapValueObject(input.value, seen);\n seen.delete(input);\n return result as UnwrapValueObject<T>;\n }\n\n if (input instanceof Date) {\n seen.delete(input);\n return input.toISOString() as UnwrapValueObject<T>;\n }\n\n if (input instanceof Map) {\n const result = new Map();\n input.forEach((value, key) => {\n result.set(key, unwrapValueObject(value, seen));\n });\n seen.delete(input);\n return result as UnwrapValueObject<T>;\n }\n\n if (input instanceof Set) {\n const result = new Set(\n Array.from(input.values()).map(v => unwrapValueObject(v, seen)),\n );\n seen.delete(input);\n return result as UnwrapValueObject<T>;\n }\n\n // generic object\n const result: Record<string, unknown> = {};\n\n for (const key in input) {\n if (Object.hasOwn(input, key)) {\n result[key] = unwrapValueObject((input as any)[key], seen);\n }\n }\n\n seen.delete(input);\n return result as UnwrapValueObject<T>;\n}\n\nexport function ensureObject<T>(input: UnwrapValueObject<T>): object {\n if (input === null || input === undefined) {\n return {};\n }\n if (typeof input === 'object') {\n return input;\n }\n\n // for primitives, wrap inside object with default key (or throw)\n return { value: input };\n}\n"],"mappings":"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","names":["index_exports","__export","AggregateId","AggregateRoot","ApplicationError","DomainError","DomainEvent","Entity","EntityValidationError","HttpStatus","HttpStatusMessage","InvalidValueObjectError","PrimitiveValueObject","UUID","ValueObject","deepFreeze","ensureObject","unwrapValueObject","__toCommonJS","Entity","props","_a","other","AggregateRoot","Entity","domainEvent","events","getCauseInfo","cause","DomainError","message","code","metadata","__spreadValues","PrimitiveValueObject","value","other","import_es6","deepFreeze","obj","seen","item","key","ValueObject","_ValueObject","props","deepFreeze","vo","other","deepEqual","EntityValidationError","DomainError","message","cause","InvalidValueObjectError","DomainError","message","import_node_crypto","DomainEvent","props","_a","import_uuid","import_zod","_UUID","PrimitiveValueObject","value","result","InvalidValueObjectError","z","UUID","AggregateId","UUID","HttpStatus","HttpStatusMessage","ApplicationError","code","HttpStatusMessage","isOperational","status","metadata","message","cause","unwrapValueObject","input","seen","result","item","ValueObject","value","key","v","ensureObject"]}
|
package/dist/index.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var
|
|
1
|
+
var N=Object.defineProperty;var O=Object.getOwnPropertySymbols;var _=Object.prototype.hasOwnProperty,S=Object.prototype.propertyIsEnumerable;var f=(t,e,r)=>e in t?N(t,e,{enumerable:!0,configurable:!0,writable:!0,value:r}):t[e]=r,m=(t,e)=>{for(var r in e||(e={}))_.call(e,r)&&f(t,r,e[r]);if(O)for(var r of O(e))S.call(e,r)&&f(t,r,e[r]);return t};var s=class{constructor(e){var r;this.id=e.id,this.createdAt=(r=e.createdAt)!=null?r:new Date}equals(e){return e==null?!1:this===e?!0:this.id.equals(e.id)}};var y=class extends s{constructor(){super(...arguments);this._domainEvents=[]}get domainEvents(){return[...this._domainEvents]}addEvent(r){this._domainEvents.push(r)}pullDomainEvents(){let r=[...this._domainEvents];return this._domainEvents.length=0,r}};var P=t=>t instanceof Error?{cause:{message:t.message,stack:t.stack,name:t.name}}:t?{cause:t}:{},o=class extends Error{constructor(e,r,a={}){super(e,m({},P(a.cause))),Object.setPrototypeOf(this,new.target.prototype),this.name=new.target.name,this.code=r,this.metadata=Object.freeze(m({},a))}};var d=class{constructor(e){this.validate(e),this.value=e}equals(e){return e==null||Object.getPrototypeOf(this)!==Object.getPrototypeOf(e)?!1:this.value===e.value}getValue(){return this.value}toJSON(){return this.value}toString(){return String(this.value)}};import U from"fast-deep-equal/es6";function c(t,e=new WeakSet){if(t==null||typeof t!="object"&&!Array.isArray(t)||Object.isFrozen(t)||e.has(t))return t;if(e.add(t),Array.isArray(t))t.forEach(r=>c(r,e));else for(let r in t)Object.hasOwn(t,r)&&c(t[r],e);return Object.freeze(t)}var l=class t{get value(){return this.props}constructor(e){this.validate(e),this.props=c(e)}static is(e){return e instanceof t}equals(e){return e==null||Object.getPrototypeOf(this)!==Object.getPrototypeOf(e)?!1:U(this.props,e.props)}toJSON(){return this.props}toString(){return JSON.stringify(this.props)}};var I=class extends o{constructor(e,r){super(e,"ENTITY_VALIDATION_ERROR",{cause:r})}};var u=class extends o{constructor(e){super(e,"INVALID_VALUE_OBJECT")}};import{randomUUID as h}from"crypto";var g=class{constructor(e){var r;this.id=(r=e.id)!=null?r:h(),this.aggregateId=e.aggregateId,this.schemaVersion=e.schemaVersion,this.occurredAt=e.occurredAt,this.payload=Object.freeze(e.payload)}toPrimitives(){return{aggregateId:this.aggregateId.toString(),schemaVersion:this.schemaVersion,occurredAt:this.occurredAt,eventName:this.eventName,payload:this.payload,id:this.id}}};import{v4 as v}from"uuid";import x from"zod";var p=class p extends d{constructor(e){super(e),this.validate(e)}static fromString(e){return new this(e)}static generate(){return new this(v())}validate(e){let r=p.schema.safeParse(e);if(!r.success)throw new u(`Invalid UUID: ${r.error.message}`)}};p.schema=x.uuid();var E=p;var R=class extends E{};var ne=Object.freeze({REQUEST_HEADER_FIELDS_TOO_LARGE:431,NETWORK_AUTHENTICATION_REQUIRED:511,NON_AUTHORITATIVE_INFORMATION:203,PROXY_AUTHENTICATION_REQUIRED:407,UNAVAILABLE_FOR_LEGAL_REASONS:451,HTTP_VERSION_NOT_SUPPORTED:505,BANDWIDTH_LIMIT_EXCEEDED:509,VARIANT_ALSO_NEGOTIATES:506,UNSUPPORTED_MEDIA_TYPE:415,RANGE_NOT_SATISFIABLE:416,PRECONDITION_REQUIRED:428,INTERNAL_SERVER_ERROR:500,UNPROCESSABLE_ENTITY:422,INSUFFICIENT_STORAGE:507,SWITCHING_PROTOCOLS:101,PRECONDITION_FAILED:412,MISDIRECTED_REQUEST:421,SERVICE_UNAVAILABLE:503,TEMPORARY_REDIRECT:307,PERMANENT_REDIRECT:308,METHOD_NOT_ALLOWED:405,EXPECTATION_FAILED:417,MOVED_PERMANENTLY:301,PAYLOAD_TOO_LARGE:413,FAILED_DEPENDENCY:424,TOO_MANY_REQUESTS:429,ALREADY_REPORTED:208,MULTIPLE_CHOICES:300,PAYMENT_REQUIRED:402,UPGRADE_REQUIRED:426,PARTIAL_CONTENT:206,REQUEST_TIMEOUT:408,LENGTH_REQUIRED:411,NOT_IMPLEMENTED:501,GATEWAY_TIMEOUT:504,NOT_ACCEPTABLE:406,RESET_CONTENT:205,LOOP_DETECTED:508,MULTI_STATUS:207,NOT_MODIFIED:304,UNAUTHORIZED:401,URI_TOO_LONG:414,NOT_EXTENDED:510,EARLY_HINTS:103,BAD_REQUEST:400,IM_A_TEAPOT:418,BAD_GATEWAY:502,PROCESSING:102,NO_CONTENT:204,SEE_OTHER:303,USE_PROXY:305,FORBIDDEN:403,NOT_FOUND:404,TOO_EARLY:425,CONTINUE:100,ACCEPTED:202,CONFLICT:409,CREATED:201,IM_USED:226,LOCKED:423,FOUND:302,GONE:410,OK:200}),b={431:"Request Header Fields Too Large",511:"Network Authentication Required",203:"Non-Authoritative Information",407:"Proxy Authentication Required",451:"Unavailable For Legal Reasons",505:"HTTP Version Not Supported",509:"Bandwidth Limit Exceeded",506:"Variant Also Negotiates",415:"Unsupported Media Type",416:"Range Not Satisfiable",428:"Precondition Required",500:"Internal Server Error",422:"Unprocessable Entity",507:"Insufficient Storage",101:"Switching Protocols",412:"Precondition Failed",421:"Misdirected Request",503:"Service Unavailable",307:"Temporary Redirect",308:"Permanent Redirect",405:"Method Not Allowed",417:"Expectation Failed",301:"Moved Permanently",413:"Payload Too Large",424:"Failed Dependency",429:"Too Many Requests",208:"Already Reported",300:"Multiple Choices",402:"Payment Required",426:"Upgrade Required",206:"Partial Content",408:"Request Timeout",411:"Length Required",501:"Not Implemented",504:"Gateway Timeout",406:"Not Acceptable",205:"Reset Content",508:"Loop Detected",207:"Multi-Status",304:"Not Modified",401:"Unauthorized",414:"URI Too Long",418:"I'm a Teapot",510:"Not Extended",103:"Early Hints",400:"Bad Request",502:"Bad Gateway",102:"Processing",204:"No Content",303:"See Other",305:"Use Proxy",403:"Forbidden",404:"Not Found",425:"Too Early",100:"Continue",202:"Accepted",226:"I'm Used",409:"Conflict",201:"Created",423:"Locked",302:"Found",410:"Gone",200:"OK"};var A=class extends Error{constructor({code:e=b[500],isOperational:r=!1,status:a=500,metadata:n,message:T,cause:D}){super(T),this.name=new.target.name,this.code=e,this.status=a,this.isOperational=r,this.metadata=n,this.cause=D,Error.captureStackTrace(this,new.target)}};function i(t,e=new WeakSet){if(t==null||typeof t!="object")return t;if(e.has(t))throw new Error("Circular reference detected in ValueObject unwrap");if(e.add(t),Array.isArray(t)){let a=t.map(n=>i(n,e));return e.delete(t),a}if(t instanceof l){let a=i(t.value,e);return e.delete(t),a}if(t instanceof Date)return e.delete(t),t.toISOString();if(t instanceof Map){let a=new Map;return t.forEach((n,T)=>{a.set(T,i(n,e))}),e.delete(t),a}if(t instanceof Set){let a=new Set(Array.from(t.values()).map(n=>i(n,e)));return e.delete(t),a}let r={};for(let a in t)Object.hasOwn(t,a)&&(r[a]=i(t[a],e));return e.delete(t),r}function le(t){return t==null?{}:typeof t=="object"?t:{value:t}}export{R as AggregateId,y as AggregateRoot,A as ApplicationError,o as DomainError,g as DomainEvent,s as Entity,I as EntityValidationError,ne as HttpStatus,b as HttpStatusMessage,u as InvalidValueObjectError,d as PrimitiveValueObject,E as UUID,l as ValueObject,c as deepFreeze,le as ensureObject,i as unwrapValueObject};
|
|
2
2
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/domain/entities/entity.ts","../src/domain/aggregates/aggregate-root.ts","../src/domain/base/domain.error.ts","../src/domain/base/primitive-vo.ts","../src/domain/base/vo.ts","../src/utils/deep-freeze.util.ts","../src/domain/errors/entity-validation.error.ts","../src/domain/errors/invalid-vo.error.ts","../src/domain/events/domain.event.ts","../src/domain/value-objects/id.vo.ts","../src/domain/value-objects/aggregate-id.vo.ts","../src/gateway/constants/http-code.ts","../src/shared/domain/domain.violation.ts","../src/shared/domain/result.ts","../src/utils/errors/application.error.ts","../src/utils/unwrap-vo.util.ts"],"sourcesContent":["import { EntityId } from '../types';\n\n/**\n * Configuration for the base Entity constructor.\n * Forces a single-object argument pattern to avoid positional argument errors.\n * @template ID - A type satisfying the EntityId interface.\n */\nexport interface EntityProps<ID extends EntityId, Props> {\n /** The unique identity of the entity */\n readonly id: ID;\n /** Optional creation timestamp; defaults to 'now' if not provided */\n readonly createdAt?: Date;\n\n readonly props: Props;\n}\n\n/**\n * Abstract Base Entity for Domain-Driven Design (DDD).\n * This class provides the standard contract for entity equality and identity.\n * It intentionally avoids \"magic\" property bags to ensure V8 engine optimization\n * and better IDE intellisense.\n * @template ID - The specific Identity Value Object type.\n */\nexport abstract class Entity<ID extends EntityId, Props> {\n /** The timestamp when this entity was first instantiated/created */\n public readonly createdAt: Date;\n /** The immutable unique identifier for this entity */\n public readonly id: ID;\n\n /**\n * Protected constructor to be called by subclasses.\n * @param props - Initial identity and metadata.\n */\n protected constructor(props: EntityProps<ID, Props>) {\n this.id = props.id;\n this.createdAt = props.createdAt ?? new Date();\n }\n\n /**\n * Compares entities by identity.\n * In DDD, two entities are considered equal if their IDs match,\n * regardless of their other properties.\n * @param other - The entity to compare against.\n * @returns True if IDs are equal.\n */\n public equals(other?: Entity<ID, Props>): boolean {\n if (other == null) return false;\n if (this === other) return true;\n return this.id.equals(other.id);\n }\n\n /**\n * Converts the Entity into a plain Javascript object.\n * Subclasses must implement this to explicitly control serialization,\n * @returns A plain object representation of the entity.\n */\n public abstract toObject(): Record<string, unknown>;\n\n /**\n * Validates the current state of the entity against domain invariants.\n * This method should be called after construction and any mutation.\n * @throws {Error} Should throw a specific DomainError if validation fails.\n */\n public abstract validate(): void;\n}\n","import { Entity, EntityProps } from '../entities/entity';\nimport { DomainEvent } from '../events';\nimport { EntityId } from '../types';\n\n/**\n * Interface for AggregateRoot to ensure type safety and extensibility.\n */\nexport interface Props<P> extends EntityProps<EntityId, P> {\n readonly domainEvents: readonly DomainEvent[];\n /**\n * Adds a domain event to the aggregate.\n * @param event The domain event to add.\n */\n addEvent: (event: DomainEvent) => void;\n\n /**\n * Retrieves and clears all domain events recorded by this aggregate.\n *\n * Domain events represent facts that occurred as a result of state changes\n * within the aggregate. This method transfers ownership of those events\n * to the application layer for further processing (e.g. publishing).\n *\n * Calling this method has the side effect of clearing the aggregate's\n * internal event collection to prevent duplicate handling.\n *\n * This method is intended to be invoked by application services\n * after the aggregate has been successfully persisted.\n *\n * @returns A read-only list of domain events raised by this aggregate.\n */\n pullDomainEvents: () => readonly DomainEvent[];\n}\n\n/**\n * Base class for aggregate roots in DDD, encapsulating domain events and validation.\n * @template EntityProps The type of the entity's properties.\n */\nexport abstract class AggregateRoot<ID extends EntityId, P> extends Entity<\n ID,\n P\n> {\n /**\n * Gets a read-only copy of the domain events.\n */\n get domainEvents(): readonly DomainEvent[] {\n return [...this._domainEvents];\n }\n\n /**\n * Internal list of domain events.\n */\n private readonly _domainEvents: DomainEvent[] = [];\n\n /**\n * Adds a domain event to the aggregate after validating invariants.\n * @param domainEvent The domain event to add.\n * @throws {EntityValidationError} If invariants are not met.\n */\n addEvent(domainEvent: DomainEvent): void {\n this._domainEvents.push(domainEvent);\n }\n\n public pullDomainEvents(): readonly DomainEvent[] {\n const events = [...this._domainEvents];\n this._domainEvents.length = 0;\n return events;\n }\n}\n","export interface DomainErrorMetadata {\n cause?: { name: string; message: string; stack?: string };\n [key: string]: unknown;\n}\n\nconst getCauseInfo = (cause: Error | undefined) => {\n // 1. Handle Error objects specifically\n if (cause instanceof Error) {\n return {\n cause: {\n message: cause.message,\n stack: cause.stack,\n name: cause.name,\n },\n };\n }\n\n // 2. Handle other existing values\n if (cause) {\n return { cause };\n }\n\n // 3. Default to empty\n return {};\n};\n\n/**\n * Base class for all Domain Errors in the application.\n *\n * This class ensures:\n * 1. Serializable and structured for logs or API responses.\n * 2. Identifiable via stable error codes (not just class names).\n * 3. Contextual with optional structured metadata.\n * 4. Supports error chaining (cause) and stack trace preservation.\n *\n * @example\n * export class InsufficientFundsError extends DomainError {\n * constructor(accountId: string, currentBalance: number) {\n * super(\n * `Account ${accountId} has insufficient funds.`,\n * 'INSUFFICIENT_FUNDS',\n * { accountId, currentBalance }\n * );\n * }\n * }\n */\nexport abstract class DomainError extends Error {\n /** Stable, machine-readable error code */\n public readonly code: string;\n /** Structured, immutable domain metadata */\n public readonly metadata: Readonly<DomainErrorMetadata>;\n\n /**\n * @param message - Human-readable error message\n * @param code - Stable error code\n * @param metadata - Domain-specific structured data; optional `cause` can be included\n */\n protected constructor(\n message: string,\n code: string,\n metadata: DomainErrorMetadata = {},\n ) {\n super(message, { ...getCauseInfo(metadata.cause) });\n\n // Restore prototype chain for proper `instanceof` checks\n Object.setPrototypeOf(this, new.target.prototype);\n\n this.name = new.target.name;\n this.code = code;\n this.metadata = Object.freeze({ ...metadata });\n }\n}\n","import { EntityId } from '../types';\n\ntype Primitive = boolean | number | string;\n\n/**\n * Base class for primitive-based Value Objects.\n *\n * This class is intended for Value Objects that are represented by\n * a single primitive value (string, number, or boolean).\n *\n * Characteristics:\n * - Immutable by construction\n * - Cheap equality comparison\n * - No deep cloning or freezing\n * - Safe for serialization and logging\n *\n * Examples:\n * - AggregateId\n * - EmailAddress\n * - Username\n * - Slug\n */\nexport abstract class PrimitiveValueObject<\n T extends Primitive,\n> implements EntityId {\n /**\n * The underlying primitive value.\n * Guaranteed to be valid after construction.\n */\n protected readonly value: T;\n\n /**\n * Constructs a new PrimitiveValueObject.\n *\n * @param value - The primitive value to wrap\n * @throws Error if validation fails\n */\n protected constructor(value: T) {\n this.validate(value);\n this.value = value;\n }\n\n /**\n * Compares two Value Objects for equality.\n *\n * Equality rules:\n * - Same concrete class\n * - Same primitive value (===)\n *\n * @param other - Another Value Object\n */\n public equals(other?: PrimitiveValueObject<T> | null | undefined): boolean {\n if (other === undefined || other === null) return false;\n\n if (Object.getPrototypeOf(this) !== Object.getPrototypeOf(other)) {\n return false;\n }\n\n return this.value === other.value;\n }\n\n /**\n * Returns the primitive value.\n * Prefer explicit access over implicit coercion.\n */\n public getValue(): T {\n return this.value;\n }\n\n /**\n * JSON serialization hook.\n * Produces the raw primitive value.\n */\n public toJSON(): T {\n return this.value;\n }\n\n /**\n * String representation.\n * Useful for logging and debugging.\n */\n public toString(): string {\n return String(this.value);\n }\n\n /**\n * Domain invariant validation.\n * Must throw if the value is invalid.\n *\n * @param value - The value to validate\n */\n protected abstract validate(value: T): void;\n}\n","import deepEqual from 'fast-deep-equal/es6';\n\nimport { deepFreeze } from '@/utils/deep-freeze.util';\n\nexport abstract class ValueObject<T> {\n get value(): T {\n return this.props;\n }\n\n protected readonly props: Readonly<T>;\n\n protected constructor(props: T) {\n this.validate(props);\n this.props = deepFreeze(props);\n }\n\n /**\n * Type guard to check if an unknown object is an instance of ValueObject.\n * This is useful for runtime type checking.\n *\n * @param vo The object to check.\n * @returns True if the object is a ValueObject instance, false otherwise.\n */\n public static is(vo: unknown): vo is ValueObject<unknown> {\n return vo instanceof ValueObject;\n }\n\n /**\n * Deep equality comparison of ValueObjects\n */\n public equals(other?: ValueObject<T>): boolean {\n if (other === null || other === undefined) return false;\n\n // Check if they share the same constructor (Type check)\n if (Object.getPrototypeOf(this) !== Object.getPrototypeOf(other)) {\n return false;\n }\n\n return deepEqual(this.props, other.props);\n }\n\n /**\n * Standard for clean API integration and logging.\n */\n public toJSON(): T {\n return this.props;\n }\n\n /**\n * Useful for debugging and string-based indexing.\n */\n public toString(): string {\n return JSON.stringify(this.props);\n }\n\n /**\n * Validates the value object props\n * @throws InvalidValueObjectError if validation fails\n */\n protected abstract validate(props: T): void;\n}\n","/**\n * Utility to deeply freeze objects to ensure immutability - handles nested objects and arrays.\n *\n * @param obj - The object to be deeply frozen.\n * @param seen - A WeakSet to track already processed objects (for circular references).\n * @returns A deeply frozen version of the input object.\n */\nexport function deepFreeze<T>(\n obj: T,\n seen = new WeakSet<object>(),\n): Readonly<T> {\n // Handle null, undefined, or non-object types\n if (obj == null || (typeof obj !== 'object' && !Array.isArray(obj))) {\n return obj;\n }\n\n // Skip if already frozen\n if (Object.isFrozen(obj)) {\n return obj as Readonly<T>;\n }\n\n // Handle circular references\n if (seen.has(obj as object)) {\n return obj as Readonly<T>;\n }\n\n seen.add(obj as object);\n\n // Handle arrays explicitly\n if (Array.isArray(obj)) {\n obj.forEach(item => deepFreeze(item, seen));\n } else {\n // Handle plain objects\n for (const key in obj) {\n if (Object.hasOwn(obj, key)) {\n deepFreeze((obj as Record<string, unknown>)[key], seen);\n }\n }\n }\n\n return Object.freeze(obj) as Readonly<T>;\n}\n","import { DomainError } from '../base/domain.error';\n\n/**\n * Custom error class for entity validation failures.\n */\nexport class EntityValidationError extends DomainError {\n constructor(message: string, cause?: Error) {\n super(message, 'ENTITY_VALIDATION_ERROR', { cause });\n }\n}\n","import { DomainError } from '../base/domain.error';\n\nexport class InvalidValueObjectError extends DomainError {\n constructor(message: string) {\n super(message, 'INVALID_VALUE_OBJECT');\n }\n}\n","import { randomUUID } from 'node:crypto';\n\nimport { EntityId } from '../types';\n\ntype Primitive = boolean | number | string | null;\n\ntype Serializable =\n | Primitive\n | Serializable[]\n | { [key: string]: Serializable };\n\nexport type DomainEventPayload = Record<string, Serializable>;\n\nexport type UnixTimestampMillis = number;\n\ntype DomainEventProps<AggregateId extends EntityId, Payload> = {\n id?: string;\n aggregateId: AggregateId;\n schemaVersion: number;\n occurredAt: UnixTimestampMillis;\n payload: Payload;\n};\n\n// Abstract base class for domain events\nexport abstract class DomainEvent<\n AggregateId extends EntityId = EntityId,\n T extends DomainEventPayload = DomainEventPayload,\n> {\n public readonly aggregateId: AggregateId;\n\n public abstract readonly eventName: string;\n public readonly id: string;\n public readonly occurredAt: number;\n public readonly payload: Readonly<T>;\n public readonly schemaVersion: number;\n\n protected constructor(props: DomainEventProps<AggregateId, T>) {\n this.id = props.id ?? randomUUID();\n this.aggregateId = props.aggregateId;\n this.schemaVersion = props.schemaVersion;\n this.occurredAt = props.occurredAt;\n this.payload = Object.freeze(props.payload);\n }\n\n public toPrimitives(): Readonly<{\n id: string;\n eventName: string;\n aggregateId: string;\n schemaVersion: number;\n occurredAt: UnixTimestampMillis;\n payload: T;\n }> {\n return {\n aggregateId: this.aggregateId.toString(),\n schemaVersion: this.schemaVersion,\n occurredAt: this.occurredAt,\n eventName: this.eventName,\n payload: this.payload,\n id: this.id,\n };\n }\n}\n","import { v4 } from 'uuid';\nimport z from 'zod';\n\nimport { InvalidValueObjectError } from '../errors/invalid-vo.error';\nimport { PrimitiveValueObject } from '../base/primitive-vo';\n\n/**\n * Represents a UUID (Universally Unique Identifier) value object.\n *\n * This class extends PrimitiveValueObject to provide type-safe UUID handling\n * with validation using Zod schema. UUIDs are immutable and can be generated\n * randomly or created from string values.\n *\n * @example\n * // Generate a new random UUID\n * const id = UUID.generate();\n *\n * @example\n * // Create UUID from an existing string\n * const id = UUID.fromString('550e8400-e29b-41d4-a716-446655440000');\n *\n * @throws {InvalidValueObjectError} When the provided string is not a valid UUID format\n */\nexport class UUID extends PrimitiveValueObject<string> {\n private static readonly schema = z.uuid();\n\n public constructor(value: string) {\n super(value);\n this.validate(value);\n }\n\n /**\n * Creates an UUID from an external string.\n * Use only for untrusted input.\n *\n * @param value - UUID string\n */\n public static fromString(value: string): UUID {\n return new this(value);\n }\n\n /**\n * Generates a new AggregateId.\n */\n public static generate<T extends typeof UUID>(this: T): InstanceType<T> {\n return new this(v4()) as InstanceType<T>;\n }\n\n protected validate(value: string): void {\n const result = UUID.schema.safeParse(value);\n\n if (!result.success) {\n throw new InvalidValueObjectError(\n `Invalid UUID: ${result.error.message}`,\n );\n }\n }\n}\n","import { UUID } from './id.vo';\n\n/**\n * AggregateId represents a strongly-typed aggregate identifier.\n *\n * - Backed by UUID v4\n * - Immutable\n * - Comparable only to AggregateId\n */\nexport class AggregateId extends UUID {}\n","/**\n * HTTP status code catalog.\n *\n * This object provides a typed, immutable map of standard HTTP status names\n * to their numeric codes. Designed for server-side frameworks such as Fastify.\n *\n * - All identifiers use clear, canonical semantic names.\n * - Values are numeric status codes.\n * - Frozen to prevent runtime mutation.\n * - Exporting `HttpStatus` ensures type-safe usage across the codebase.\n * Usage:\n * ```ts\n * import { HttpStatus } from 'path-to-this-file';\n *\n * function handleRequest() {\n * return {\n * statusCode: HttpStatus.OK,\n * body: 'Success',\n * };\n * }\n * ```\n */\nexport const HttpStatus = Object.freeze({\n REQUEST_HEADER_FIELDS_TOO_LARGE: 431,\n NETWORK_AUTHENTICATION_REQUIRED: 511,\n NON_AUTHORITATIVE_INFORMATION: 203,\n PROXY_AUTHENTICATION_REQUIRED: 407,\n\n UNAVAILABLE_FOR_LEGAL_REASONS: 451,\n HTTP_VERSION_NOT_SUPPORTED: 505,\n BANDWIDTH_LIMIT_EXCEEDED: 509,\n VARIANT_ALSO_NEGOTIATES: 506,\n UNSUPPORTED_MEDIA_TYPE: 415,\n RANGE_NOT_SATISFIABLE: 416,\n PRECONDITION_REQUIRED: 428,\n INTERNAL_SERVER_ERROR: 500,\n UNPROCESSABLE_ENTITY: 422,\n INSUFFICIENT_STORAGE: 507,\n\n SWITCHING_PROTOCOLS: 101,\n PRECONDITION_FAILED: 412,\n MISDIRECTED_REQUEST: 421,\n SERVICE_UNAVAILABLE: 503,\n TEMPORARY_REDIRECT: 307,\n PERMANENT_REDIRECT: 308,\n METHOD_NOT_ALLOWED: 405,\n EXPECTATION_FAILED: 417,\n\n MOVED_PERMANENTLY: 301,\n PAYLOAD_TOO_LARGE: 413,\n FAILED_DEPENDENCY: 424,\n TOO_MANY_REQUESTS: 429,\n ALREADY_REPORTED: 208,\n MULTIPLE_CHOICES: 300,\n PAYMENT_REQUIRED: 402,\n UPGRADE_REQUIRED: 426,\n PARTIAL_CONTENT: 206,\n REQUEST_TIMEOUT: 408,\n LENGTH_REQUIRED: 411,\n NOT_IMPLEMENTED: 501,\n GATEWAY_TIMEOUT: 504,\n NOT_ACCEPTABLE: 406,\n RESET_CONTENT: 205,\n LOOP_DETECTED: 508,\n MULTI_STATUS: 207,\n NOT_MODIFIED: 304,\n UNAUTHORIZED: 401,\n URI_TOO_LONG: 414,\n NOT_EXTENDED: 510,\n EARLY_HINTS: 103,\n BAD_REQUEST: 400,\n IM_A_TEAPOT: 418,\n BAD_GATEWAY: 502,\n PROCESSING: 102,\n NO_CONTENT: 204,\n SEE_OTHER: 303,\n USE_PROXY: 305,\n\n FORBIDDEN: 403,\n NOT_FOUND: 404,\n TOO_EARLY: 425,\n CONTINUE: 100,\n ACCEPTED: 202,\n CONFLICT: 409,\n CREATED: 201,\n IM_USED: 226,\n LOCKED: 423,\n FOUND: 302,\n GONE: 410,\n OK: 200,\n} as const);\n\n/**\n * HTTP status messages mapped by numeric code.\n * Use for sending descriptive text in responses or logging.\n */\nexport const HttpStatusMessage = {\n 431: 'Request Header Fields Too Large',\n 511: 'Network Authentication Required',\n 203: 'Non-Authoritative Information',\n 407: 'Proxy Authentication Required',\n 451: 'Unavailable For Legal Reasons',\n 505: 'HTTP Version Not Supported',\n 509: 'Bandwidth Limit Exceeded',\n 506: 'Variant Also Negotiates',\n 415: 'Unsupported Media Type',\n 416: 'Range Not Satisfiable',\n 428: 'Precondition Required',\n 500: 'Internal Server Error',\n 422: 'Unprocessable Entity',\n 507: 'Insufficient Storage',\n 101: 'Switching Protocols',\n 412: 'Precondition Failed',\n 421: 'Misdirected Request',\n 503: 'Service Unavailable',\n 307: 'Temporary Redirect',\n 308: 'Permanent Redirect',\n 405: 'Method Not Allowed',\n 417: 'Expectation Failed',\n 301: 'Moved Permanently',\n 413: 'Payload Too Large',\n 424: 'Failed Dependency',\n 429: 'Too Many Requests',\n 208: 'Already Reported',\n 300: 'Multiple Choices',\n 402: 'Payment Required',\n 426: 'Upgrade Required',\n 206: 'Partial Content',\n 408: 'Request Timeout',\n 411: 'Length Required',\n 501: 'Not Implemented',\n 504: 'Gateway Timeout',\n 406: 'Not Acceptable',\n 205: 'Reset Content',\n 508: 'Loop Detected',\n 207: 'Multi-Status',\n 304: 'Not Modified',\n 401: 'Unauthorized',\n 414: 'URI Too Long',\n 418: \"I'm a Teapot\",\n 510: 'Not Extended',\n 103: 'Early Hints',\n 400: 'Bad Request',\n 502: 'Bad Gateway',\n 102: 'Processing',\n 204: 'No Content',\n 303: 'See Other',\n 305: 'Use Proxy',\n 403: 'Forbidden',\n 404: 'Not Found',\n 425: 'Too Early',\n 100: 'Continue',\n 202: 'Accepted',\n 226: \"I'm Used\",\n 409: 'Conflict',\n 201: 'Created',\n 423: 'Locked',\n 302: 'Found',\n 410: 'Gone',\n 200: 'OK',\n} as const;\n\nexport type HttpStatusCode = keyof typeof HttpStatusMessage;\n\nexport type HttpStatusMessage =\n (typeof HttpStatusMessage)[keyof typeof HttpStatusMessage];\n","/**\n * Base class for Domain violations.\n * Purposely does NOT extend native Error to avoid stack trace overhead in the domain.\n */\nexport abstract class DomainViolation {\n public abstract readonly code: string;\n public abstract readonly message: string;\n public readonly metadata: Readonly<Record<string, unknown>>;\n\n protected constructor(metadata: Record<string, unknown> = {}) {\n this.metadata = Object.freeze(metadata);\n }\n}\n","/**\n * Represents the outcome of an operation that can either succeed or fail,\n * without relying on exceptions for control flow.\n *\n * This pattern is commonly used in domain and application layers to make\n * success and failure states explicit, predictable, and type-safe.\n *\n * ## Design guarantees\n * - A `Result` is **immutable** once created.\n * - A `Result` is **exactly one of**:\n * - Success → contains a value\n * - Failure → contains an error\n * - Accessing the wrong side throws immediately (fail-fast).\n *\n * @typeParam T - Type of the success value\n * @typeParam E - Type of the failure error\n *\n * @example\n * ```ts\n * function parseNumber(input: string): Result<number, string> {\n * const value = Number(input);\n *\n * if (Number.isNaN(value)) {\n * return Result.fail('Invalid number');\n * }\n *\n * return Result.ok(value);\n * }\n *\n * const result = parseNumber('42');\n *\n * if (result.isSuccess) {\n * console.log(result.getValue()); // 42\n * } else {\n * console.error(result.getError());\n * }\n * ```\n */\nexport class Result<T, E> {\n /**\n * Indicates whether the result represents a failed outcome.\n *\n * This flag is mutually exclusive with {@link isSuccess}.\n */\n public readonly isFailure: boolean;\n /**\n * Indicates whether the result represents a successful outcome.\n *\n * This flag is mutually exclusive with {@link isFailure}.\n */\n public readonly isSuccess: boolean;\n\n /**\n * Creates a new {@link Result} instance.\n *\n * This constructor is private to enforce the use of\n * {@link Result.ok} and {@link Result.fail} factory methods,\n * preserving the success/failure invariants.\n *\n * @param _value - Success value (defined only for success results)\n * @param _error - Failure error (defined only for failure results)\n */\n private constructor(\n private readonly _value?: T,\n private readonly _error?: E,\n ) {\n this.isSuccess = _error === undefined;\n this.isFailure = !this.isSuccess;\n Object.freeze(this);\n }\n\n /**\n * Creates a failed {@link Result}.\n *\n * @param error - Error describing the failure\n * @returns A failure {@link Result} containing the provided error\n *\n * @example\n * ```ts\n * return Result.fail(new ValidationError('Email is invalid'));\n * ```\n */\n public static fail<T, E>(error: E): Result<T, E> {\n return new Result<T, E>(undefined, error);\n }\n\n /**\n * Creates a successful {@link Result}.\n *\n * @param value - Value representing a successful outcome\n * @returns A success {@link Result} containing the provided value\n *\n * @example\n * ```ts\n * return Result.ok(user);\n * ```\n */\n public static ok<T, E>(value: T): Result<T, E> {\n return new Result<T, E>(value);\n }\n\n /**\n * Returns the failure error.\n *\n * @returns The error associated with a failed result\n *\n * @throws {Error}\n * Thrown if this result represents a success.\n * This is a fail-fast guard against incorrect usage.\n *\n * @example\n * ```ts\n * if (result.isFailure) {\n * const error = result.getError();\n * }\n * ```\n */\n public getError(): E {\n if (this.isSuccess) {\n throw new Error('Result: Cannot get error of a success.');\n }\n\n return this._error as E;\n }\n\n /**\n * Returns the success value.\n *\n * @returns The value associated with a successful result\n *\n * @throws {Error}\n * Thrown if this result represents a failure.\n * This is a fail-fast guard against incorrect usage.\n *\n * @example\n * ```ts\n * if (result.isSuccess) {\n * const value = result.getValue();\n * }\n * ```\n */\n public getValue(): T {\n if (this.isFailure) {\n throw new Error('Result: Cannot get value of a failure.');\n }\n\n return this._value as T;\n }\n}\n","import {\n HttpStatusCode,\n HttpStatusMessage,\n} from '@/gateway/constants/http-code';\n\ninterface ErrorParams {\n message: string;\n code: HttpStatusMessage;\n status?: HttpStatusCode;\n metadata?: Record<string, unknown> | undefined;\n isOperational?: boolean;\n cause?: Error | undefined;\n}\n\n/**\n * Abstract base class for application-level errors with structured error handling.\n *\n * Extends the native Error class to provide machine-readable error codes, HTTP status codes,\n * operational error classification, and optional metadata for better error tracking and client communication.\n *\n * @abstract\n * @extends {Error}\n *\n * @example\n * ```typescript\n * class UserNotFoundError extends ApplicationError {\n * constructor(userId: string) {\n * super({\n * code: HttpStatusMessage['404'],\n * status: 404,\n * isOperational: true,\n * message: `User with id ${userId} not found`,\n * metadata: { userId }\n * });\n * }\n * }\n * ```\n */\nexport abstract class ApplicationError extends Error {\n /** Optional cause (linked error) */\n public readonly cause?: Error | undefined;\n /** Machine-readable error code (e.g. `OTP_LOCKED`, `USER_NOT_FOUND`) */\n public readonly code: HttpStatusMessage;\n /** Operational vs programmer error flag */\n public readonly isOperational: boolean;\n /** Optional structured metadata for debugging or clients */\n public readonly metadata?: Record<string, unknown> | undefined;\n /** HTTP status code intended for response layer */\n public readonly status: HttpStatusCode;\n\n constructor({\n code = HttpStatusMessage['500'],\n isOperational = false,\n status = 500,\n metadata,\n message,\n cause,\n }: ErrorParams) {\n super(message);\n\n this.name = new.target.name;\n this.code = code;\n this.status = status;\n this.isOperational = isOperational;\n this.metadata = metadata;\n this.cause = cause;\n\n Error.captureStackTrace(this, new.target);\n }\n}\n","import { ValueObject } from '@/domain/base/vo';\n\nexport type UnwrapValueObject<T> =\n T extends ValueObject<infer V>\n ? UnwrapValueObject<V>\n : T extends (infer U)[]\n ? UnwrapValueObject<U>[]\n : T extends Map<infer K, infer V>\n ? Map<K, UnwrapValueObject<V>>\n : T extends Set<infer V>\n ? Set<UnwrapValueObject<V>>\n : T extends Date\n ? string\n : T extends object\n ? { [K in keyof T]: UnwrapValueObject<T[K]> }\n : T;\n\nexport function unwrapValueObject<T>(\n input: T,\n seen = new WeakSet(),\n): UnwrapValueObject<T> {\n if (input === null || input === undefined) {\n return input as UnwrapValueObject<T>;\n }\n\n if (typeof input !== 'object') {\n return input as UnwrapValueObject<T>;\n }\n\n if (seen.has(input)) {\n // Prevent circular reference infinite recursion, just return input or throw\n throw new Error('Circular reference detected in ValueObject unwrap');\n }\n\n seen.add(input);\n\n if (Array.isArray(input)) {\n const result = input.map(item => unwrapValueObject(item, seen));\n seen.delete(input);\n return result as UnwrapValueObject<T>;\n }\n\n if (input instanceof ValueObject) {\n const result = unwrapValueObject(input.value, seen);\n seen.delete(input);\n return result as UnwrapValueObject<T>;\n }\n\n if (input instanceof Date) {\n seen.delete(input);\n return input.toISOString() as UnwrapValueObject<T>;\n }\n\n if (input instanceof Map) {\n const result = new Map();\n input.forEach((value, key) => {\n result.set(key, unwrapValueObject(value, seen));\n });\n seen.delete(input);\n return result as UnwrapValueObject<T>;\n }\n\n if (input instanceof Set) {\n const result = new Set(\n Array.from(input.values()).map(v => unwrapValueObject(v, seen)),\n );\n seen.delete(input);\n return result as UnwrapValueObject<T>;\n }\n\n // generic object\n const result: Record<string, unknown> = {};\n\n for (const key in input) {\n if (Object.hasOwn(input, key)) {\n result[key] = unwrapValueObject((input as any)[key], seen);\n }\n }\n\n seen.delete(input);\n return result as UnwrapValueObject<T>;\n}\n\nexport function ensureObject<T>(input: UnwrapValueObject<T>): object {\n if (input === null || input === undefined) {\n return {};\n }\n if (typeof input === 'object') {\n return input;\n }\n\n // for primitives, wrap inside object with default key (or throw)\n return { value: input };\n}\n"],"mappings":"yVAuBO,IAAeA,EAAf,KAAkD,CAU7C,YAAYC,EAA+B,CAjCvD,IAAAC,EAkCI,KAAK,GAAKD,EAAM,GAChB,KAAK,WAAYC,EAAAD,EAAM,YAAN,KAAAC,EAAmB,IAAI,IAC1C,CASO,OAAOC,EAAoC,CAChD,OAAIA,GAAS,KAAa,GACtB,OAASA,EAAc,GACpB,KAAK,GAAG,OAAOA,EAAM,EAAE,CAChC,CAeF,EC3BO,IAAeC,EAAf,cAA6DC,CAGlE,CAHK,kCAcL,KAAiB,cAA+B,CAAC,EAPjD,IAAI,cAAuC,CACzC,MAAO,CAAC,GAAG,KAAK,aAAa,CAC/B,CAYA,SAASC,EAAgC,CACvC,KAAK,cAAc,KAAKA,CAAW,CACrC,CAEO,kBAA2C,CAChD,IAAMC,EAAS,CAAC,GAAG,KAAK,aAAa,EACrC,YAAK,cAAc,OAAS,EACrBA,CACT,CACF,EC9DA,IAAMC,EAAgBC,GAEhBA,aAAiB,MACZ,CACL,MAAO,CACL,QAASA,EAAM,QACf,MAAOA,EAAM,MACb,KAAMA,EAAM,IACd,CACF,EAIEA,EACK,CAAE,MAAAA,CAAM,EAIV,CAAC,EAuBYC,EAAf,cAAmC,KAAM,CAWpC,YACRC,EACAC,EACAC,EAAgC,CAAC,EACjC,CACA,MAAMF,EAASG,EAAA,GAAKN,EAAaK,EAAS,KAAK,EAAG,EAGlD,OAAO,eAAe,KAAM,WAAW,SAAS,EAEhD,KAAK,KAAO,WAAW,KACvB,KAAK,KAAOD,EACZ,KAAK,SAAW,OAAO,OAAOE,EAAA,GAAKD,EAAU,CAC/C,CACF,ECjDO,IAAeE,EAAf,KAEe,CAaV,YAAYC,EAAU,CAC9B,KAAK,SAASA,CAAK,EACnB,KAAK,MAAQA,CACf,CAWO,OAAOC,EAA6D,CAGzE,OAF2BA,GAAU,MAEjC,OAAO,eAAe,IAAI,IAAM,OAAO,eAAeA,CAAK,EACtD,GAGF,KAAK,QAAUA,EAAM,KAC9B,CAMO,UAAc,CACnB,OAAO,KAAK,KACd,CAMO,QAAY,CACjB,OAAO,KAAK,KACd,CAMO,UAAmB,CACxB,OAAO,OAAO,KAAK,KAAK,CAC1B,CASF,EC5FA,OAAOC,MAAe,sBCOf,SAASC,EACdC,EACAC,EAAO,IAAI,QACE,CAYb,GAVID,GAAO,MAAS,OAAOA,GAAQ,UAAY,CAAC,MAAM,QAAQA,CAAG,GAK7D,OAAO,SAASA,CAAG,GAKnBC,EAAK,IAAID,CAAa,EACxB,OAAOA,EAMT,GAHAC,EAAK,IAAID,CAAa,EAGlB,MAAM,QAAQA,CAAG,EACnBA,EAAI,QAAQE,GAAQH,EAAWG,EAAMD,CAAI,CAAC,MAG1C,SAAWE,KAAOH,EACZ,OAAO,OAAOA,EAAKG,CAAG,GACxBJ,EAAYC,EAAgCG,CAAG,EAAGF,CAAI,EAK5D,OAAO,OAAO,OAAOD,CAAG,CAC1B,CDrCO,IAAeI,EAAf,MAAeC,CAAe,CACnC,IAAI,OAAW,CACb,OAAO,KAAK,KACd,CAIU,YAAYC,EAAU,CAC9B,KAAK,SAASA,CAAK,EACnB,KAAK,MAAQC,EAAWD,CAAK,CAC/B,CASA,OAAc,GAAGE,EAAyC,CACxD,OAAOA,aAAcH,CACvB,CAKO,OAAOI,EAAiC,CAI7C,OAHIA,GAAU,MAGV,OAAO,eAAe,IAAI,IAAM,OAAO,eAAeA,CAAK,EACtD,GAGFC,EAAU,KAAK,MAAOD,EAAM,KAAK,CAC1C,CAKO,QAAY,CACjB,OAAO,KAAK,KACd,CAKO,UAAmB,CACxB,OAAO,KAAK,UAAU,KAAK,KAAK,CAClC,CAOF,EEvDO,IAAME,EAAN,cAAoCC,CAAY,CACrD,YAAYC,EAAiBC,EAAe,CAC1C,MAAMD,EAAS,0BAA2B,CAAE,MAAAC,CAAM,CAAC,CACrD,CACF,ECPO,IAAMC,EAAN,cAAsCC,CAAY,CACvD,YAAYC,EAAiB,CAC3B,MAAMA,EAAS,sBAAsB,CACvC,CACF,ECNA,OAAS,cAAAC,MAAkB,SAwBpB,IAAeC,EAAf,KAGL,CASU,YAAYC,EAAyC,CApCjE,IAAAC,EAqCI,KAAK,IAAKA,EAAAD,EAAM,KAAN,KAAAC,EAAYH,EAAW,EACjC,KAAK,YAAcE,EAAM,YACzB,KAAK,cAAgBA,EAAM,cAC3B,KAAK,WAAaA,EAAM,WACxB,KAAK,QAAU,OAAO,OAAOA,EAAM,OAAO,CAC5C,CAEO,cAOJ,CACD,MAAO,CACL,YAAa,KAAK,YAAY,SAAS,EACvC,cAAe,KAAK,cACpB,WAAY,KAAK,WACjB,UAAW,KAAK,UAChB,QAAS,KAAK,QACd,GAAI,KAAK,EACX,CACF,CACF,EC7DA,OAAS,MAAAE,MAAU,OACnB,OAAOC,MAAO,MAsBP,IAAMC,EAAN,MAAMA,UAAaC,CAA6B,CAG9C,YAAYC,EAAe,CAChC,MAAMA,CAAK,EACX,KAAK,SAASA,CAAK,CACrB,CAQA,OAAc,WAAWA,EAAqB,CAC5C,OAAO,IAAI,KAAKA,CAAK,CACvB,CAKA,OAAc,UAA0D,CACtE,OAAO,IAAI,KAAKC,EAAG,CAAC,CACtB,CAEU,SAASD,EAAqB,CACtC,IAAME,EAASJ,EAAK,OAAO,UAAUE,CAAK,EAE1C,GAAI,CAACE,EAAO,QACV,MAAM,IAAIC,EACR,iBAAiBD,EAAO,MAAM,OAAO,EACvC,CAEJ,CACF,EAlCaJ,EACa,OAASM,EAAE,KAAK,EADnC,IAAMC,EAANP,ECdA,IAAMQ,EAAN,cAA0BC,CAAK,CAAC,ECahC,IAAMC,GAAa,OAAO,OAAO,CACtC,gCAAiC,IACjC,gCAAiC,IACjC,8BAA+B,IAC/B,8BAA+B,IAE/B,8BAA+B,IAC/B,2BAA4B,IAC5B,yBAA0B,IAC1B,wBAAyB,IACzB,uBAAwB,IACxB,sBAAuB,IACvB,sBAAuB,IACvB,sBAAuB,IACvB,qBAAsB,IACtB,qBAAsB,IAEtB,oBAAqB,IACrB,oBAAqB,IACrB,oBAAqB,IACrB,oBAAqB,IACrB,mBAAoB,IACpB,mBAAoB,IACpB,mBAAoB,IACpB,mBAAoB,IAEpB,kBAAmB,IACnB,kBAAmB,IACnB,kBAAmB,IACnB,kBAAmB,IACnB,iBAAkB,IAClB,iBAAkB,IAClB,iBAAkB,IAClB,iBAAkB,IAClB,gBAAiB,IACjB,gBAAiB,IACjB,gBAAiB,IACjB,gBAAiB,IACjB,gBAAiB,IACjB,eAAgB,IAChB,cAAe,IACf,cAAe,IACf,aAAc,IACd,aAAc,IACd,aAAc,IACd,aAAc,IACd,aAAc,IACd,YAAa,IACb,YAAa,IACb,YAAa,IACb,YAAa,IACb,WAAY,IACZ,WAAY,IACZ,UAAW,IACX,UAAW,IAEX,UAAW,IACX,UAAW,IACX,UAAW,IACX,SAAU,IACV,SAAU,IACV,SAAU,IACV,QAAS,IACT,QAAS,IACT,OAAQ,IACR,MAAO,IACP,KAAM,IACN,GAAI,GACN,CAAU,EAMGC,EAAoB,CAC/B,IAAK,kCACL,IAAK,kCACL,IAAK,gCACL,IAAK,gCACL,IAAK,gCACL,IAAK,6BACL,IAAK,2BACL,IAAK,0BACL,IAAK,yBACL,IAAK,wBACL,IAAK,wBACL,IAAK,wBACL,IAAK,uBACL,IAAK,uBACL,IAAK,sBACL,IAAK,sBACL,IAAK,sBACL,IAAK,sBACL,IAAK,qBACL,IAAK,qBACL,IAAK,qBACL,IAAK,qBACL,IAAK,oBACL,IAAK,oBACL,IAAK,oBACL,IAAK,oBACL,IAAK,mBACL,IAAK,mBACL,IAAK,mBACL,IAAK,mBACL,IAAK,kBACL,IAAK,kBACL,IAAK,kBACL,IAAK,kBACL,IAAK,kBACL,IAAK,iBACL,IAAK,gBACL,IAAK,gBACL,IAAK,eACL,IAAK,eACL,IAAK,eACL,IAAK,eACL,IAAK,eACL,IAAK,eACL,IAAK,cACL,IAAK,cACL,IAAK,cACL,IAAK,aACL,IAAK,aACL,IAAK,YACL,IAAK,YACL,IAAK,YACL,IAAK,YACL,IAAK,YACL,IAAK,WACL,IAAK,WACL,IAAK,WACL,IAAK,WACL,IAAK,UACL,IAAK,SACL,IAAK,QACL,IAAK,OACL,IAAK,IACP,EC5JO,IAAeC,EAAf,KAA+B,CAK1B,YAAYC,EAAoC,CAAC,EAAG,CAC5D,KAAK,SAAW,OAAO,OAAOA,CAAQ,CACxC,CACF,EC0BO,IAAMC,EAAN,MAAMC,CAAa,CAwBhB,YACWC,EACAC,EACjB,CAFiB,YAAAD,EACA,YAAAC,EAEjB,KAAK,UAAYA,IAAW,OAC5B,KAAK,UAAY,CAAC,KAAK,UACvB,OAAO,OAAO,IAAI,CACpB,CAaA,OAAc,KAAWC,EAAwB,CAC/C,OAAO,IAAIH,EAAa,OAAWG,CAAK,CAC1C,CAaA,OAAc,GAASC,EAAwB,CAC7C,OAAO,IAAIJ,EAAaI,CAAK,CAC/B,CAkBO,UAAc,CACnB,GAAI,KAAK,UACP,MAAM,IAAI,MAAM,wCAAwC,EAG1D,OAAO,KAAK,MACd,CAkBO,UAAc,CACnB,GAAI,KAAK,UACP,MAAM,IAAI,MAAM,wCAAwC,EAG1D,OAAO,KAAK,MACd,CACF,EC9GO,IAAeC,EAAf,cAAwC,KAAM,CAYnD,YAAY,CACV,KAAAC,EAAOC,EAAkB,GAAK,EAC9B,cAAAC,EAAgB,GAChB,OAAAC,EAAS,IACT,SAAAC,EACA,QAAAC,EACA,MAAAC,CACF,EAAgB,CACd,MAAMD,CAAO,EAEb,KAAK,KAAO,WAAW,KACvB,KAAK,KAAOL,EACZ,KAAK,OAASG,EACd,KAAK,cAAgBD,EACrB,KAAK,SAAWE,EAChB,KAAK,MAAQE,EAEb,MAAM,kBAAkB,KAAM,UAAU,CAC1C,CACF,ECpDO,SAASC,EACdC,EACAC,EAAO,IAAI,QACW,CAKtB,GAJID,GAAU,MAIV,OAAOA,GAAU,SACnB,OAAOA,EAGT,GAAIC,EAAK,IAAID,CAAK,EAEhB,MAAM,IAAI,MAAM,mDAAmD,EAKrE,GAFAC,EAAK,IAAID,CAAK,EAEV,MAAM,QAAQA,CAAK,EAAG,CACxB,IAAME,EAASF,EAAM,IAAIG,GAAQJ,EAAkBI,EAAMF,CAAI,CAAC,EAC9D,OAAAA,EAAK,OAAOD,CAAK,EACVE,CACT,CAEA,GAAIF,aAAiBI,EAAa,CAChC,IAAMF,EAASH,EAAkBC,EAAM,MAAOC,CAAI,EAClD,OAAAA,EAAK,OAAOD,CAAK,EACVE,CACT,CAEA,GAAIF,aAAiB,KACnB,OAAAC,EAAK,OAAOD,CAAK,EACVA,EAAM,YAAY,EAG3B,GAAIA,aAAiB,IAAK,CACxB,IAAME,EAAS,IAAI,IACnB,OAAAF,EAAM,QAAQ,CAACK,EAAOC,IAAQ,CAC5BJ,EAAO,IAAII,EAAKP,EAAkBM,EAAOJ,CAAI,CAAC,CAChD,CAAC,EACDA,EAAK,OAAOD,CAAK,EACVE,CACT,CAEA,GAAIF,aAAiB,IAAK,CACxB,IAAME,EAAS,IAAI,IACjB,MAAM,KAAKF,EAAM,OAAO,CAAC,EAAE,IAAIO,GAAKR,EAAkBQ,EAAGN,CAAI,CAAC,CAChE,EACA,OAAAA,EAAK,OAAOD,CAAK,EACVE,CACT,CAGA,IAAMA,EAAkC,CAAC,EAEzC,QAAWI,KAAON,EACZ,OAAO,OAAOA,EAAOM,CAAG,IAC1BJ,EAAOI,CAAG,EAAIP,EAAmBC,EAAcM,CAAG,EAAGL,CAAI,GAI7D,OAAAA,EAAK,OAAOD,CAAK,EACVE,CACT,CAEO,SAASM,GAAgBR,EAAqC,CACnE,OAAIA,GAAU,KACL,CAAC,EAEN,OAAOA,GAAU,SACZA,EAIF,CAAE,MAAOA,CAAM,CACxB","names":["Entity","props","_a","other","AggregateRoot","Entity","domainEvent","events","getCauseInfo","cause","DomainError","message","code","metadata","__spreadValues","PrimitiveValueObject","value","other","deepEqual","deepFreeze","obj","seen","item","key","ValueObject","_ValueObject","props","deepFreeze","vo","other","deepEqual","EntityValidationError","DomainError","message","cause","InvalidValueObjectError","DomainError","message","randomUUID","DomainEvent","props","_a","v4","z","_UUID","PrimitiveValueObject","value","v4","result","InvalidValueObjectError","z","UUID","AggregateId","UUID","HttpStatus","HttpStatusMessage","DomainViolation","metadata","Result","_Result","_value","_error","error","value","ApplicationError","code","HttpStatusMessage","isOperational","status","metadata","message","cause","unwrapValueObject","input","seen","result","item","ValueObject","value","key","v","ensureObject"]}
|
|
1
|
+
{"version":3,"sources":["../src/domain/entities/entity.ts","../src/domain/aggregates/aggregate-root.ts","../src/domain/base/domain.error.ts","../src/domain/base/primitive-vo.ts","../src/domain/base/vo.ts","../src/utils/deep-freeze.util.ts","../src/domain/errors/entity-validation.error.ts","../src/domain/errors/invalid-vo.error.ts","../src/domain/events/domain.event.ts","../src/domain/value-objects/id.vo.ts","../src/domain/value-objects/aggregate-id.vo.ts","../src/gateway/constants/http-code.ts","../src/utils/errors/application.error.ts","../src/utils/unwrap-vo.util.ts"],"sourcesContent":["import { EntityId } from '../types';\n\n/**\n * Configuration for the base Entity constructor.\n * Forces a single-object argument pattern to avoid positional argument errors.\n * @template ID - A type satisfying the EntityId interface.\n */\nexport interface EntityProps<ID extends EntityId, Props> {\n /** The unique identity of the entity */\n readonly id: ID;\n /** Optional creation timestamp; defaults to 'now' if not provided */\n readonly createdAt?: Date;\n\n readonly props: Props;\n}\n\n/**\n * Abstract Base Entity for Domain-Driven Design (DDD).\n * This class provides the standard contract for entity equality and identity.\n * It intentionally avoids \"magic\" property bags to ensure V8 engine optimization\n * and better IDE intellisense.\n * @template ID - The specific Identity Value Object type.\n */\nexport abstract class Entity<ID extends EntityId, Props> {\n /** The timestamp when this entity was first instantiated/created */\n public readonly createdAt: Date;\n /** The immutable unique identifier for this entity */\n public readonly id: ID;\n\n /**\n * Protected constructor to be called by subclasses.\n * @param props - Initial identity and metadata.\n */\n protected constructor(props: EntityProps<ID, Props>) {\n this.id = props.id;\n this.createdAt = props.createdAt ?? new Date();\n }\n\n /**\n * Compares entities by identity.\n * In DDD, two entities are considered equal if their IDs match,\n * regardless of their other properties.\n * @param other - The entity to compare against.\n * @returns True if IDs are equal.\n */\n public equals(other?: Entity<ID, Props>): boolean {\n if (other == null) return false;\n if (this === other) return true;\n return this.id.equals(other.id);\n }\n\n /**\n * Converts the Entity into a plain Javascript object.\n * Subclasses must implement this to explicitly control serialization,\n * @returns A plain object representation of the entity.\n */\n public abstract toObject(): Record<string, unknown>;\n\n /**\n * Validates the current state of the entity against domain invariants.\n * This method should be called after construction and any mutation.\n * @throws {Error} Should throw a specific DomainError if validation fails.\n */\n public abstract validate(): void;\n}\n","import { Entity, EntityProps } from '../entities/entity';\nimport { DomainEvent } from '../events';\nimport { EntityId } from '../types';\n\n/**\n * Interface for AggregateRoot to ensure type safety and extensibility.\n */\nexport interface Props<P> extends EntityProps<EntityId, P> {\n readonly domainEvents: readonly DomainEvent[];\n /**\n * Adds a domain event to the aggregate.\n * @param event The domain event to add.\n */\n addEvent: (event: DomainEvent) => void;\n\n /**\n * Retrieves and clears all domain events recorded by this aggregate.\n *\n * Domain events represent facts that occurred as a result of state changes\n * within the aggregate. This method transfers ownership of those events\n * to the application layer for further processing (e.g. publishing).\n *\n * Calling this method has the side effect of clearing the aggregate's\n * internal event collection to prevent duplicate handling.\n *\n * This method is intended to be invoked by application services\n * after the aggregate has been successfully persisted.\n *\n * @returns A read-only list of domain events raised by this aggregate.\n */\n pullDomainEvents: () => readonly DomainEvent[];\n}\n\n/**\n * Base class for aggregate roots in DDD, encapsulating domain events and validation.\n * @template EntityProps The type of the entity's properties.\n */\nexport abstract class AggregateRoot<ID extends EntityId, P> extends Entity<\n ID,\n P\n> {\n /**\n * Gets a read-only copy of the domain events.\n */\n get domainEvents(): readonly DomainEvent[] {\n return [...this._domainEvents];\n }\n\n /**\n * Internal list of domain events.\n */\n private readonly _domainEvents: DomainEvent[] = [];\n\n /**\n * Adds a domain event to the aggregate after validating invariants.\n * @param domainEvent The domain event to add.\n * @throws {EntityValidationError} If invariants are not met.\n */\n addEvent(domainEvent: DomainEvent): void {\n this._domainEvents.push(domainEvent);\n }\n\n public pullDomainEvents(): readonly DomainEvent[] {\n const events = [...this._domainEvents];\n this._domainEvents.length = 0;\n return events;\n }\n}\n","export interface DomainErrorMetadata {\n cause?: { name: string; message: string; stack?: string };\n [key: string]: unknown;\n}\n\nconst getCauseInfo = (cause: Error | undefined) => {\n // 1. Handle Error objects specifically\n if (cause instanceof Error) {\n return {\n cause: {\n message: cause.message,\n stack: cause.stack,\n name: cause.name,\n },\n };\n }\n\n // 2. Handle other existing values\n if (cause) {\n return { cause };\n }\n\n // 3. Default to empty\n return {};\n};\n\n/**\n * Base class for all Domain Errors in the application.\n *\n * This class ensures:\n * 1. Serializable and structured for logs or API responses.\n * 2. Identifiable via stable error codes (not just class names).\n * 3. Contextual with optional structured metadata.\n * 4. Supports error chaining (cause) and stack trace preservation.\n *\n * @example\n * export class InsufficientFundsError extends DomainError {\n * constructor(accountId: string, currentBalance: number) {\n * super(\n * `Account ${accountId} has insufficient funds.`,\n * 'INSUFFICIENT_FUNDS',\n * { accountId, currentBalance }\n * );\n * }\n * }\n */\nexport abstract class DomainError extends Error {\n /** Stable, machine-readable error code */\n public readonly code: string;\n /** Structured, immutable domain metadata */\n public readonly metadata: Readonly<DomainErrorMetadata>;\n\n /**\n * @param message - Human-readable error message\n * @param code - Stable error code\n * @param metadata - Domain-specific structured data; optional `cause` can be included\n */\n protected constructor(\n message: string,\n code: string,\n metadata: DomainErrorMetadata = {},\n ) {\n super(message, { ...getCauseInfo(metadata.cause) });\n\n // Restore prototype chain for proper `instanceof` checks\n Object.setPrototypeOf(this, new.target.prototype);\n\n this.name = new.target.name;\n this.code = code;\n this.metadata = Object.freeze({ ...metadata });\n }\n}\n","import { EntityId } from '../types';\n\ntype Primitive = boolean | number | string;\n\n/**\n * Base class for primitive-based Value Objects.\n *\n * This class is intended for Value Objects that are represented by\n * a single primitive value (string, number, or boolean).\n *\n * Characteristics:\n * - Immutable by construction\n * - Cheap equality comparison\n * - No deep cloning or freezing\n * - Safe for serialization and logging\n *\n * Examples:\n * - AggregateId\n * - EmailAddress\n * - Username\n * - Slug\n */\nexport abstract class PrimitiveValueObject<\n T extends Primitive,\n> implements EntityId {\n /**\n * The underlying primitive value.\n * Guaranteed to be valid after construction.\n */\n protected readonly value: T;\n\n /**\n * Constructs a new PrimitiveValueObject.\n *\n * @param value - The primitive value to wrap\n * @throws Error if validation fails\n */\n protected constructor(value: T) {\n this.validate(value);\n this.value = value;\n }\n\n /**\n * Compares two Value Objects for equality.\n *\n * Equality rules:\n * - Same concrete class\n * - Same primitive value (===)\n *\n * @param other - Another Value Object\n */\n public equals(other?: PrimitiveValueObject<T> | null | undefined): boolean {\n if (other === undefined || other === null) return false;\n\n if (Object.getPrototypeOf(this) !== Object.getPrototypeOf(other)) {\n return false;\n }\n\n return this.value === other.value;\n }\n\n /**\n * Returns the primitive value.\n * Prefer explicit access over implicit coercion.\n */\n public getValue(): T {\n return this.value;\n }\n\n /**\n * JSON serialization hook.\n * Produces the raw primitive value.\n */\n public toJSON(): T {\n return this.value;\n }\n\n /**\n * String representation.\n * Useful for logging and debugging.\n */\n public toString(): string {\n return String(this.value);\n }\n\n /**\n * Domain invariant validation.\n * Must throw if the value is invalid.\n *\n * @param value - The value to validate\n */\n protected abstract validate(value: T): void;\n}\n","import deepEqual from 'fast-deep-equal/es6';\n\nimport { deepFreeze } from '@/utils/deep-freeze.util';\n\nexport abstract class ValueObject<T> {\n get value(): T {\n return this.props;\n }\n\n protected readonly props: Readonly<T>;\n\n protected constructor(props: T) {\n this.validate(props);\n this.props = deepFreeze(props);\n }\n\n /**\n * Type guard to check if an unknown object is an instance of ValueObject.\n * This is useful for runtime type checking.\n *\n * @param vo The object to check.\n * @returns True if the object is a ValueObject instance, false otherwise.\n */\n public static is(vo: unknown): vo is ValueObject<unknown> {\n return vo instanceof ValueObject;\n }\n\n /**\n * Deep equality comparison of ValueObjects\n */\n public equals(other?: ValueObject<T>): boolean {\n if (other === null || other === undefined) return false;\n\n // Check if they share the same constructor (Type check)\n if (Object.getPrototypeOf(this) !== Object.getPrototypeOf(other)) {\n return false;\n }\n\n return deepEqual(this.props, other.props);\n }\n\n /**\n * Standard for clean API integration and logging.\n */\n public toJSON(): T {\n return this.props;\n }\n\n /**\n * Useful for debugging and string-based indexing.\n */\n public toString(): string {\n return JSON.stringify(this.props);\n }\n\n /**\n * Validates the value object props\n * @throws InvalidValueObjectError if validation fails\n */\n protected abstract validate(props: T): void;\n}\n","/**\n * Utility to deeply freeze objects to ensure immutability - handles nested objects and arrays.\n *\n * @param obj - The object to be deeply frozen.\n * @param seen - A WeakSet to track already processed objects (for circular references).\n * @returns A deeply frozen version of the input object.\n */\nexport function deepFreeze<T>(\n obj: T,\n seen = new WeakSet<object>(),\n): Readonly<T> {\n // Handle null, undefined, or non-object types\n if (obj == null || (typeof obj !== 'object' && !Array.isArray(obj))) {\n return obj;\n }\n\n // Skip if already frozen\n if (Object.isFrozen(obj)) {\n return obj as Readonly<T>;\n }\n\n // Handle circular references\n if (seen.has(obj as object)) {\n return obj as Readonly<T>;\n }\n\n seen.add(obj as object);\n\n // Handle arrays explicitly\n if (Array.isArray(obj)) {\n obj.forEach(item => deepFreeze(item, seen));\n } else {\n // Handle plain objects\n for (const key in obj) {\n if (Object.hasOwn(obj, key)) {\n deepFreeze((obj as Record<string, unknown>)[key], seen);\n }\n }\n }\n\n return Object.freeze(obj) as Readonly<T>;\n}\n","import { DomainError } from '../base/domain.error';\n\n/**\n * Custom error class for entity validation failures.\n */\nexport class EntityValidationError extends DomainError {\n constructor(message: string, cause?: Error) {\n super(message, 'ENTITY_VALIDATION_ERROR', { cause });\n }\n}\n","import { DomainError } from '../base/domain.error';\n\nexport class InvalidValueObjectError extends DomainError {\n constructor(message: string) {\n super(message, 'INVALID_VALUE_OBJECT');\n }\n}\n","import { randomUUID } from 'node:crypto';\n\nimport { EntityId } from '../types';\n\ntype Primitive = boolean | number | string | null;\n\ntype Serializable =\n | Primitive\n | Serializable[]\n | { [key: string]: Serializable };\n\nexport type DomainEventPayload = Record<string, Serializable>;\n\nexport type UnixTimestampMillis = number;\n\ntype DomainEventProps<AggregateId extends EntityId, Payload> = {\n id?: string;\n aggregateId: AggregateId;\n schemaVersion: number;\n occurredAt: UnixTimestampMillis;\n payload: Payload;\n};\n\n// Abstract base class for domain events\nexport abstract class DomainEvent<\n AggregateId extends EntityId = EntityId,\n T extends DomainEventPayload = DomainEventPayload,\n> {\n public readonly aggregateId: AggregateId;\n\n public abstract readonly eventName: string;\n public readonly id: string;\n public readonly occurredAt: number;\n public readonly payload: Readonly<T>;\n public readonly schemaVersion: number;\n\n protected constructor(props: DomainEventProps<AggregateId, T>) {\n this.id = props.id ?? randomUUID();\n this.aggregateId = props.aggregateId;\n this.schemaVersion = props.schemaVersion;\n this.occurredAt = props.occurredAt;\n this.payload = Object.freeze(props.payload);\n }\n\n public toPrimitives(): Readonly<{\n id: string;\n eventName: string;\n aggregateId: string;\n schemaVersion: number;\n occurredAt: UnixTimestampMillis;\n payload: T;\n }> {\n return {\n aggregateId: this.aggregateId.toString(),\n schemaVersion: this.schemaVersion,\n occurredAt: this.occurredAt,\n eventName: this.eventName,\n payload: this.payload,\n id: this.id,\n };\n }\n}\n","import { v4 } from 'uuid';\nimport z from 'zod';\n\nimport { InvalidValueObjectError } from '../errors/invalid-vo.error';\nimport { PrimitiveValueObject } from '../base/primitive-vo';\n\n/**\n * Represents a UUID (Universally Unique Identifier) value object.\n *\n * This class extends PrimitiveValueObject to provide type-safe UUID handling\n * with validation using Zod schema. UUIDs are immutable and can be generated\n * randomly or created from string values.\n *\n * @example\n * // Generate a new random UUID\n * const id = UUID.generate();\n *\n * @example\n * // Create UUID from an existing string\n * const id = UUID.fromString('550e8400-e29b-41d4-a716-446655440000');\n *\n * @throws {InvalidValueObjectError} When the provided string is not a valid UUID format\n */\nexport class UUID extends PrimitiveValueObject<string> {\n private static readonly schema = z.uuid();\n\n public constructor(value: string) {\n super(value);\n this.validate(value);\n }\n\n /**\n * Creates an UUID from an external string.\n * Use only for untrusted input.\n *\n * @param value - UUID string\n */\n public static fromString(value: string): UUID {\n return new this(value);\n }\n\n /**\n * Generates a new AggregateId.\n */\n public static generate<T extends typeof UUID>(this: T): InstanceType<T> {\n return new this(v4()) as InstanceType<T>;\n }\n\n protected validate(value: string): void {\n const result = UUID.schema.safeParse(value);\n\n if (!result.success) {\n throw new InvalidValueObjectError(\n `Invalid UUID: ${result.error.message}`,\n );\n }\n }\n}\n","import { UUID } from './id.vo';\n\n/**\n * AggregateId represents a strongly-typed aggregate identifier.\n *\n * - Backed by UUID v4\n * - Immutable\n * - Comparable only to AggregateId\n */\nexport class AggregateId extends UUID {}\n","/**\n * HTTP status code catalog.\n *\n * This object provides a typed, immutable map of standard HTTP status names\n * to their numeric codes. Designed for server-side frameworks such as Fastify.\n *\n * - All identifiers use clear, canonical semantic names.\n * - Values are numeric status codes.\n * - Frozen to prevent runtime mutation.\n * - Exporting `HttpStatus` ensures type-safe usage across the codebase.\n * Usage:\n * ```ts\n * import { HttpStatus } from 'path-to-this-file';\n *\n * function handleRequest() {\n * return {\n * statusCode: HttpStatus.OK,\n * body: 'Success',\n * };\n * }\n * ```\n */\nexport const HttpStatus = Object.freeze({\n REQUEST_HEADER_FIELDS_TOO_LARGE: 431,\n NETWORK_AUTHENTICATION_REQUIRED: 511,\n NON_AUTHORITATIVE_INFORMATION: 203,\n PROXY_AUTHENTICATION_REQUIRED: 407,\n\n UNAVAILABLE_FOR_LEGAL_REASONS: 451,\n HTTP_VERSION_NOT_SUPPORTED: 505,\n BANDWIDTH_LIMIT_EXCEEDED: 509,\n VARIANT_ALSO_NEGOTIATES: 506,\n UNSUPPORTED_MEDIA_TYPE: 415,\n RANGE_NOT_SATISFIABLE: 416,\n PRECONDITION_REQUIRED: 428,\n INTERNAL_SERVER_ERROR: 500,\n UNPROCESSABLE_ENTITY: 422,\n INSUFFICIENT_STORAGE: 507,\n\n SWITCHING_PROTOCOLS: 101,\n PRECONDITION_FAILED: 412,\n MISDIRECTED_REQUEST: 421,\n SERVICE_UNAVAILABLE: 503,\n TEMPORARY_REDIRECT: 307,\n PERMANENT_REDIRECT: 308,\n METHOD_NOT_ALLOWED: 405,\n EXPECTATION_FAILED: 417,\n\n MOVED_PERMANENTLY: 301,\n PAYLOAD_TOO_LARGE: 413,\n FAILED_DEPENDENCY: 424,\n TOO_MANY_REQUESTS: 429,\n ALREADY_REPORTED: 208,\n MULTIPLE_CHOICES: 300,\n PAYMENT_REQUIRED: 402,\n UPGRADE_REQUIRED: 426,\n PARTIAL_CONTENT: 206,\n REQUEST_TIMEOUT: 408,\n LENGTH_REQUIRED: 411,\n NOT_IMPLEMENTED: 501,\n GATEWAY_TIMEOUT: 504,\n NOT_ACCEPTABLE: 406,\n RESET_CONTENT: 205,\n LOOP_DETECTED: 508,\n MULTI_STATUS: 207,\n NOT_MODIFIED: 304,\n UNAUTHORIZED: 401,\n URI_TOO_LONG: 414,\n NOT_EXTENDED: 510,\n EARLY_HINTS: 103,\n BAD_REQUEST: 400,\n IM_A_TEAPOT: 418,\n BAD_GATEWAY: 502,\n PROCESSING: 102,\n NO_CONTENT: 204,\n SEE_OTHER: 303,\n USE_PROXY: 305,\n\n FORBIDDEN: 403,\n NOT_FOUND: 404,\n TOO_EARLY: 425,\n CONTINUE: 100,\n ACCEPTED: 202,\n CONFLICT: 409,\n CREATED: 201,\n IM_USED: 226,\n LOCKED: 423,\n FOUND: 302,\n GONE: 410,\n OK: 200,\n} as const);\n\n/**\n * HTTP status messages mapped by numeric code.\n * Use for sending descriptive text in responses or logging.\n */\nexport const HttpStatusMessage = {\n 431: 'Request Header Fields Too Large',\n 511: 'Network Authentication Required',\n 203: 'Non-Authoritative Information',\n 407: 'Proxy Authentication Required',\n 451: 'Unavailable For Legal Reasons',\n 505: 'HTTP Version Not Supported',\n 509: 'Bandwidth Limit Exceeded',\n 506: 'Variant Also Negotiates',\n 415: 'Unsupported Media Type',\n 416: 'Range Not Satisfiable',\n 428: 'Precondition Required',\n 500: 'Internal Server Error',\n 422: 'Unprocessable Entity',\n 507: 'Insufficient Storage',\n 101: 'Switching Protocols',\n 412: 'Precondition Failed',\n 421: 'Misdirected Request',\n 503: 'Service Unavailable',\n 307: 'Temporary Redirect',\n 308: 'Permanent Redirect',\n 405: 'Method Not Allowed',\n 417: 'Expectation Failed',\n 301: 'Moved Permanently',\n 413: 'Payload Too Large',\n 424: 'Failed Dependency',\n 429: 'Too Many Requests',\n 208: 'Already Reported',\n 300: 'Multiple Choices',\n 402: 'Payment Required',\n 426: 'Upgrade Required',\n 206: 'Partial Content',\n 408: 'Request Timeout',\n 411: 'Length Required',\n 501: 'Not Implemented',\n 504: 'Gateway Timeout',\n 406: 'Not Acceptable',\n 205: 'Reset Content',\n 508: 'Loop Detected',\n 207: 'Multi-Status',\n 304: 'Not Modified',\n 401: 'Unauthorized',\n 414: 'URI Too Long',\n 418: \"I'm a Teapot\",\n 510: 'Not Extended',\n 103: 'Early Hints',\n 400: 'Bad Request',\n 502: 'Bad Gateway',\n 102: 'Processing',\n 204: 'No Content',\n 303: 'See Other',\n 305: 'Use Proxy',\n 403: 'Forbidden',\n 404: 'Not Found',\n 425: 'Too Early',\n 100: 'Continue',\n 202: 'Accepted',\n 226: \"I'm Used\",\n 409: 'Conflict',\n 201: 'Created',\n 423: 'Locked',\n 302: 'Found',\n 410: 'Gone',\n 200: 'OK',\n} as const;\n\nexport type HttpStatusCode = keyof typeof HttpStatusMessage;\n\nexport type HttpStatusMessage =\n (typeof HttpStatusMessage)[keyof typeof HttpStatusMessage];\n","import {\n HttpStatusCode,\n HttpStatusMessage,\n} from '@/gateway/constants/http-code';\n\ninterface ErrorParams {\n message: string;\n code: HttpStatusMessage;\n status?: HttpStatusCode;\n metadata?: Record<string, unknown> | undefined;\n isOperational?: boolean;\n cause?: Error | undefined;\n}\n\n/**\n * Abstract base class for application-level errors with structured error handling.\n *\n * Extends the native Error class to provide machine-readable error codes, HTTP status codes,\n * operational error classification, and optional metadata for better error tracking and client communication.\n *\n * @abstract\n * @extends {Error}\n *\n * @example\n * ```typescript\n * class UserNotFoundError extends ApplicationError {\n * constructor(userId: string) {\n * super({\n * code: HttpStatusMessage['404'],\n * status: 404,\n * isOperational: true,\n * message: `User with id ${userId} not found`,\n * metadata: { userId }\n * });\n * }\n * }\n * ```\n */\nexport abstract class ApplicationError extends Error {\n /** Optional cause (linked error) */\n public readonly cause?: Error | undefined;\n /** Machine-readable error code (e.g. `OTP_LOCKED`, `USER_NOT_FOUND`) */\n public readonly code: HttpStatusMessage;\n /** Operational vs programmer error flag */\n public readonly isOperational: boolean;\n /** Optional structured metadata for debugging or clients */\n public readonly metadata?: Record<string, unknown> | undefined;\n /** HTTP status code intended for response layer */\n public readonly status: HttpStatusCode;\n\n constructor({\n code = HttpStatusMessage['500'],\n isOperational = false,\n status = 500,\n metadata,\n message,\n cause,\n }: ErrorParams) {\n super(message);\n\n this.name = new.target.name;\n this.code = code;\n this.status = status;\n this.isOperational = isOperational;\n this.metadata = metadata;\n this.cause = cause;\n\n Error.captureStackTrace(this, new.target);\n }\n}\n","import { ValueObject } from '@/domain/base/vo';\n\nexport type UnwrapValueObject<T> =\n T extends ValueObject<infer V>\n ? UnwrapValueObject<V>\n : T extends (infer U)[]\n ? UnwrapValueObject<U>[]\n : T extends Map<infer K, infer V>\n ? Map<K, UnwrapValueObject<V>>\n : T extends Set<infer V>\n ? Set<UnwrapValueObject<V>>\n : T extends Date\n ? string\n : T extends object\n ? { [K in keyof T]: UnwrapValueObject<T[K]> }\n : T;\n\nexport function unwrapValueObject<T>(\n input: T,\n seen = new WeakSet(),\n): UnwrapValueObject<T> {\n if (input === null || input === undefined) {\n return input as UnwrapValueObject<T>;\n }\n\n if (typeof input !== 'object') {\n return input as UnwrapValueObject<T>;\n }\n\n if (seen.has(input)) {\n // Prevent circular reference infinite recursion, just return input or throw\n throw new Error('Circular reference detected in ValueObject unwrap');\n }\n\n seen.add(input);\n\n if (Array.isArray(input)) {\n const result = input.map(item => unwrapValueObject(item, seen));\n seen.delete(input);\n return result as UnwrapValueObject<T>;\n }\n\n if (input instanceof ValueObject) {\n const result = unwrapValueObject(input.value, seen);\n seen.delete(input);\n return result as UnwrapValueObject<T>;\n }\n\n if (input instanceof Date) {\n seen.delete(input);\n return input.toISOString() as UnwrapValueObject<T>;\n }\n\n if (input instanceof Map) {\n const result = new Map();\n input.forEach((value, key) => {\n result.set(key, unwrapValueObject(value, seen));\n });\n seen.delete(input);\n return result as UnwrapValueObject<T>;\n }\n\n if (input instanceof Set) {\n const result = new Set(\n Array.from(input.values()).map(v => unwrapValueObject(v, seen)),\n );\n seen.delete(input);\n return result as UnwrapValueObject<T>;\n }\n\n // generic object\n const result: Record<string, unknown> = {};\n\n for (const key in input) {\n if (Object.hasOwn(input, key)) {\n result[key] = unwrapValueObject((input as any)[key], seen);\n }\n }\n\n seen.delete(input);\n return result as UnwrapValueObject<T>;\n}\n\nexport function ensureObject<T>(input: UnwrapValueObject<T>): object {\n if (input === null || input === undefined) {\n return {};\n }\n if (typeof input === 'object') {\n return input;\n }\n\n // for primitives, wrap inside object with default key (or throw)\n return { value: input };\n}\n"],"mappings":"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","names":["Entity","props","_a","other","AggregateRoot","Entity","domainEvent","events","getCauseInfo","cause","DomainError","message","code","metadata","__spreadValues","PrimitiveValueObject","value","other","deepEqual","deepFreeze","obj","seen","item","key","ValueObject","_ValueObject","props","deepFreeze","vo","other","deepEqual","EntityValidationError","DomainError","message","cause","InvalidValueObjectError","DomainError","message","randomUUID","DomainEvent","props","_a","v4","z","_UUID","PrimitiveValueObject","value","v4","result","InvalidValueObjectError","z","UUID","AggregateId","UUID","HttpStatus","HttpStatusMessage","ApplicationError","code","HttpStatusMessage","isOperational","status","metadata","message","cause","unwrapValueObject","input","seen","result","item","ValueObject","value","key","v","ensureObject"]}
|