@rineex/ddd 2.1.0 → 3.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/dist/index.d.mts CHANGED
@@ -1,3 +1,48 @@
1
+ import { Primitive as Primitive$2, EmptyObject, Tagged } from 'type-fest';
2
+ import z from 'zod';
3
+
4
+ interface ErrorParams {
5
+ message: string;
6
+ code: string;
7
+ metadata?: Record<string, unknown>;
8
+ isOperational?: boolean;
9
+ cause?: Error;
10
+ }
11
+ /**
12
+ * Abstract base class for application-level errors with structured error handling.
13
+ *
14
+ * Extends the native Error class to provide machine-readable error codes, HTTP status codes,
15
+ * operational error classification, and optional metadata for better error tracking and client communication.
16
+ *
17
+ * @abstract
18
+ * @extends {Error}
19
+ *
20
+ * @example
21
+ * ```typescript
22
+ * class UserNotFoundError extends ApplicationError {
23
+ * constructor(userId: string) {
24
+ * super({
25
+ * code: HttpStatusMessage['404'],
26
+ * isOperational: true,
27
+ * message: `User with id ${userId} not found`,
28
+ * metadata: { userId }
29
+ * });
30
+ * }
31
+ * }
32
+ * ```
33
+ */
34
+ declare abstract class ApplicationError extends Error {
35
+ /** Optional cause (linked error) */
36
+ readonly cause?: Error | undefined;
37
+ /** Machine-readable error code (e.g. `OTP_LOCKED`, `USER_NOT_FOUND`) */
38
+ readonly code: string;
39
+ /** Operational vs programmer error flag */
40
+ readonly isOperational: boolean;
41
+ /** Optional structured metadata for debugging or clients */
42
+ readonly metadata?: Record<string, unknown> | undefined;
43
+ constructor({ isOperational, metadata, message, cause, code, }: ErrorParams);
44
+ }
45
+
1
46
  /**
2
47
  * Port interface for application services that execute commands or queries.
3
48
  *
@@ -33,11 +78,15 @@ interface ApplicationServicePort<I, O> {
33
78
  * (e.g., UUID, ULID, or Database Sequence).
34
79
  * @template T - The underlying primitive type of the ID (usually string or number).
35
80
  */
36
- interface EntityId<T = string> {
37
- equals: (other?: EntityId<T> | null | undefined) => boolean;
81
+ interface EntityId {
82
+ equals: <T extends EntityId>(other?: T) => boolean;
38
83
  toString: () => string;
84
+ readonly value: Readonly<Primitive$2>;
39
85
  }
40
86
 
87
+ type Immutable<T> = T extends (...args: any[]) => any ? T : T extends Date ? T : T extends Map<infer K, infer V> ? ReadonlyMap<Immutable<K>, Immutable<V>> : T extends Set<infer U> ? ReadonlySet<Immutable<U>> : T extends object ? {
88
+ readonly [K in keyof T]: Immutable<T[K]>;
89
+ } : T;
41
90
  /**
42
91
  * Configuration for the base Entity constructor.
43
92
  * Forces a single-object argument pattern to avoid positional argument errors.
@@ -48,7 +97,7 @@ interface EntityProps<ID extends EntityId, Props> {
48
97
  readonly id: ID;
49
98
  /** Optional creation timestamp; defaults to 'now' if not provided */
50
99
  readonly createdAt?: Date;
51
- readonly props: Props;
100
+ props: Props;
52
101
  }
53
102
  /**
54
103
  * Abstract Base Entity for Domain-Driven Design (DDD).
@@ -58,15 +107,21 @@ interface EntityProps<ID extends EntityId, Props> {
58
107
  * @template ID - The specific Identity Value Object type.
59
108
  */
60
109
  declare abstract class Entity<ID extends EntityId, Props> {
110
+ #private;
61
111
  /** The timestamp when this entity was first instantiated/created */
62
112
  readonly createdAt: Date;
63
113
  /** The immutable unique identifier for this entity */
64
114
  readonly id: ID;
115
+ /**
116
+ * Read-only view of entity state.
117
+ * External code can never mutate internal state.
118
+ */
119
+ protected get props(): Immutable<Props>;
65
120
  /**
66
121
  * Protected constructor to be called by subclasses.
67
- * @param props - Initial identity and metadata.
122
+ * @param params - Initial identity and metadata.
68
123
  */
69
- protected constructor(props: EntityProps<ID, Props>);
124
+ protected constructor(params: EntityProps<ID, Props>);
70
125
  /**
71
126
  * Compares entities by identity.
72
127
  * In DDD, two entities are considered equal if their IDs match,
@@ -87,6 +142,7 @@ declare abstract class Entity<ID extends EntityId, Props> {
87
142
  * @throws {Error} Should throw a specific DomainError if validation fails.
88
143
  */
89
144
  abstract validate(): void;
145
+ protected mutate(updater: (current: Props) => Props): void;
90
146
  }
91
147
 
92
148
  type Primitive$1 = boolean | number | string | null;
@@ -95,13 +151,14 @@ type Serializable = Primitive$1 | Serializable[] | {
95
151
  };
96
152
  type DomainEventPayload = Record<string, Serializable>;
97
153
  type UnixTimestampMillis = number;
