@rineex/ddd 1.5.1 → 1.6.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/dist/index.d.mts +373 -289
- package/dist/index.d.ts +373 -289
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -1
package/dist/index.d.mts
CHANGED
|
@@ -27,6 +27,190 @@ interface ApplicationServicePort<I, O> {
|
|
|
27
27
|
execute: (args: I) => Promise<O>;
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
+
/**
|
|
31
|
+
* Interface for Identity Value Objects.
|
|
32
|
+
* Enables the Entity to remain agnostic of the underlying ID implementation
|
|
33
|
+
* (e.g., UUID, ULID, or Database Sequence).
|
|
34
|
+
* @template T - The underlying primitive type of the ID (usually string or number).
|
|
35
|
+
*/
|
|
36
|
+
interface EntityId<T = string> {
|
|
37
|
+
equals: (other?: EntityId<T> | null | undefined) => boolean;
|
|
38
|
+
toString: () => string;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Configuration for the base Entity constructor.
|
|
43
|
+
* Forces a single-object argument pattern to avoid positional argument errors.
|
|
44
|
+
* @template ID - A type satisfying the EntityId interface.
|
|
45
|
+
*/
|
|
46
|
+
interface EntityProps<ID extends EntityId, Props> {
|
|
47
|
+
/** The unique identity of the entity */
|
|
48
|
+
readonly id: ID;
|
|
49
|
+
/** Optional creation timestamp; defaults to 'now' if not provided */
|
|
50
|
+
readonly createdAt?: Date;
|
|
51
|
+
readonly props: Props;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Abstract Base Entity for Domain-Driven Design (DDD).
|
|
55
|
+
* This class provides the standard contract for entity equality and identity.
|
|
56
|
+
* It intentionally avoids "magic" property bags to ensure V8 engine optimization
|
|
57
|
+
* and better IDE intellisense.
|
|
58
|
+
* @template ID - The specific Identity Value Object type.
|
|
59
|
+
*/
|
|
60
|
+
declare abstract class Entity<ID extends EntityId, Props> {
|
|
61
|
+
/** The immutable unique identifier for this entity */
|
|
62
|
+
readonly id: ID;
|
|
63
|
+
/** The timestamp when this entity was first instantiated/created */
|
|
64
|
+
readonly createdAt: Date;
|
|
65
|
+
/**
|
|
66
|
+
* Protected constructor to be called by subclasses.
|
|
67
|
+
* @param props - Initial identity and metadata.
|
|
68
|
+
*/
|
|
69
|
+
protected constructor(props: EntityProps<ID, Props>);
|
|
70
|
+
/**
|
|
71
|
+
* Compares entities by identity.
|
|
72
|
+
* In DDD, two entities are considered equal if their IDs match,
|
|
73
|
+
* regardless of their other properties.
|
|
74
|
+
* @param other - The entity to compare against.
|
|
75
|
+
* @returns True if IDs are equal.
|
|
76
|
+
*/
|
|
77
|
+
equals(other?: Entity<ID, Props>): boolean;
|
|
78
|
+
/**
|
|
79
|
+
* Validates the current state of the entity against domain invariants.
|
|
80
|
+
* This method should be called after construction and any mutation.
|
|
81
|
+
* @throws {Error} Should throw a specific DomainError if validation fails.
|
|
82
|
+
*/
|
|
83
|
+
abstract validate(): void;
|
|
84
|
+
/**
|
|
85
|
+
* Converts the Entity into a plain Javascript object.
|
|
86
|
+
* Subclasses must implement this to explicitly control serialization,
|
|
87
|
+
* @returns A plain object representation of the entity.
|
|
88
|
+
*/
|
|
89
|
+
abstract toObject(): Record<string, unknown>;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
type Primitive$1 = boolean | number | string | null;
|
|
93
|
+
type Serializable = Primitive$1 | Serializable[] | {
|
|
94
|
+
[key: string]: Serializable;
|
|
95
|
+
};
|
|
96
|
+
type DomainEventPayload = Record<string, Serializable>;
|
|
97
|
+
type UnixTimestampMillis = number;
|
|
98
|
+
type DomainEventProps<AggregateId extends EntityId, Payload> = {
|
|
99
|
+
id?: string;
|
|
100
|
+
aggregateId: AggregateId;
|
|
101
|
+
schemaVersion: number;
|
|
102
|
+
occurredAt: UnixTimestampMillis;
|
|
103
|
+
payload: Payload;
|
|
104
|
+
};
|
|
105
|
+
declare abstract class DomainEvent<AggregateId extends EntityId = EntityId, T extends DomainEventPayload = DomainEventPayload> {
|
|
106
|
+
abstract readonly eventName: string;
|
|
107
|
+
readonly id: string;
|
|
108
|
+
readonly aggregateId: AggregateId;
|
|
109
|
+
readonly schemaVersion: number;
|
|
110
|
+
readonly occurredAt: number;
|
|
111
|
+
readonly payload: Readonly<T>;
|
|
112
|
+
protected constructor(props: DomainEventProps<AggregateId, T>);
|
|
113
|
+
toPrimitives(): Readonly<{
|
|
114
|
+
id: string;
|
|
115
|
+
eventName: string;
|
|
116
|
+
aggregateId: string;
|
|
117
|
+
schemaVersion: number;
|
|
118
|
+
occurredAt: UnixTimestampMillis;
|
|
119
|
+
payload: T;
|
|
120
|
+
}>;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Interface for AggregateRoot to ensure type safety and extensibility.
|
|
125
|
+
*/
|
|
126
|
+
interface Props<P> extends EntityProps<EntityId, P> {
|
|
127
|
+
readonly domainEvents: readonly DomainEvent[];
|
|
128
|
+
/**
|
|
129
|
+
* Adds a domain event to the aggregate.
|
|
130
|
+
* @param event The domain event to add.
|
|
131
|
+
*/
|
|
132
|
+
addEvent: (event: DomainEvent) => void;
|
|
133
|
+
/**
|
|
134
|
+
* Retrieves and clears all domain events recorded by this aggregate.
|
|
135
|
+
*
|
|
136
|
+
* Domain events represent facts that occurred as a result of state changes
|
|
137
|
+
* within the aggregate. This method transfers ownership of those events
|
|
138
|
+
* to the application layer for further processing (e.g. publishing).
|
|
139
|
+
*
|
|
140
|
+
* Calling this method has the side effect of clearing the aggregate's
|
|
141
|
+
* internal event collection to prevent duplicate handling.
|
|
142
|
+
*
|
|
143
|
+
* This method is intended to be invoked by application services
|
|
144
|
+
* after the aggregate has been successfully persisted.
|
|
145
|
+
*
|
|
146
|
+
* @returns A read-only list of domain events raised by this aggregate.
|
|
147
|
+
*/
|
|
148
|
+
pullDomainEvents: () => readonly DomainEvent[];
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Base class for aggregate roots in DDD, encapsulating domain events and validation.
|
|
152
|
+
* @template EntityProps The type of the entity's properties.
|
|
153
|
+
*/
|
|
154
|
+
declare abstract class AggregateRoot<ID extends EntityId, P> extends Entity<ID, P> {
|
|
155
|
+
/**
|
|
156
|
+
* Gets a read-only copy of the domain events.
|
|
157
|
+
*/
|
|
158
|
+
get domainEvents(): readonly DomainEvent[];
|
|
159
|
+
/**
|
|
160
|
+
* Internal list of domain events.
|
|
161
|
+
*/
|
|
162
|
+
private readonly _domainEvents;
|
|
163
|
+
/**
|
|
164
|
+
* Adds a domain event to the aggregate after validating invariants.
|
|
165
|
+
* @param domainEvent The domain event to add.
|
|
166
|
+
* @throws {EntityValidationError} If invariants are not met.
|
|
167
|
+
*/
|
|
168
|
+
addEvent(domainEvent: DomainEvent): void;
|
|
169
|
+
pullDomainEvents(): readonly DomainEvent[];
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
interface DomainErrorMetadata {
|
|
173
|
+
cause?: {
|
|
174
|
+
name: string;
|
|
175
|
+
message: string;
|
|
176
|
+
stack?: string;
|
|
177
|
+
};
|
|
178
|
+
[key: string]: unknown;
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Base class for all Domain Errors in the application.
|
|
182
|
+
*
|
|
183
|
+
* This class ensures:
|
|
184
|
+
* 1. Serializable and structured for logs or API responses.
|
|
185
|
+
* 2. Identifiable via stable error codes (not just class names).
|
|
186
|
+
* 3. Contextual with optional structured metadata.
|
|
187
|
+
* 4. Supports error chaining (cause) and stack trace preservation.
|
|
188
|
+
*
|
|
189
|
+
* @example
|
|
190
|
+
* export class InsufficientFundsError extends DomainError {
|
|
191
|
+
* constructor(accountId: string, currentBalance: number) {
|
|
192
|
+
* super(
|
|
193
|
+
* `Account ${accountId} has insufficient funds.`,
|
|
194
|
+
* 'INSUFFICIENT_FUNDS',
|
|
195
|
+
* { accountId, currentBalance }
|
|
196
|
+
* );
|
|
197
|
+
* }
|
|
198
|
+
* }
|
|
199
|
+
*/
|
|
200
|
+
declare abstract class DomainError extends Error {
|
|
201
|
+
/** Stable, machine-readable error code */
|
|
202
|
+
readonly code: string;
|
|
203
|
+
/** Structured, immutable domain metadata */
|
|
204
|
+
readonly metadata: Readonly<DomainErrorMetadata>;
|
|
205
|
+
/**
|
|
206
|
+
* @param message - Human-readable error message
|
|
207
|
+
* @param code - Stable error code
|
|
208
|
+
* @param metadata - Domain-specific structured data; optional `cause` can be included
|
|
209
|
+
*/
|
|
210
|
+
protected constructor(message: string, code: string, metadata?: DomainErrorMetadata);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
type Primitive = boolean | number | string;
|
|
30
214
|
/**
|
|
31
215
|
* Base class for primitive-based Value Objects.
|
|
32
216
|
*
|
|
@@ -45,7 +229,7 @@ interface ApplicationServicePort<I, O> {
|
|
|
45
229
|
* - Username
|
|
46
230
|
* - Slug
|
|
47
231
|
*/
|
|
48
|
-
declare abstract class PrimitiveValueObject<T extends
|
|
232
|
+
declare abstract class PrimitiveValueObject<T extends Primitive> implements EntityId {
|
|
49
233
|
/**
|
|
50
234
|
* The underlying primitive value.
|
|
51
235
|
* Guaranteed to be valid after construction.
|
|
@@ -72,7 +256,7 @@ declare abstract class PrimitiveValueObject<T extends boolean | number | string>
|
|
|
72
256
|
*
|
|
73
257
|
* @param other - Another Value Object
|
|
74
258
|
*/
|
|
75
|
-
equals(other?: PrimitiveValueObject<T>): boolean;
|
|
259
|
+
equals(other?: PrimitiveValueObject<T> | null | undefined): boolean;
|
|
76
260
|
/**
|
|
77
261
|
* JSON serialization hook.
|
|
78
262
|
* Produces the raw primitive value.
|
|
@@ -92,6 +276,48 @@ declare abstract class PrimitiveValueObject<T extends boolean | number | string>
|
|
|
92
276
|
protected abstract validate(value: T): void;
|
|
93
277
|
}
|
|
94
278
|
|
|
279
|
+
declare abstract class ValueObject<T> {
|
|
280
|
+
get value(): T;
|
|
281
|
+
protected readonly props: Readonly<T>;
|
|
282
|
+
protected constructor(props: T);
|
|
283
|
+
/**
|
|
284
|
+
* Standard for clean API integration and logging.
|
|
285
|
+
*/
|
|
286
|
+
toJSON(): T;
|
|
287
|
+
/**
|
|
288
|
+
* Useful for debugging and string-based indexing.
|
|
289
|
+
*/
|
|
290
|
+
toString(): string;
|
|
291
|
+
/**
|
|
292
|
+
* Type guard to check if an unknown object is an instance of ValueObject.
|
|
293
|
+
* This is useful for runtime type checking.
|
|
294
|
+
*
|
|
295
|
+
* @param vo The object to check.
|
|
296
|
+
* @returns True if the object is a ValueObject instance, false otherwise.
|
|
297
|
+
*/
|
|
298
|
+
static is(vo: unknown): vo is ValueObject<unknown>;
|
|
299
|
+
/**
|
|
300
|
+
* Deep equality comparison of ValueObjects
|
|
301
|
+
*/
|
|
302
|
+
equals(other?: ValueObject<T>): boolean;
|
|
303
|
+
/**
|
|
304
|
+
* Validates the value object props
|
|
305
|
+
* @throws InvalidValueObjectError if validation fails
|
|
306
|
+
*/
|
|
307
|
+
protected abstract validate(props: T): void;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* Custom error class for entity validation failures.
|
|
312
|
+
*/
|
|
313
|
+
declare class EntityValidationError extends DomainError {
|
|
314
|
+
constructor(message: string, cause?: Error);
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
declare class InvalidValueObjectError extends DomainError {
|
|
318
|
+
constructor(message: string);
|
|
319
|
+
}
|
|
320
|
+
|
|
95
321
|
/**
|
|
96
322
|
* Represents a UUID (Universally Unique Identifier) value object.
|
|
97
323
|
*
|
|
@@ -136,15 +362,6 @@ declare class UUID extends PrimitiveValueObject<string> {
|
|
|
136
362
|
declare class AggregateId extends UUID {
|
|
137
363
|
}
|
|
138
364
|
|
|
139
|
-
/**
|
|
140
|
-
* Utility to deeply freeze objects to ensure immutability - handles nested objects and arrays.
|
|
141
|
-
*
|
|
142
|
-
* @param obj - The object to be deeply frozen.
|
|
143
|
-
* @param seen - A WeakSet to track already processed objects (for circular references).
|
|
144
|
-
* @returns A deeply frozen version of the input object.
|
|
145
|
-
*/
|
|
146
|
-
declare function deepFreeze<T>(obj: T, seen?: WeakSet<object>): Readonly<T>;
|
|
147
|
-
|
|
148
365
|
/**
|
|
149
366
|
* HTTP status code catalog.
|
|
150
367
|
*
|
|
@@ -304,6 +521,150 @@ declare const HttpStatusMessage: {
|
|
|
304
521
|
};
|
|
305
522
|
type HttpStatusMessage = (typeof HttpStatusMessage)[keyof typeof HttpStatusMessage];
|
|
306
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 successful outcome.
|
|
578
|
+
*
|
|
579
|
+
* This flag is mutually exclusive with {@link isFailure}.
|
|
580
|
+
*/
|
|
581
|
+
readonly isSuccess: boolean;
|
|
582
|
+
/**
|
|
583
|
+
* Indicates whether the result represents a failed outcome.
|
|
584
|
+
*
|
|
585
|
+
* This flag is mutually exclusive with {@link isSuccess}.
|
|
586
|
+
*/
|
|
587
|
+
readonly isFailure: 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 successful {@link Result}.
|
|
601
|
+
*
|
|
602
|
+
* @param value - Value representing a successful outcome
|
|
603
|
+
* @returns A success {@link Result} containing the provided value
|
|
604
|
+
*
|
|
605
|
+
* @example
|
|
606
|
+
* ```ts
|
|
607
|
+
* return Result.ok(user);
|
|
608
|
+
* ```
|
|
609
|
+
*/
|
|
610
|
+
static ok<T, E>(value: T): Result<T, E>;
|
|
611
|
+
/**
|
|
612
|
+
* Creates a failed {@link Result}.
|
|
613
|
+
*
|
|
614
|
+
* @param error - Error describing the failure
|
|
615
|
+
* @returns A failure {@link Result} containing the provided error
|
|
616
|
+
*
|
|
617
|
+
* @example
|
|
618
|
+
* ```ts
|
|
619
|
+
* return Result.fail(new ValidationError('Email is invalid'));
|
|
620
|
+
* ```
|
|
621
|
+
*/
|
|
622
|
+
static fail<T, E>(error: E): Result<T, E>;
|
|
623
|
+
/**
|
|
624
|
+
* Returns the success value.
|
|
625
|
+
*
|
|
626
|
+
* @returns The value associated with a successful result
|
|
627
|
+
*
|
|
628
|
+
* @throws {Error}
|
|
629
|
+
* Thrown if this result represents a failure.
|
|
630
|
+
* This is a fail-fast guard against incorrect usage.
|
|
631
|
+
*
|
|
632
|
+
* @example
|
|
633
|
+
* ```ts
|
|
634
|
+
* if (result.isSuccess) {
|
|
635
|
+
* const value = result.getValue();
|
|
636
|
+
* }
|
|
637
|
+
* ```
|
|
638
|
+
*/
|
|
639
|
+
getValue(): T;
|
|
640
|
+
/**
|
|
641
|
+
* Returns the failure error.
|
|
642
|
+
*
|
|
643
|
+
* @returns The error associated with a failed result
|
|
644
|
+
*
|
|
645
|
+
* @throws {Error}
|
|
646
|
+
* Thrown if this result represents a success.
|
|
647
|
+
* This is a fail-fast guard against incorrect usage.
|
|
648
|
+
*
|
|
649
|
+
* @example
|
|
650
|
+
* ```ts
|
|
651
|
+
* if (result.isFailure) {
|
|
652
|
+
* const error = result.getError();
|
|
653
|
+
* }
|
|
654
|
+
* ```
|
|
655
|
+
*/
|
|
656
|
+
getError(): E;
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
/**
|
|
660
|
+
* Utility to deeply freeze objects to ensure immutability - handles nested objects and arrays.
|
|
661
|
+
*
|
|
662
|
+
* @param obj - The object to be deeply frozen.
|
|
663
|
+
* @param seen - A WeakSet to track already processed objects (for circular references).
|
|
664
|
+
* @returns A deeply frozen version of the input object.
|
|
665
|
+
*/
|
|
666
|
+
declare function deepFreeze<T>(obj: T, seen?: WeakSet<object>): Readonly<T>;
|
|
667
|
+
|
|
307
668
|
interface ErrorParams {
|
|
308
669
|
message: string;
|
|
309
670
|
code: HttpStatusMessage;
|
|
@@ -350,287 +711,10 @@ declare abstract class ApplicationError extends Error {
|
|
|
350
711
|
constructor({ code, isOperational, status, metadata, message, cause, }: ErrorParams);
|
|
351
712
|
}
|
|
352
713
|
|
|
353
|
-
declare abstract class ValueObject<T> {
|
|
354
|
-
get value(): T;
|
|
355
|
-
protected readonly props: Readonly<T>;
|
|
356
|
-
protected constructor(props: T);
|
|
357
|
-
/**
|
|
358
|
-
* Standard for clean API integration and logging.
|
|
359
|
-
*/
|
|
360
|
-
toJSON(): T;
|
|
361
|
-
/**
|
|
362
|
-
* Useful for debugging and string-based indexing.
|
|
363
|
-
*/
|
|
364
|
-
toString(): string;
|
|
365
|
-
/**
|
|
366
|
-
* Type guard to check if an unknown object is an instance of ValueObject.
|
|
367
|
-
* This is useful for runtime type checking.
|
|
368
|
-
*
|
|
369
|
-
* @param vo The object to check.
|
|
370
|
-
* @returns True if the object is a ValueObject instance, false otherwise.
|
|
371
|
-
*/
|
|
372
|
-
static is(vo: unknown): vo is ValueObject<unknown>;
|
|
373
|
-
/**
|
|
374
|
-
* Deep equality comparison of ValueObjects
|
|
375
|
-
*/
|
|
376
|
-
equals(other?: ValueObject<T>): boolean;
|
|
377
|
-
/**
|
|
378
|
-
* Validates the value object props
|
|
379
|
-
* @throws InvalidValueObjectError if validation fails
|
|
380
|
-
*/
|
|
381
|
-
protected abstract validate(props: T): void;
|
|
382
|
-
}
|
|
383
|
-
|
|
384
714
|
type UnwrapValueObject<T> = T extends ValueObject<infer V> ? UnwrapValueObject<V> : T extends (infer U)[] ? UnwrapValueObject<U>[] : T extends Map<infer K, infer V> ? Map<K, UnwrapValueObject<V>> : T extends Set<infer V> ? Set<UnwrapValueObject<V>> : T extends Date ? string : T extends object ? {
|
|
385
715
|
[K in keyof T]: UnwrapValueObject<T[K]>;
|
|
386
716
|
} : T;
|
|
387
717
|
declare function unwrapValueObject<T>(input: T, seen?: WeakSet<object>): UnwrapValueObject<T>;
|
|
388
718
|
declare function ensureObject<T>(input: UnwrapValueObject<T>): object;
|
|
389
719
|
|
|
390
|
-
|
|
391
|
-
id: AggregateId;
|
|
392
|
-
equals: (entity: unknown) => boolean;
|
|
393
|
-
}
|
|
394
|
-
/**
|
|
395
|
-
* Base properties common to all entities, including ID and timestamps.
|
|
396
|
-
*/
|
|
397
|
-
interface BaseEntityProps {
|
|
398
|
-
/** Unique identifier for the entity */
|
|
399
|
-
id?: AggregateId;
|
|
400
|
-
/** Date when the entity was created */
|
|
401
|
-
createdAt: Date;
|
|
402
|
-
}
|
|
403
|
-
/**
|
|
404
|
-
* Interface for constructing an entity with optional timestamps.
|
|
405
|
-
* @template Props - The specific props type for the entity
|
|
406
|
-
*/
|
|
407
|
-
type CreateEntityProps<T> = BaseEntityProps & {
|
|
408
|
-
props: T;
|
|
409
|
-
};
|
|
410
|
-
/**
|
|
411
|
-
* Abstract base class for domain entities in a Domain-Driven Design (DDD) context.
|
|
412
|
-
* Provides common functionality for entity identification, equality comparison,
|
|
413
|
-
* immutability, and validation. Entities extending this class must implement
|
|
414
|
-
* the `validate` method to enforce domain invariants.
|
|
415
|
-
* @template EntityProps - The specific props type for the entity
|
|
416
|
-
*/
|
|
417
|
-
declare abstract class Entity<EntityProps> {
|
|
418
|
-
#private;
|
|
419
|
-
/**
|
|
420
|
-
* Returns the creation timestamp.
|
|
421
|
-
* A new Date instance is returned to preserve immutability.
|
|
422
|
-
*
|
|
423
|
-
* @returns {Date} The creation date of the entity.
|
|
424
|
-
*/
|
|
425
|
-
get createdAt(): Date;
|
|
426
|
-
/**
|
|
427
|
-
* Gets the entity's unique identifier.
|
|
428
|
-
* @returns The entity's ID
|
|
429
|
-
*/
|
|
430
|
-
get id(): AggregateId;
|
|
431
|
-
get metadata(): Readonly<{
|
|
432
|
-
createdAt: string;
|
|
433
|
-
id: AggregateId;
|
|
434
|
-
}>;
|
|
435
|
-
/**
|
|
436
|
-
* Returns an immutable shallow copy of the entity's properties.
|
|
437
|
-
*
|
|
438
|
-
* @returns {Readonly<EntityProps>} The entity domain properties.
|
|
439
|
-
*/
|
|
440
|
-
get props(): Readonly<EntityProps>;
|
|
441
|
-
/**
|
|
442
|
-
* Constructs an entity with the provided properties and timestamps.
|
|
443
|
-
* Ensures immutability by cloning props and validates the entity.
|
|
444
|
-
* @param params - Entity creation parameters
|
|
445
|
-
* @throws EntityValidationError if the ID is empty or validation fails
|
|
446
|
-
*/
|
|
447
|
-
protected constructor(args: CreateEntityProps<EntityProps>);
|
|
448
|
-
/**
|
|
449
|
-
* Checks if the provided value is an instance of Entity.
|
|
450
|
-
* @param entity - The value to check
|
|
451
|
-
* @returns True if the value is an Entity instance
|
|
452
|
-
*/
|
|
453
|
-
static isEntity(entity: unknown): entity is EntityBaseInterface;
|
|
454
|
-
/**
|
|
455
|
-
* Compares this entity with another to determine if they are the same.
|
|
456
|
-
* Equality is based on the entity ID.
|
|
457
|
-
* @param other - The entity to compare with
|
|
458
|
-
* @returns True if the entities have the same ID
|
|
459
|
-
*/
|
|
460
|
-
equals(other?: Entity<unknown>): boolean;
|
|
461
|
-
/**
|
|
462
|
-
* Returns a frozen copy of the entity's properties, including base properties.
|
|
463
|
-
* Ensures immutability by returning a new object.
|
|
464
|
-
* @returns A frozen copy of the entity's properties
|
|
465
|
-
*/
|
|
466
|
-
getPropsCopy(): Readonly<EntityProps>;
|
|
467
|
-
/**
|
|
468
|
-
* Determines if the entity is transient, i.e., it has not been persisted yet.
|
|
469
|
-
* By convention, an entity is considered transient if it lacks a valid identifier.
|
|
470
|
-
* This can be useful when performing logic that depends on persistence state,
|
|
471
|
-
* such as conditional inserts or validations that only apply to new entities.
|
|
472
|
-
*
|
|
473
|
-
* @returns True if the entity is transient (not persisted), otherwise false.
|
|
474
|
-
*/
|
|
475
|
-
toJSON(): Record<string, unknown>;
|
|
476
|
-
/**
|
|
477
|
-
* Internal mutation hook.
|
|
478
|
-
* Must be followed by validation by caller.
|
|
479
|
-
*/
|
|
480
|
-
protected updateProps(updater: (current: EntityProps) => EntityProps): void;
|
|
481
|
-
toObject(): Readonly<UnwrapValueObject<EntityProps> & {
|
|
482
|
-
createdAt: string;
|
|
483
|
-
id: string;
|
|
484
|
-
}>;
|
|
485
|
-
/**
|
|
486
|
-
* Validates the entity's state to enforce domain invariants.
|
|
487
|
-
* Must be implemented by subclasses to define specific validation rules.
|
|
488
|
-
* @implements Must be called by concrete factories and mutators.
|
|
489
|
-
* @throws EntityValidationError if validation fails
|
|
490
|
-
*/
|
|
491
|
-
abstract validate(): void;
|
|
492
|
-
}
|
|
493
|
-
|
|
494
|
-
type Primitive = boolean | number | string | null;
|
|
495
|
-
type Serializable = Primitive | Serializable[] | {
|
|
496
|
-
[key: string]: Serializable;
|
|
497
|
-
};
|
|
498
|
-
type DomainEventPayload = Record<string, Serializable>;
|
|
499
|
-
type DomainEventProps<T> = {
|
|
500
|
-
id: string;
|
|
501
|
-
aggregateId: string;
|
|
502
|
-
schemaVersion: number;
|
|
503
|
-
occurredAt: number;
|
|
504
|
-
payload: T;
|
|
505
|
-
};
|
|
506
|
-
declare abstract class DomainEvent<T extends DomainEventPayload = DomainEventPayload> {
|
|
507
|
-
abstract readonly eventName: string;
|
|
508
|
-
readonly id: string;
|
|
509
|
-
readonly aggregateId: string;
|
|
510
|
-
readonly schemaVersion: number;
|
|
511
|
-
readonly occurredAt: number;
|
|
512
|
-
readonly payload: Readonly<T>;
|
|
513
|
-
protected constructor(props: DomainEventProps<T>);
|
|
514
|
-
toPrimitives(): {
|
|
515
|
-
schemaVersion: number;
|
|
516
|
-
aggregateId: string;
|
|
517
|
-
occurredAt: number;
|
|
518
|
-
eventName: string;
|
|
519
|
-
payload: Readonly<T>;
|
|
520
|
-
id: string;
|
|
521
|
-
};
|
|
522
|
-
}
|
|
523
|
-
|
|
524
|
-
/**
|
|
525
|
-
* Interface for AggregateRoot to ensure type safety and extensibility.
|
|
526
|
-
*/
|
|
527
|
-
interface AggregateRootInterface {
|
|
528
|
-
readonly id: AggregateId;
|
|
529
|
-
readonly domainEvents: readonly DomainEvent[];
|
|
530
|
-
/**
|
|
531
|
-
* Validates the aggregate's invariants.
|
|
532
|
-
* @throws {EntityValidationError} If validation fails.
|
|
533
|
-
*/
|
|
534
|
-
validate: () => void;
|
|
535
|
-
/**
|
|
536
|
-
* Adds a domain event to the aggregate.
|
|
537
|
-
* @param event The domain event to add.
|
|
538
|
-
*/
|
|
539
|
-
addEvent: (event: DomainEvent) => void;
|
|
540
|
-
/**
|
|
541
|
-
* Retrieves and clears all domain events recorded by this aggregate.
|
|
542
|
-
*
|
|
543
|
-
* Domain events represent facts that occurred as a result of state changes
|
|
544
|
-
* within the aggregate. This method transfers ownership of those events
|
|
545
|
-
* to the application layer for further processing (e.g. publishing).
|
|
546
|
-
*
|
|
547
|
-
* Calling this method has the side effect of clearing the aggregate's
|
|
548
|
-
* internal event collection to prevent duplicate handling.
|
|
549
|
-
*
|
|
550
|
-
* This method is intended to be invoked by application services
|
|
551
|
-
* after the aggregate has been successfully persisted.
|
|
552
|
-
*
|
|
553
|
-
* @returns A read-only list of domain events raised by this aggregate.
|
|
554
|
-
*/
|
|
555
|
-
pullDomainEvents: () => readonly DomainEvent[];
|
|
556
|
-
}
|
|
557
|
-
/**
|
|
558
|
-
* Base class for aggregate roots in DDD, encapsulating domain events and validation.
|
|
559
|
-
* @template EntityProps The type of the entity's properties.
|
|
560
|
-
*/
|
|
561
|
-
declare abstract class AggregateRoot<EntityProps> extends Entity<EntityProps> implements AggregateRootInterface {
|
|
562
|
-
/**
|
|
563
|
-
* Gets a read-only copy of the domain events.
|
|
564
|
-
*/
|
|
565
|
-
get domainEvents(): readonly DomainEvent[];
|
|
566
|
-
/**
|
|
567
|
-
* Internal list of domain events.
|
|
568
|
-
*/
|
|
569
|
-
private readonly _domainEvents;
|
|
570
|
-
/**
|
|
571
|
-
* Adds a domain event to the aggregate after validating invariants.
|
|
572
|
-
* @param domainEvent The domain event to add.
|
|
573
|
-
* @throws {EntityValidationError} If invariants are not met.
|
|
574
|
-
*/
|
|
575
|
-
addEvent(domainEvent: DomainEvent): void;
|
|
576
|
-
pullDomainEvents(): readonly DomainEvent[];
|
|
577
|
-
/**
|
|
578
|
-
* Validates the entity's invariants.
|
|
579
|
-
* @throws {EntityValidationError} If validation fails.
|
|
580
|
-
*/
|
|
581
|
-
abstract validate(): void;
|
|
582
|
-
}
|
|
583
|
-
|
|
584
|
-
interface DomainErrorMetadata {
|
|
585
|
-
cause?: {
|
|
586
|
-
name: string;
|
|
587
|
-
message: string;
|
|
588
|
-
stack?: string;
|
|
589
|
-
};
|
|
590
|
-
[key: string]: unknown;
|
|
591
|
-
}
|
|
592
|
-
/**
|
|
593
|
-
* Base class for all Domain Errors in the application.
|
|
594
|
-
*
|
|
595
|
-
* This class ensures:
|
|
596
|
-
* 1. Serializable and structured for logs or API responses.
|
|
597
|
-
* 2. Identifiable via stable error codes (not just class names).
|
|
598
|
-
* 3. Contextual with optional structured metadata.
|
|
599
|
-
* 4. Supports error chaining (cause) and stack trace preservation.
|
|
600
|
-
*
|
|
601
|
-
* @example
|
|
602
|
-
* export class InsufficientFundsError extends DomainError {
|
|
603
|
-
* constructor(accountId: string, currentBalance: number) {
|
|
604
|
-
* super(
|
|
605
|
-
* `Account ${accountId} has insufficient funds.`,
|
|
606
|
-
* 'INSUFFICIENT_FUNDS',
|
|
607
|
-
* { accountId, currentBalance }
|
|
608
|
-
* );
|
|
609
|
-
* }
|
|
610
|
-
* }
|
|
611
|
-
*/
|
|
612
|
-
declare abstract class DomainError extends Error {
|
|
613
|
-
/** Stable, machine-readable error code */
|
|
614
|
-
readonly code: string;
|
|
615
|
-
/** Structured, immutable domain metadata */
|
|
616
|
-
readonly metadata: Readonly<DomainErrorMetadata>;
|
|
617
|
-
/**
|
|
618
|
-
* @param message - Human-readable error message
|
|
619
|
-
* @param code - Stable error code
|
|
620
|
-
* @param metadata - Domain-specific structured data; optional `cause` can be included
|
|
621
|
-
*/
|
|
622
|
-
protected constructor(message: string, code: string, metadata?: DomainErrorMetadata);
|
|
623
|
-
}
|
|
624
|
-
|
|
625
|
-
/**
|
|
626
|
-
* Custom error class for entity validation failures.
|
|
627
|
-
*/
|
|
628
|
-
declare class EntityValidationError extends DomainError {
|
|
629
|
-
constructor(message: string, cause?: Error);
|
|
630
|
-
}
|
|
631
|
-
|
|
632
|
-
declare class InvalidValueObjectError extends DomainError {
|
|
633
|
-
constructor(message: string);
|
|
634
|
-
}
|
|
635
|
-
|
|
636
|
-
export { AggregateId, AggregateRoot, type AggregateRootInterface, ApplicationError, type ApplicationServicePort, type BaseEntityProps, type CreateEntityProps, DomainError, type DomainErrorMetadata, DomainEvent, type DomainEventPayload, Entity, type EntityBaseInterface, EntityValidationError, HttpStatus, type HttpStatusCode, HttpStatusMessage, InvalidValueObjectError, PrimitiveValueObject, UUID, type UnwrapValueObject, ValueObject, deepFreeze, ensureObject, unwrapValueObject };
|
|
720
|
+
export { AggregateId, AggregateRoot, ApplicationError, type ApplicationServicePort, DomainError, type DomainErrorMetadata, DomainEvent, type DomainEventPayload, DomainViolation, Entity, type EntityId, type EntityProps, EntityValidationError, HttpStatus, type HttpStatusCode, HttpStatusMessage, InvalidValueObjectError, PrimitiveValueObject, type Props, Result, UUID, type UnixTimestampMillis, type UnwrapValueObject, ValueObject, deepFreeze, ensureObject, unwrapValueObject };
|