98
- type DomainEventProps<AggregateId extends EntityId, Payload> = {
154
+ type DomainEventProps<Payload, AggregateId extends EntityId> = {
99
155
  id?: string;
100
156
  aggregateId: AggregateId;
101
157
  schemaVersion: number;
102
158
  occurredAt: UnixTimestampMillis;
103
159
  payload: Payload;
104
160
  };
161
+ type CreateEventProps<EventProps, ID extends EntityId> = DomainEventProps<EventProps, ID>;
105
162
  declare abstract class DomainEvent<AggregateId extends EntityId = EntityId, T extends DomainEventPayload = DomainEventPayload> {
106
163
  readonly aggregateId: AggregateId;
107
164
  abstract readonly eventName: string;
@@ -109,7 +166,7 @@ declare abstract class DomainEvent<AggregateId extends EntityId = EntityId, T ex
109
166
  readonly occurredAt: number;
110
167
  readonly payload: Readonly<T>;
111
168
  readonly schemaVersion: number;
112
- protected constructor(props: DomainEventProps<AggregateId, T>);
169
+ protected constructor(props: DomainEventProps<T, AggregateId>);
113
170
  toPrimitives(): Readonly<{
114
171
  id: string;
115
172
  eventName: string;
@@ -120,36 +177,28 @@ declare abstract class DomainEvent<AggregateId extends EntityId = EntityId, T ex
120
177
  }>;
121
178
  }
122
179
 
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
180
  /**
151
181
  * Base class for aggregate roots in DDD, encapsulating domain events and validation.
152
- * @template EntityProps The type of the entity's properties.
182
+ *
183
+ * Aggregate roots are entities that serve as entry points to aggregates. They:
184
+ * - Enforce invariants across the aggregate
185
+ * - Manage domain events
186
+ * - Define transaction boundaries
187
+ *
188
+ * @template ID - The type of the aggregate's identity (must extend EntityId)
189
+ * @template P - The type of the aggregate's properties
190
+ *
191
+ * @example
192
+ * ```typescript
193
+ * interface UserProps {
194
+ * email: string;
195
+ * isActive: boolean;
196
+ * }
197
+ *
198
+ * class User extends AggregateRoot<AggregateId, UserProps> {
199
+ * // Implementation...
200
+ * }
201
+ * ```
153
202
  */
154
203
  declare abstract class AggregateRoot<ID extends EntityId, P> extends Entity<ID, P> {
155
204
  /**
@@ -169,48 +218,6 @@ declare abstract class AggregateRoot<ID extends EntityId, P> extends Entity<ID,
169
218
  pullDomainEvents(): readonly DomainEvent[];
170
219
  }
171
220
 
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$1 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;
214
221
  /**
215
222
  * Base class for primitive-based Value Objects.
216
223
  *
@@ -229,12 +236,13 @@ type Primitive = boolean | number | string;
229
236
  * - Username
230
237
  * - Slug
231
238
  */
232
- declare abstract class PrimitiveValueObject<T extends Primitive> implements EntityId {
239
+ declare abstract class PrimitiveValueObject<T extends Primitive$2> implements EntityId {
240
+ #private;
233
241
  /**
234
242
  * The underlying primitive value.
235
243
  * Guaranteed to be valid after construction.
236
244
  */
237
- protected readonly value: T;
245
+ get value(): T;
238
246
  /**
239
247
  * Constructs a new PrimitiveValueObject.
240
248
  *
@@ -251,17 +259,13 @@ declare abstract class PrimitiveValueObject<T extends Primitive> implements Enti
251
259
  *
252
260
  * @param other - Another Value Object
253
261
  */
254
- equals(other?: PrimitiveValueObject<T> | null | undefined): boolean;
262
+ equals(other: any): boolean;
255
263
  /**
256
264
  * Returns the primitive value.
257
265
  * Prefer explicit access over implicit coercion.
266
+ * @deprecated - instead use instance.value
258
267
  */
259
268
  getValue(): T;
260
- /**
261
- * JSON serialization hook.
262
- * Produces the raw primitive value.
263
- */
264
- toJSON(): T;
265
269
  /**
266
270
  * String representation.
267
271
  * Useful for logging and debugging.
@@ -307,234 +311,411 @@ declare abstract class ValueObject<T> {
307
311
  protected abstract validate(props: T): void;
308
312
  }
309
313
 
314
+ type Primitive = boolean | number | string | null | undefined;
315
+ type Metadata<T = EmptyObject> = T extends Record<string, Primitive> ? T : EmptyObject;
310
316
  /**
311
- * Custom error class for entity validation failures.
317
+ * Categories of domain errors based on the nature of the violation.
318
+ *
319
+ * @typedef {'DOMAIN.INVALID_STATE' | 'DOMAIN.INVALID_VALUE'} DomainErrorType
320
+ *
321
+ * @example
322
+ * // DomainErrorType usage:
323
+ * const errorType: DomainErrorType = 'DOMAIN.INVALID_STATE';
312
324
  */
313
- declare class EntityValidationError extends DomainError$1 {
314
- constructor(message: string, cause?: Error);
315
- }
316
-
317
- declare class InvalidValueObjectError extends DomainError$1 {
318
- constructor(message: string);
325
+ type DomainErrorType = 'DOMAIN.INVALID_STATE' | 'DOMAIN.INVALID_VALUE';
326
+ type ValueOf<T> = T[keyof T];
327
+ type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (k: infer I) => void ? I : never;
328
+ /**
329
+ * Interface for declaring domain error namespaces via declaration merging.
330
+ * Projects extend this interface to add their own namespaces and error codes.
331
+ *
332
+ * @example
333
+ * // In your project's type definition file (.d.ts):
334
+ * declare module '@your-org/domain-errors' {
335
+ * interface DomainErrorNamespaces {
336
+ * USER: ['NOT_FOUND', 'INVALID_EMAIL', 'SUSPENDED'];
337
+ * ORDER: ['NOT_FOUND', 'INVALID_STATUS', 'OUT_OF_STOCK'];
338
+ * // Override default namespace (optional):
339
+ * CORE: ['INTERNAL_ERROR', 'VALIDATION_FAILED', 'CONFIGURATION_ERROR'];
340
+ * }
341
+ * }
342
+ *
343
+ * @example
344
+ * // This enables type-safe error codes:
345
+ * const code: DomainErrorCode = 'USER.NOT_FOUND'; // ✅ Valid
346
+ * const code: DomainErrorCode = 'USER.INVALID'; // ❌ TypeScript error
347
+ */
348
+ interface DomainErrorNamespaces {
349
+ DOMAIN: ['INVALID_VALUE', 'INVALID_STATE'];
350
+ CORE: [
351
+ 'INTERNAL_ERROR',
352
+ 'VALIDATION_FAILED',
353
+ 'CONFIGURATION_ERROR',
354
+ 'NOT_IMPLEMENTED'
355
+ ];
356
+ SYSTEM: ['UNEXPECTED', 'TIMEOUT', 'NETWORK_ERROR', 'DEPENDENCY_ERROR'];
319
357
  }
320
-
358
+ type Namespace = keyof DomainErrorNamespaces;
359
+ type ErrorName<N extends Namespace> = DomainErrorNamespaces[N][number];
321
360
  /**
322
- * Represents a UUID (Universally Unique Identifier) value object.
361
+ * Union type of all valid domain error codes derived from registered namespaces.
362
+ * Automatically updates when projects extend DomainErrorNamespaces.
323
363
  *
324
- * This class extends PrimitiveValueObject to provide type-safe UUID handling
325
- * with validation using Zod schema. UUIDs are immutable and can be generated
326
- * randomly or created from string values.
364
+ * @example
365
+ * // After extending DomainErrorNamespaces with USER namespace:
366
+ * type ErrorCode = DomainErrorCode;
367
+ * // Becomes: 'CORE.INTERNAL_ERROR' | 'CORE.VALIDATION_FAILED' |
368
+ * // 'USER.NOT_FOUND' | 'USER.INVALID_EMAIL' | ...
369
+ */
370
+ type DomainErrorCode = {
371
+ [N in Namespace]: `${Uppercase<string & N>}.${Uppercase<ErrorName<N>>}`;
372
+ }[Namespace];
373
+ type ExtractNamespace<Code extends DomainErrorCode> = Code extends `${infer N}.${string}` ? N : never;
374
+ type ExtractErrorName<Code extends DomainErrorCode> = Code extends `${string}.${infer E}` ? E : never;
375
+ /**
376
+ * Base class for all domain errors in a Domain-Driven Design architecture.
377
+ *
378
+ * Domain errors represent violations of business rules and domain invariants.
379
+ * They are pure value objects without infrastructure concerns like IDs or timestamps.
380
+ *
381
+ * @typeParam Code - The specific error code from DomainErrorCode union
382
+ * @typeParam Meta - Type of metadata associated with this error
327
383
  *
328
384
  * @example
329
- * // Generate a new random UUID
330
- * const id = UUID.generate();
385
+ * // 1. First, declare your namespaces:
386
+ * declare module '@your-org/domain-errors' {
387
+ * interface DomainErrorNamespaces {
388
+ * USER: ['NOT_FOUND', 'INVALID_EMAIL'];
389
+ * }
390
+ * }
331
391
  *
332
392
  * @example
333
- * // Create UUID from an existing string
334
- * const id = UUID.fromString('550e8400-e29b-41d4-a716-446655440000');
393
+ * // 2. Create a concrete domain error:
394
+ * class UserNotFoundError extends DomainError<'USER.NOT_FOUND', { userId: string }> {
395
+ * public readonly code = 'USER.NOT_FOUND' as const;
396
+ * public readonly type: DomainErrorType = 'DOMAIN.INVALID_VALUE';
335
397
  *
336
- * @throws {InvalidValueObjectError} When the provided string is not a valid UUID format
398
+ * constructor(userId: string) {
399
+ * super(`User with ID '${userId}' not found`, { userId });
400
+ * }
401
+ * }
402
+ *
403
+ * @example
404
+ * // 3. Usage in domain services:
405
+ * class UserService {
406
+ * async activateUser(userId: string): Promise<Result<User, DomainError>> {
407
+ * const user = await this.repository.findById(userId);
408
+ *
409
+ * if (!user) {
410
+ * return Result.failure(new UserNotFoundError(userId));
411
+ * }
412
+ *
413
+ * if (user.isSuspended) {
414
+ * return Result.failure(new UserSuspendedError(userId));
415
+ * }
416
+ *
417
+ * // Business logic...
418
+ * }
419
+ * }
420
+ *
421
+ * @abstract
337
422
  */
338
- declare class UUID extends PrimitiveValueObject<string> {
339
- private static readonly schema;
340
- constructor(value: string);
423
+ declare abstract class DomainError<Meta extends Record<string, Primitive> = EmptyObject, Code extends DomainErrorCode = DomainErrorCode> {
341
424
  /**
342
- * Creates an UUID from an external string.
343
- * Use only for untrusted input.
425
+ * Machine-readable error code in format: NAMESPACE.ERROR_NAME
344
426
  *
345
- * @param value - UUID string
427
+ * @remarks
428
+ * - Must be uppercase (e.g., 'USER.NOT_FOUND')
429
+ * - Namespace must be declared in DomainErrorNamespaces
430
+ * - Error name must be in the namespace's array
431
+ *
432
+ * @example
433
+ * public readonly code = 'USER.NOT_FOUND' as const;
346
434
  */
347
- static fromString(value: string): UUID;
435
+ abstract readonly code: Code;
348
436
  /**
349
- * Generates a new AggregateId.
437
+ * Human-readable error message describing the domain rule violation.
438
+ * Should be meaningful to developers and potentially end-users.
439
+ *
440
+ * @remarks
441
+ * - Avoid technical implementation details
442
+ * - Focus on the business rule that was violated
443
+ * - Can include values from metadata for context
444
+ *
445
+ * @example
446
+ * // Good: "Order amount $150 exceeds maximum limit of $100"
447
+ * // Bad: "Amount validation failed: 150 > 100"
350
448
  */
351
- static generate<T extends typeof UUID>(this: T): InstanceType<T>;
352
- protected validate(value: string): void;
449
+ readonly message: string;
450
+ /**
451
+ * Immutable structured context providing additional information about the error.
452
+ * Useful for debugging, logging, and creating detailed error messages.
453
+ *
454
+ * @remarks
455
+ * - Values must be primitive types (string, number, boolean, etc.)
456
+ * - Object is frozen to prevent mutation
457
+ * - Type-safe based on the error code
458
+ *
459
+ * @example
460
+ * // For UserNotFoundError:
461
+ * { userId: 'usr_123', attemptedAction: 'activate' }
462
+ *
463
+ * @readonly
464
+ */
465
+ readonly metadata: Readonly<Meta>;
466
+ /**
467
+ * Category of domain error indicating the nature of violation.
468
+ *
469
+ * @remarks
470
+ * Use 'DOMAIN.INVALID_STATE' for state violations (e.g., "Cannot checkout empty cart")
471
+ * Use 'DOMAIN.INVALID_VALUE' for value violations (e.g., "Email format is invalid")
472
+ *
473
+ * @example
474
+ * public readonly type: DomainErrorType = 'DOMAIN.INVALID_VALUE';
475
+ */
476
+ abstract readonly type: DomainErrorType;
477
+ /** Get error name from error code */
478
+ get errorName(): ExtractErrorName<Code>;
479
+ /** Get namespace from error code */
480
+ get namespace(): ExtractNamespace<Code>;
481
+ /**
482
+ * Creates a new DomainError instance.
483
+ *
484
+ * @param message - Human-readable description of the domain rule violation
485
+ * @param metadata - Optional structured context (primitive values only)
486
+ *
487
+ * @example
488
+ * constructor(userId: string) {
489
+ * super(`User with ID '${userId}' not found`, { userId });
490
+ * }
491
+ *
492
+ * @example
493
+ * constructor(amount: number, maxLimit: number) {
494
+ * super(
495
+ * `Order amount $${amount} exceeds maximum limit of $${maxLimit}`,
496
+ * { amount, maxLimit }
497
+ * );
498
+ * }
499
+ */
500
+ protected constructor(message: string, ...args: keyof Meta extends never ? [] | [metadata?: Meta] : [metadata: Meta]);
501
+ /**
502
+ * Serializes the error to a plain object for debugging, logging, or transport.
503
+ * Does not include infrastructure concerns like stack traces or timestamps.
504
+ *
505
+ * @returns Plain object with error details
506
+ *
507
+ * @example
508
+ * const error = new UserNotFoundError('usr_123');
509
+ * const json = error.toJSON();
510
+ * // Result:
511
+ * // {
512
+ * // code: 'USER.NOT_FOUND',
513
+ * // message: "User with ID 'usr_123' not found",
514
+ * // type: 'DOMAIN.INVALID_VALUE',
515
+ * // metadata: { userId: 'usr_123' }
516
+ * // }
517
+ */
518
+ toObject(): {
519
+ metadata: Readonly<Meta>;
520
+ message: string;
521
+ code: Code;
522
+ type: DomainErrorType;
523
+ };
524
+ /**
525
+ * Returns a string representation of the error.
526
+ * Format: [CODE] MESSAGE
527
+ *
528
+ * @returns Human-readable string representation
529
+ *
530
+ * @example
531
+ * const error = new UserNotFoundError('usr_123');
532
+ * console.log(error.toString());
533
+ * // Output: [USER.NOT_FOUND] User with ID 'usr_123' not found
534
+ *
535
+ * @override
536
+ */
537
+ toString(): string;
353
538
  }
354
539
 
355
540
  /**
356
- * AggregateId represents a strongly-typed aggregate identifier.
541
+ * Default domain errors for common scenarios.
542
+ * These errors are available across all projects using this module.
543
+ */
544
+ /**
545
+ * Error thrown when an unexpected internal error occurs.
546
+ * Typically used for programming bugs, invalid assumptions, or states that should never happen.
357
547
  *
358
- * - Backed by UUID v4
359
- * - Immutable
360
- * - Comparable only to AggregateId
548
+ * @remarks
549
+ * - Metadata is optional for empty metadata types and required if a non-empty type is provided.
550
+ * - Useful for debugging, logging, and adding context to unexpected failures.
551
+ *
552
+ * @template T - Type of metadata object (must extend Record<string, Primitive>)
553
+ *
554
+ * @example
555
+ * // Catch a programming error:
556
+ * try {
557
+ * complexBusinessLogic();
558
+ * } catch (error) {
559
+ * throw new InternalError(
560
+ * 'Unexpected error in complexBusinessLogic',
561
+ * { originalError: error.message, timestamp: Date.now() }
562
+ * );
563
+ * }
564
+ *
565
+ * @example
566
+ * // Fallback for unhandled cases:
567
+ * switch (status) {
568
+ * case 'PENDING':
569
+ * break;
570
+ * case 'COMPLETED':
571
+ * break;
572
+ * default:
573
+ * throw new InternalError(
574
+ * `Unhandled status: ${status}`,
575
+ * { status }
576
+ * );
577
+ * }
578
+ *
579
+ * @example
580
+ * // With custom metadata type:
581
+ * type ErrorMetadata = { userId: string; action: string };
582
+ * throw new InternalError<ErrorMetadata>(
583
+ * 'Failed to process user action',
584
+ * { userId: 'usr_123', action: 'activate' }
585
+ * );
361
586
  */
362
- declare class AggregateId extends UUID {
587
+ declare class InternalError<T extends Record<string, Primitive> = Record<string, Primitive>> extends DomainError<Metadata<T>> {
588
+ /** @inheritdoc */
589
+ readonly code: "CORE.INTERNAL_ERROR";
590
+ /** @inheritdoc */
591
+ readonly type: DomainErrorType;
592
+ /**
593
+ * Creates a new InternalError.
594
+ *
595
+ * @param message - Description of the internal error (defaults to 'An unexpected internal error occurred')
596
+ * @param metadata - Optional debug information (primitive values only)
597
+ *
598
+ * @example
599
+ * // Basic usage:
600
+ * throw new InternalError('Something went wrong');
601
+ *
602
+ * @example
603
+ * // With metadata:
604
+ * throw new InternalError(
605
+ * 'Database connection failed',
606
+ * { host: 'localhost', port: 5432, retries: 3 }
607
+ * );
608
+ */
609
+ constructor(message?: string, metadata?: Metadata<T>);
363
610
  }
364
611
 
365
612
  /**
366
- * HTTP status code catalog.
367
- *
368
- * This object provides a typed, immutable map of standard HTTP status names
369
- * to their numeric codes. Designed for server-side frameworks such as Fastify.
613
+ * Error thrown when an entity or aggregate is in an invalid state for the requested operation.
614
+ * Use for state violations (e.g., "Cannot checkout empty cart", "Cannot cancel completed order").
370
615
  *
371
- * - All identifiers use clear, canonical semantic names.
372
- * - Values are numeric status codes.
373
- * - Frozen to prevent runtime mutation.
374
- * - Exporting `HttpStatus` ensures type-safe usage across the codebase.
375
- * Usage:
376
- * ```ts
377
- * import { HttpStatus } from 'path-to-this-file';
616
+ * @example
617
+ * // Prevent invalid state transitions:
618
+ * if (order.status === 'COMPLETED') {
619
+ * throw new InvalidStateError('Cannot cancel a completed order');
620
+ * }
378
621
  *
379
- * function handleRequest() {
380
- * return {
381
- * statusCode: HttpStatus.OK,
382
- * body: 'Success',
383
- * };
622
+ * @example
623
+ * // With context:
624
+ * if (!cart.hasItems()) {
625
+ * throw new InvalidStateError('Cannot checkout empty cart');
384
626
  * }
385
- * ```
386
627
  */
387
- declare const HttpStatus: Readonly<{
388
- readonly REQUEST_HEADER_FIELDS_TOO_LARGE: 431;
389
- readonly NETWORK_AUTHENTICATION_REQUIRED: 511;
390
- readonly NON_AUTHORITATIVE_INFORMATION: 203;
391
- readonly PROXY_AUTHENTICATION_REQUIRED: 407;
392
- readonly UNAVAILABLE_FOR_LEGAL_REASONS: 451;
393
- readonly HTTP_VERSION_NOT_SUPPORTED: 505;
394
- readonly BANDWIDTH_LIMIT_EXCEEDED: 509;
395
- readonly VARIANT_ALSO_NEGOTIATES: 506;
396
- readonly UNSUPPORTED_MEDIA_TYPE: 415;
397
- readonly RANGE_NOT_SATISFIABLE: 416;
398
- readonly PRECONDITION_REQUIRED: 428;
399
- readonly INTERNAL_SERVER_ERROR: 500;
400
- readonly UNPROCESSABLE_ENTITY: 422;
401
- readonly INSUFFICIENT_STORAGE: 507;
402
- readonly SWITCHING_PROTOCOLS: 101;
403
- readonly PRECONDITION_FAILED: 412;
404
- readonly MISDIRECTED_REQUEST: 421;
405
- readonly SERVICE_UNAVAILABLE: 503;
406
- readonly TEMPORARY_REDIRECT: 307;
407
- readonly PERMANENT_REDIRECT: 308;
408
- readonly METHOD_NOT_ALLOWED: 405;
409
- readonly EXPECTATION_FAILED: 417;
410
- readonly MOVED_PERMANENTLY: 301;
411
- readonly PAYLOAD_TOO_LARGE: 413;
412
- readonly FAILED_DEPENDENCY: 424;
413
- readonly TOO_MANY_REQUESTS: 429;
414
- readonly ALREADY_REPORTED: 208;
415
- readonly MULTIPLE_CHOICES: 300;
416
- readonly PAYMENT_REQUIRED: 402;
417
- readonly UPGRADE_REQUIRED: 426;
418
- readonly PARTIAL_CONTENT: 206;
419
- readonly REQUEST_TIMEOUT: 408;
420
- readonly LENGTH_REQUIRED: 411;
421
- readonly NOT_IMPLEMENTED: 501;
422
- readonly GATEWAY_TIMEOUT: 504;
423
- readonly NOT_ACCEPTABLE: 406;
424
- readonly RESET_CONTENT: 205;
425
- readonly LOOP_DETECTED: 508;
426
- readonly MULTI_STATUS: 207;
427
- readonly NOT_MODIFIED: 304;
428
- readonly UNAUTHORIZED: 401;
429
- readonly URI_TOO_LONG: 414;
430
- readonly NOT_EXTENDED: 510;
431
- readonly EARLY_HINTS: 103;
432
- readonly BAD_REQUEST: 400;
433
- readonly IM_A_TEAPOT: 418;
434
- readonly BAD_GATEWAY: 502;
435
- readonly PROCESSING: 102;
436
- readonly NO_CONTENT: 204;
437
- readonly SEE_OTHER: 303;
438
- readonly USE_PROXY: 305;
439
- readonly FORBIDDEN: 403;
440
- readonly NOT_FOUND: 404;
441
- readonly TOO_EARLY: 425;
442
- readonly CONTINUE: 100;
443
- readonly ACCEPTED: 202;
444
- readonly CONFLICT: 409;
445
- readonly CREATED: 201;
446
- readonly IM_USED: 226;
447
- readonly LOCKED: 423;
448
- readonly FOUND: 302;
449
- readonly GONE: 410;
450
- readonly OK: 200;
451
- }>;
452
- type HttpStatusCode = keyof typeof HttpStatusMessage;
628
+ declare class InvalidStateError extends DomainError<Record<string, Primitive>> {
629
+ code: DomainErrorCode;
630
+ type: DomainErrorType;
631
+ constructor(message?: string);
632
+ }
633
+
453
634
  /**
454
- * HTTP status messages mapped by numeric code.
455
- * Use for sending descriptive text in responses or logging.
635
+ * Error thrown when a value violates domain rules or constraints.
636
+ * Use for value violations (e.g., "Email format is invalid", "Age cannot be negative").
637
+ *
638
+ * @template T - Type of metadata object (must extend Record<string, Primitive>)
639
+ *
640
+ * @example
641
+ * // Basic usage:
642
+ * if (age < 0) {
643
+ * throw new InvalidValueError('Age cannot be negative');
644
+ * }
645
+ *
646
+ * @example
647
+ * // With metadata:
648
+ * if (!isValidEmail(email)) {
649
+ * throw new InvalidValueError(
650
+ * 'Invalid email format',
651
+ * { email, pattern: '^[^@]+@[^@]+\\.[^@]+$' }
652
+ * );
653
+ * }
654
+ *
655
+ * @example
656
+ * // With custom metadata type:
657
+ * type ValidationMetadata = { field: string; value: unknown; reason: string };
658
+ * throw new InvalidValueError<ValidationMetadata>(
659
+ * 'Validation failed',
660
+ * { field: 'email', value: email, reason: 'Invalid format' }
661
+ * );
456
662
  */
457
- declare const HttpStatusMessage: {
458
- readonly 431: "Request Header Fields Too Large";
459
- readonly 511: "Network Authentication Required";
460
- readonly 203: "Non-Authoritative Information";
461
- readonly 407: "Proxy Authentication Required";
462
- readonly 451: "Unavailable For Legal Reasons";
463
- readonly 505: "HTTP Version Not Supported";
464
- readonly 509: "Bandwidth Limit Exceeded";
465
- readonly 506: "Variant Also Negotiates";
466
- readonly 415: "Unsupported Media Type";
467
- readonly 416: "Range Not Satisfiable";
468
- readonly 428: "Precondition Required";
469
- readonly 500: "Internal Server Error";
470
- readonly 422: "Unprocessable Entity";
471
- readonly 507: "Insufficient Storage";
472
- readonly 101: "Switching Protocols";
473
- readonly 412: "Precondition Failed";
474
- readonly 421: "Misdirected Request";
475
- readonly 503: "Service Unavailable";
476
- readonly 307: "Temporary Redirect";
477
- readonly 308: "Permanent Redirect";
478
- readonly 405: "Method Not Allowed";
479
- readonly 417: "Expectation Failed";
480
- readonly 301: "Moved Permanently";
481
- readonly 413: "Payload Too Large";
482
- readonly 424: "Failed Dependency";
483
- readonly 429: "Too Many Requests";
484
- readonly 208: "Already Reported";
485
- readonly 300: "Multiple Choices";
486
- readonly 402: "Payment Required";
487
- readonly 426: "Upgrade Required";
488
- readonly 206: "Partial Content";
489
- readonly 408: "Request Timeout";
490
- readonly 411: "Length Required";
491
- readonly 501: "Not Implemented";
492
- readonly 504: "Gateway Timeout";
493
- readonly 406: "Not Acceptable";
494
- readonly 205: "Reset Content";
495
- readonly 508: "Loop Detected";
496
- readonly 207: "Multi-Status";
497
- readonly 304: "Not Modified";
498
- readonly 401: "Unauthorized";
499
- readonly 414: "URI Too Long";
500
- readonly 418: "I'm a Teapot";
501
- readonly 510: "Not Extended";
502
- readonly 103: "Early Hints";
503
- readonly 400: "Bad Request";
504
- readonly 502: "Bad Gateway";
505
- readonly 102: "Processing";
506
- readonly 204: "No Content";
507
- readonly 303: "See Other";
508
- readonly 305: "Use Proxy";
509
- readonly 403: "Forbidden";
510
- readonly 404: "Not Found";
511
- readonly 425: "Too Early";
512
- readonly 100: "Continue";
513
- readonly 202: "Accepted";
514
- readonly 226: "I'm Used";
515
- readonly 409: "Conflict";
516
- readonly 201: "Created";
517
- readonly 423: "Locked";
518
- readonly 302: "Found";
519
- readonly 410: "Gone";
520
- readonly 200: "OK";
521
- };
522
- type HttpStatusMessage = (typeof HttpStatusMessage)[keyof typeof HttpStatusMessage];
663
+ declare class InvalidValueError<T extends Record<string, Primitive> = Record<string, Primitive>> extends DomainError<Metadata<T>> {
664
+ code: DomainErrorCode;
665
+ type: DomainErrorType;
666
+ constructor(msg?: string, meta?: Metadata<T>);
667
+ }
523
668
 
524
669
  /**
525
- * Strongly-typed domain error used in Result failures.
526
- * Does NOT extend native Error on purpose infrastructure maps to transport later.
670
+ * Error thrown when an operation times out.
671
+ * Use for operations that exceed their allowed execution time.
672
+ *
673
+ * @template T - Type of metadata object (must extend Record<string, Primitive>)
674
+ *
675
+ * @example
676
+ * // Operation timeout:
677
+ * const timeout = setTimeout(() => {
678
+ * throw new TimeoutError(
679
+ * 'User registration timed out'
680
+ * );
681
+ * }, 5000);
682
+ *
683
+ * @example
684
+ * // With Promise.race:
685
+ * type Props = { url: string; timeoutMs: number };
686
+ * async function fetchWithTimeout(url: string, timeoutMs: number) {
687
+ * const timeoutPromise = new Promise<never>((_, reject) => {
688
+ * setTimeout(() => {
689
+ * reject(new TimeoutError<Props>(
690
+ * `Request to ${url} timed out`,
691
+ * { url, timeoutMs }
692
+ * ));
693
+ * }, timeoutMs);
694
+ * });
695
+ *
696
+ * return await Promise.race([fetch(url), timeoutPromise]);
697
+ * }
698
+ *
699
+ * @example
700
+ * // With custom metadata:
701
+ * throw new TimeoutError(
702
+ * 'Database query timed out',
703
+ * { query: 'SELECT * FROM users', timeout: 5000, retries: 3 }
704
+ * );
527
705
  */
528
- declare abstract class DomainError {
529
- abstract readonly code: DomainErrorCode;
530
- readonly message: string;
531
- readonly metadata: Readonly<Record<string, boolean | number | string>>;
532
- protected constructor(params: {
533
- message: string;
534
- metadata?: Record<string, boolean | number | string>;
535
- });
706
+ declare class TimeoutError<T extends Record<string, Primitive> = Record<string, Primitive>> extends DomainError<Metadata<T>> {
707
+ /** @inheritdoc */
708
+ readonly code: "SYSTEM.TIMEOUT";
709
+ /** @inheritdoc */
710
+ readonly type: DomainErrorType;
711
+ /**
712
+ * Creates a new TimeoutError.
713
+ *
714
+ * @param message - Description of the timeout
715
+ * @param metadata - Optional timeout context
716
+ */
717
+ constructor(message: string, metadata?: Metadata<T>);
536
718
  }
537
- type DomainErrorCode = 'DOMAIN.INVALID_STATE' | 'DOMAIN.INVALID_VALUE';
538
719
 
539
720
  /**
540
721
  * Represents the result of an operation, which can be either a success or a failure.
@@ -877,65 +1058,308 @@ declare class Result<T, E> {
877
1058
  isSuccessResult(): this is Result<T, never>;
878
1059
  }
879
1060
 
1061
+ type ClockPort = {
1062
+ now: () => Date;
1063
+ };
1064
+
1065
+ interface ExtraProps extends Record<string, Primitive> {
1066
+ entityId?: string;
1067
+ entityType?: string;
1068
+ }
1069
+ type Props$1 = Metadata<ExtraProps>;
1070
+ /**
1071
+ * Custom error class for entity validation failures.
1072
+ */
1073
+ declare class EntityValidationError extends DomainError<Props$1> {
1074
+ code: DomainErrorCode;
1075
+ type: DomainErrorType;
1076
+ constructor(message: string, props: Props$1);
1077
+ static create(msg: string, props: Props$1): EntityValidationError;
1078
+ }
1079
+
1080
+ type Params = {
1081
+ value: string;
1082
+ };
1083
+ type Props = Metadata<Params>;
1084
+ declare class InvalidValueObjectError extends DomainError<Props> {
1085
+ code: DomainErrorCode;
1086
+ type: DomainErrorType;
1087
+ static create(msg?: string, meta?: Props): InvalidValueObjectError;
1088
+ }
1089
+
880
1090
  /**
881
- * Utility to deeply freeze objects to ensure immutability - handles nested objects and arrays.
1091
+ * Represents a UUID (Universally Unique Identifier) value object.
1092
+ *
1093
+ * This class extends PrimitiveValueObject to provide type-safe UUID handling
1094
+ * with validation using Zod schema. UUIDs are immutable and can be generated
1095
+ * randomly or created from string values.
1096
+ * @deprecated
1097
+ * @example
1098
+ * // Generate a new random UUID
1099
+ * const id = UUID.generate();
1100
+ *
1101
+ * @example
1102
+ * // Create UUID from an existing string
1103
+ * const id = UUID.fromString('550e8400-e29b-41d4-a716-446655440000');
882
1104
  *
883
- * @param obj - The object to be deeply frozen.
884
- * @param seen - A WeakSet to track already processed objects (for circular references).
885
- * @returns A deeply frozen version of the input object.
1105
+ * @throws {InvalidValueObjectError} When the provided string is not a valid UUID format
886
1106
  */
887
- declare function deepFreeze<T>(obj: T, seen?: WeakSet<object>): Readonly<T>;
1107
+ declare class UUID extends PrimitiveValueObject<string> {
1108
+ private static readonly schema;
1109
+ constructor(value: string);
1110
+ /**
1111
+ * Creates an UUID from an external string.
1112
+ * Use only for untrusted input.
1113
+ *
1114
+ * @param value - UUID string
1115
+ */
1116
+ static fromString(value: string): UUID;
1117
+ /**
1118
+ * Generates a new AggregateId.
1119
+ */
1120
+ static generate<T extends typeof UUID>(this: T): InstanceType<T>;
1121
+ protected validate(value: string): void;
1122
+ }
888
1123
 
889
- interface ErrorParams {
890
- message: string;
891
- code: HttpStatusMessage;
892
- status?: HttpStatusCode;
893
- metadata?: Record<string, unknown> | undefined;
894
- isOperational?: boolean;
895
- cause?: Error | undefined;
1124
+ /**
1125
+ * AggregateId represents a strongly-typed aggregate identifier.
1126
+ *
1127
+ * - Backed by UUID v4
1128
+ * - Immutable
1129
+ * - Comparable only to AggregateId
1130
+ */
1131
+ declare class AggregateId extends UUID {
896
1132
  }
1133
+
897
1134
  /**
898
- * Abstract base class for application-level errors with structured error handling.
1135
+ * UUID is a branded string type.
899
1136
  *
900
- * Extends the native Error class to provide machine-readable error codes, HTTP status codes,
901
- * operational error classification, and optional metadata for better error tracking and client communication.
1137
+ * - Prevents accidental use of arbitrary strings
1138
+ * - Requires explicit validation or construction
1139
+ * - Zero runtime cost after creation
1140
+ */
1141
+ type UuID = Tagged<string, 'UUID'>;
1142
+ /**
1143
+ * Abstract base class for all domain identifiers.
902
1144
  *
903
- * @abstract
904
- * @extends {Error}
1145
+ * Responsibilities:
1146
+ * - Enforces that every DomainID wraps a primitive string value.
1147
+ * - Provides a type-safe static factory `fromString` for creating concrete IDs.
1148
+ * - Leaves domain-specific validation to subclasses via `validate`.
905
1149
  *
906
- * @example
907
- * ```typescript
908
- * class UserNotFoundError extends ApplicationError {
909
- * constructor(userId: string) {
910
- * super({
911
- * code: HttpStatusMessage['404'],
912
- * status: 404,
913
- * isOperational: true,
914
- * message: `User with id ${userId} not found`,
915
- * metadata: { userId }
916
- * });
1150
+ * Design Notes:
1151
+ * - The class cannot know how to validate the ID itself, because validation
1152
+ * rules differ between ID types (e.g., UUID v4, ULID, NanoID).
1153
+ * - Static factory uses `new this(value)` pattern; hence, base class is **not abstract** in TypeScript terms.
1154
+ * - Subclasses must implement `validate(value: string)` inherited from PrimitiveValueObject.
1155
+ *
1156
+ * Usage:
1157
+ * ```ts
1158
+ * class AuthAttemptId extends DomainID {
1159
+ * protected validate(value: string): void {
1160
+ * if (!isValidUuid(value)) {
1161
+ * throw new Error('Invalid AuthAttemptId');
1162
+ * }
917
1163
  * }
918
1164
  * }
1165
+ *
1166
+ * const id = AuthAttemptId.fromString('550e8400-e29b-41d4-a716-446655440000');
919
1167
  * ```
920
1168
  */
921
- declare abstract class ApplicationError extends Error {
922
- /** Optional cause (linked error) */
923
- readonly cause?: Error | undefined;
924
- /** Machine-readable error code (e.g. `OTP_LOCKED`, `USER_NOT_FOUND`) */
925
- readonly code: HttpStatusMessage;
926
- /** Operational vs programmer error flag */
927
- readonly isOperational: boolean;
928
- /** Optional structured metadata for debugging or clients */
929
- readonly metadata?: Record<string, unknown> | undefined;
930
- /** HTTP status code intended for response layer */
931
- readonly status: HttpStatusCode;
932
- constructor({ code, isOperational, status, metadata, message, cause, }: ErrorParams);
1169
+ declare abstract class DomainID extends PrimitiveValueObject<UuID> {
1170
+ static schema: z.ZodUUID;
1171
+ constructor(value: string);
1172
+ /**
1173
+ * Creates a concrete DomainID from a trusted string value.
1174
+ *
1175
+ * - Validation is enforced in the subclass constructor.
1176
+ * - Intended for application or infrastructure layers to produce IDs.
1177
+ *
1178
+ * @template T - Concrete subclass of DomainID
1179
+ * @param this - The constructor of the concrete subclass
1180
+ * @param value - Raw string value of the ID
1181
+ * @returns Instance of the concrete DomainID subclass
1182
+ */
1183
+ static fromString<T extends new (value: string) => DomainID>(this: T, value: string): InstanceType<T>;
1184
+ static generate<T extends new (value: string) => DomainID>(this: T): InstanceType<T>;
1185
+ protected validate(value: UuID): void;
933
1186
  }
934
1187
 
935
- 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 ? {
936
- [K in keyof T]: UnwrapValueObject<T[K]>;
937
- } : T;
938
- declare function unwrapValueObject<T>(input: T, seen?: WeakSet<object>): UnwrapValueObject<T>;
939
- declare function ensureObject<T>(input: UnwrapValueObject<T>): object;
1188
+ declare class Email extends PrimitiveValueObject<string> {
1189
+ private static readonly schema;
1190
+ constructor(value: string);
1191
+ static fromString(value: string): Email;
1192
+ protected validate(value: string): void;
1193
+ }
1194
+
1195
+ /**
1196
+ * HTTP status code catalog.
1197
+ *
1198
+ * This object provides a typed, immutable map of standard HTTP status names
1199
+ * to their numeric codes. Designed for server-side frameworks such as Fastify.
1200
+ *
1201
+ * - All identifiers use clear, canonical semantic names.
1202
+ * - Values are numeric status codes.
1203
+ * - Frozen to prevent runtime mutation.
1204
+ * - Exporting `HttpStatus` ensures type-safe usage across the codebase.
1205
+ * Usage:
1206
+ * ```ts
1207
+ * import { HttpStatus } from 'path-to-this-file';
1208
+ *
1209
+ * function handleRequest() {
1210
+ * return {
1211
+ * statusCode: HttpStatus.OK,
1212
+ * body: 'Success',
1213
+ * };
1214
+ * }
1215
+ * ```
1216
+ */
1217
+ declare const HttpStatus: Readonly<{
1218
+ readonly REQUEST_HEADER_FIELDS_TOO_LARGE: 431;
1219
+ readonly NETWORK_AUTHENTICATION_REQUIRED: 511;
1220
+ readonly NON_AUTHORITATIVE_INFORMATION: 203;
1221
+ readonly PROXY_AUTHENTICATION_REQUIRED: 407;
1222
+ readonly UNAVAILABLE_FOR_LEGAL_REASONS: 451;
1223
+ readonly HTTP_VERSION_NOT_SUPPORTED: 505;
1224
+ readonly BANDWIDTH_LIMIT_EXCEEDED: 509;
1225
+ readonly VARIANT_ALSO_NEGOTIATES: 506;
1226
+ readonly UNSUPPORTED_MEDIA_TYPE: 415;
1227
+ readonly RANGE_NOT_SATISFIABLE: 416;
1228
+ readonly PRECONDITION_REQUIRED: 428;
1229
+ readonly INTERNAL_SERVER_ERROR: 500;
1230
+ readonly UNPROCESSABLE_ENTITY: 422;
1231
+ readonly INSUFFICIENT_STORAGE: 507;
1232
+ readonly SWITCHING_PROTOCOLS: 101;
1233
+ readonly PRECONDITION_FAILED: 412;
1234
+ readonly MISDIRECTED_REQUEST: 421;
1235
+ readonly SERVICE_UNAVAILABLE: 503;
1236
+ readonly TEMPORARY_REDIRECT: 307;
1237
+ readonly PERMANENT_REDIRECT: 308;
1238
+ readonly METHOD_NOT_ALLOWED: 405;
1239
+ readonly EXPECTATION_FAILED: 417;
1240
+ readonly MOVED_PERMANENTLY: 301;
1241
+ readonly PAYLOAD_TOO_LARGE: 413;
1242
+ readonly FAILED_DEPENDENCY: 424;
1243
+ readonly TOO_MANY_REQUESTS: 429;
1244
+ readonly ALREADY_REPORTED: 208;
1245
+ readonly MULTIPLE_CHOICES: 300;
1246
+ readonly PAYMENT_REQUIRED: 402;
1247
+ readonly UPGRADE_REQUIRED: 426;
1248
+ readonly PARTIAL_CONTENT: 206;
1249
+ readonly REQUEST_TIMEOUT: 408;
1250
+ readonly LENGTH_REQUIRED: 411;
1251
+ readonly NOT_IMPLEMENTED: 501;
1252
+ readonly GATEWAY_TIMEOUT: 504;
1253
+ readonly NOT_ACCEPTABLE: 406;
1254
+ readonly RESET_CONTENT: 205;
1255
+ readonly LOOP_DETECTED: 508;
1256
+ readonly MULTI_STATUS: 207;
1257
+ readonly NOT_MODIFIED: 304;
1258
+ readonly UNAUTHORIZED: 401;
1259
+ readonly URI_TOO_LONG: 414;
1260
+ readonly NOT_EXTENDED: 510;
1261
+ readonly EARLY_HINTS: 103;
1262
+ readonly BAD_REQUEST: 400;
1263
+ readonly IM_A_TEAPOT: 418;
1264
+ readonly BAD_GATEWAY: 502;
1265
+ readonly PROCESSING: 102;
1266
+ readonly NO_CONTENT: 204;
1267
+ readonly SEE_OTHER: 303;
1268
+ readonly USE_PROXY: 305;
1269
+ readonly FORBIDDEN: 403;
1270
+ readonly NOT_FOUND: 404;
1271
+ readonly TOO_EARLY: 425;
1272
+ readonly CONTINUE: 100;
1273
+ readonly ACCEPTED: 202;
1274
+ readonly CONFLICT: 409;
1275
+ readonly CREATED: 201;
1276
+ readonly IM_USED: 226;
1277
+ readonly LOCKED: 423;
1278
+ readonly FOUND: 302;
1279
+ readonly GONE: 410;
1280
+ readonly OK: 200;
1281
+ }>;
1282
+ type HttpStatusCode = keyof typeof HttpStatusMessage;
1283
+ /**
1284
+ * HTTP status messages mapped by numeric code.
1285
+ * Use for sending descriptive text in responses or logging.
1286
+ */
1287
+ declare const HttpStatusMessage: {
1288
+ readonly 431: "Request Header Fields Too Large";
1289
+ readonly 511: "Network Authentication Required";
1290
+ readonly 203: "Non-Authoritative Information";
1291
+ readonly 407: "Proxy Authentication Required";
1292
+ readonly 451: "Unavailable For Legal Reasons";
1293
+ readonly 505: "HTTP Version Not Supported";
1294
+ readonly 509: "Bandwidth Limit Exceeded";
1295
+ readonly 506: "Variant Also Negotiates";
1296
+ readonly 415: "Unsupported Media Type";
1297
+ readonly 416: "Range Not Satisfiable";
1298
+ readonly 428: "Precondition Required";
1299
+ readonly 500: "Internal Server Error";
1300
+ readonly 422: "Unprocessable Entity";
1301
+ readonly 507: "Insufficient Storage";
1302
+ readonly 101: "Switching Protocols";
1303
+ readonly 412: "Precondition Failed";
1304
+ readonly 421: "Misdirected Request";
1305
+ readonly 503: "Service Unavailable";
1306
+ readonly 307: "Temporary Redirect";
1307
+ readonly 308: "Permanent Redirect";
1308
+ readonly 405: "Method Not Allowed";
1309
+ readonly 417: "Expectation Failed";
1310
+ readonly 301: "Moved Permanently";
1311
+ readonly 413: "Payload Too Large";
1312
+ readonly 424: "Failed Dependency";
1313
+ readonly 429: "Too Many Requests";
1314
+ readonly 208: "Already Reported";
1315
+ readonly 300: "Multiple Choices";
1316
+ readonly 402: "Payment Required";
1317
+ readonly 426: "Upgrade Required";
1318
+ readonly 206: "Partial Content";
1319
+ readonly 408: "Request Timeout";
1320
+ readonly 411: "Length Required";
1321
+ readonly 501: "Not Implemented";
1322
+ readonly 504: "Gateway Timeout";
1323
+ readonly 406: "Not Acceptable";
1324
+ readonly 205: "Reset Content";
1325
+ readonly 508: "Loop Detected";
1326
+ readonly 207: "Multi-Status";
1327
+ readonly 304: "Not Modified";
1328
+ readonly 401: "Unauthorized";
1329
+ readonly 414: "URI Too Long";
1330
+ readonly 418: "I'm a Teapot";
1331
+ readonly 510: "Not Extended";
1332
+ readonly 103: "Early Hints";
1333
+ readonly 400: "Bad Request";
1334
+ readonly 502: "Bad Gateway";
1335
+ readonly 102: "Processing";
1336
+ readonly 204: "No Content";
1337
+ readonly 303: "See Other";
1338
+ readonly 305: "Use Proxy";
1339
+ readonly 403: "Forbidden";
1340
+ readonly 404: "Not Found";
1341
+ readonly 425: "Too Early";
1342
+ readonly 100: "Continue";
1343
+ readonly 202: "Accepted";
1344
+ readonly 226: "I'm Used";
1345
+ readonly 409: "Conflict";
1346
+ readonly 201: "Created";
1347
+ readonly 423: "Locked";
1348
+ readonly 302: "Found";
1349
+ readonly 410: "Gone";
1350
+ readonly 200: "OK";
1351
+ };
1352
+ type HttpStatusMessage = (typeof HttpStatusMessage)[keyof typeof HttpStatusMessage];
1353
+
1354
+ /**
1355
+ * Deeply freezes an object graph to enforce runtime immutability.
1356
+ * - Handles arrays
1357
+ * - Handles circular references
1358
+ * - Skips functions
1359
+ * - Skips already frozen objects
1360
+ *
1361
+ * Intended for aggregate and value object state only.
1362
+ */
1363
+ declare function deepFreeze<T>(value: T, seen?: WeakSet<object>): Readonly<T>;
940
1364
 
941
- export { AggregateId, AggregateRoot, ApplicationError, type ApplicationServicePort, DomainError$1 as DomainError, type DomainErrorMetadata, DomainEvent, type DomainEventPayload, Entity, type EntityId, type EntityProps, EntityValidationError, HttpStatus, type HttpStatusCode, HttpStatusMessage, InvalidValueObjectError, PrimitiveValueObject, type Props, Result, UUID, type UnixTimestampMillis, type UnwrapValueObject, ValueObject, deepFreeze, ensureObject, unwrapValueObject };
1365
+ export { AggregateId, AggregateRoot, ApplicationError, type ApplicationServicePort, type ClockPort, type CreateEventProps, DomainError, type DomainErrorCode, type DomainErrorNamespaces, type DomainErrorType, DomainEvent, type DomainEventPayload, DomainID, Email, Entity, type EntityId, type EntityProps, EntityValidationError, type ExtractErrorName, type ExtractNamespace, HttpStatus, type HttpStatusCode, HttpStatusMessage, type Immutable, InternalError, InvalidStateError, InvalidValueError, InvalidValueObjectError, type Metadata, type Primitive, PrimitiveValueObject, Result, TimeoutError, UUID, type UnionToIntersection, type UnixTimestampMillis, type UuID, ValueObject, type ValueOf, deepFreeze };