@cosmneo/onion-lasagna 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. package/dist/backend/core/global.cjs +283 -0
  2. package/dist/backend/core/global.cjs.map +1 -0
  3. package/dist/backend/core/global.d.cts +294 -0
  4. package/dist/backend/core/global.d.ts +294 -0
  5. package/dist/backend/core/global.js +39 -0
  6. package/dist/backend/core/global.js.map +1 -0
  7. package/dist/backend/core/onion-layers.cjs +2302 -0
  8. package/dist/backend/core/onion-layers.cjs.map +1 -0
  9. package/dist/backend/core/onion-layers.d.cts +1675 -0
  10. package/dist/backend/core/onion-layers.d.ts +1675 -0
  11. package/dist/backend/core/onion-layers.js +1158 -0
  12. package/dist/backend/core/onion-layers.js.map +1 -0
  13. package/dist/backend/core/presentation.cjs +573 -0
  14. package/dist/backend/core/presentation.cjs.map +1 -0
  15. package/dist/backend/core/presentation.d.cts +5 -0
  16. package/dist/backend/core/presentation.d.ts +5 -0
  17. package/dist/backend/core/presentation.js +28 -0
  18. package/dist/backend/core/presentation.js.map +1 -0
  19. package/dist/backend/core/validators/arktype.cjs +947 -0
  20. package/dist/backend/core/validators/arktype.cjs.map +1 -0
  21. package/dist/backend/core/validators/arktype.d.cts +188 -0
  22. package/dist/backend/core/validators/arktype.d.ts +188 -0
  23. package/dist/backend/core/validators/arktype.js +287 -0
  24. package/dist/backend/core/validators/arktype.js.map +1 -0
  25. package/dist/backend/core/validators/typebox.cjs +939 -0
  26. package/dist/backend/core/validators/typebox.cjs.map +1 -0
  27. package/dist/backend/core/validators/typebox.d.cts +189 -0
  28. package/dist/backend/core/validators/typebox.d.ts +189 -0
  29. package/dist/backend/core/validators/typebox.js +281 -0
  30. package/dist/backend/core/validators/typebox.js.map +1 -0
  31. package/dist/backend/core/validators/valibot.cjs +942 -0
  32. package/dist/backend/core/validators/valibot.cjs.map +1 -0
  33. package/dist/backend/core/validators/valibot.d.cts +160 -0
  34. package/dist/backend/core/validators/valibot.d.ts +160 -0
  35. package/dist/backend/core/validators/valibot.js +294 -0
  36. package/dist/backend/core/validators/valibot.js.map +1 -0
  37. package/dist/backend/core/validators/zod.cjs +934 -0
  38. package/dist/backend/core/validators/zod.cjs.map +1 -0
  39. package/dist/backend/core/validators/zod.d.cts +188 -0
  40. package/dist/backend/core/validators/zod.d.ts +188 -0
  41. package/dist/backend/core/validators/zod.js +278 -0
  42. package/dist/backend/core/validators/zod.js.map +1 -0
  43. package/dist/backend/frameworks/elysia.cjs +715 -0
  44. package/dist/backend/frameworks/elysia.cjs.map +1 -0
  45. package/dist/backend/frameworks/elysia.d.cts +208 -0
  46. package/dist/backend/frameworks/elysia.d.ts +208 -0
  47. package/dist/backend/frameworks/elysia.js +251 -0
  48. package/dist/backend/frameworks/elysia.js.map +1 -0
  49. package/dist/backend/frameworks/fastify.cjs +677 -0
  50. package/dist/backend/frameworks/fastify.cjs.map +1 -0
  51. package/dist/backend/frameworks/fastify.d.cts +201 -0
  52. package/dist/backend/frameworks/fastify.d.ts +201 -0
  53. package/dist/backend/frameworks/fastify.js +213 -0
  54. package/dist/backend/frameworks/fastify.js.map +1 -0
  55. package/dist/backend/frameworks/hono.cjs +715 -0
  56. package/dist/backend/frameworks/hono.cjs.map +1 -0
  57. package/dist/backend/frameworks/hono.d.cts +163 -0
  58. package/dist/backend/frameworks/hono.d.ts +163 -0
  59. package/dist/backend/frameworks/hono.js +249 -0
  60. package/dist/backend/frameworks/hono.js.map +1 -0
  61. package/dist/backend/frameworks/nestjs.cjs +260 -0
  62. package/dist/backend/frameworks/nestjs.cjs.map +1 -0
  63. package/dist/backend/frameworks/nestjs.d.cts +168 -0
  64. package/dist/backend/frameworks/nestjs.d.ts +168 -0
  65. package/dist/backend/frameworks/nestjs.js +193 -0
  66. package/dist/backend/frameworks/nestjs.js.map +1 -0
  67. package/dist/base-dto.class-D7W9iqoU.d.cts +146 -0
  68. package/dist/base-dto.class-D7W9iqoU.d.ts +146 -0
  69. package/dist/base-uuid-v7.vo-BPGEIWLM.d.ts +799 -0
  70. package/dist/base-uuid-v7.vo-BjqKX44G.d.cts +799 -0
  71. package/dist/chunk-74IKUOSE.js +116 -0
  72. package/dist/chunk-74IKUOSE.js.map +1 -0
  73. package/dist/chunk-BKZOLGQW.js +29 -0
  74. package/dist/chunk-BKZOLGQW.js.map +1 -0
  75. package/dist/chunk-CGZBV6BD.js +54 -0
  76. package/dist/chunk-CGZBV6BD.js.map +1 -0
  77. package/dist/chunk-DDAHJZVK.js +258 -0
  78. package/dist/chunk-DDAHJZVK.js.map +1 -0
  79. package/dist/chunk-MQD5GXMT.js +171 -0
  80. package/dist/chunk-MQD5GXMT.js.map +1 -0
  81. package/dist/chunk-OKFXZHBC.js +43 -0
  82. package/dist/chunk-OKFXZHBC.js.map +1 -0
  83. package/dist/chunk-RLLWYFPI.js +168 -0
  84. package/dist/chunk-RLLWYFPI.js.map +1 -0
  85. package/dist/chunk-VCHFXT5W.js +425 -0
  86. package/dist/chunk-VCHFXT5W.js.map +1 -0
  87. package/dist/chunk-ZWLYNGO3.js +40 -0
  88. package/dist/chunk-ZWLYNGO3.js.map +1 -0
  89. package/dist/http-response-BAhi8lF4.d.cts +124 -0
  90. package/dist/http-response-BAhi8lF4.d.ts +124 -0
  91. package/dist/index-DingXh7B.d.cts +1187 -0
  92. package/dist/index-tOH7XBa3.d.ts +1187 -0
  93. package/dist/routing.type-DB4pt-d9.d.ts +184 -0
  94. package/dist/routing.type-DF2BIL7x.d.cts +184 -0
  95. package/dist/validation-error.type-kD4_qNZ9.d.cts +199 -0
  96. package/dist/validation-error.type-kD4_qNZ9.d.ts +199 -0
  97. package/package.json +191 -0
@@ -0,0 +1,1675 @@
1
+ import { B as BaseDto } from '../../base-dto.class-D7W9iqoU.cjs';
2
+ import { B as BaseInboundPort } from '../../index-DingXh7B.cjs';
3
+ export { A as AccessDeniedError, d as AccessGuard, e as AccessGuardResult, l as ApiKeyAuthScheme, o as AuthScheme, b as BaseController, a as BaseControllerConfig, C as ControllerError, E as EnhancedHttpRequest, f as EnhancedRequest, c as GuardedController, G as GuardedControllerConfig, n as HttpBasicAuthScheme, m as HttpBearerAuthScheme, j as HttpEndpointMetadata, k as HttpEndpointMetadataFor, H as HttpEndpointMethod, h as HttpEndpointOpenApi, i as HttpEndpointOpenApiFor, g as HttpSuccessStatus, I as InvalidRequestError, R as ResourceMetadata, q as SchemeNamesOf, r as SecurityRequirementOf, S as ServiceMetadata, p as SystemMetadata, v as assertHttpResponse, t as computeRoutePath, s as defineSystemMetadata, u as isHttpResponse } from '../../index-DingXh7B.cjs';
4
+ import { C as CodedError, A as AppErrorCode, D as DomainErrorCode, I as InfraErrorCode } from '../../validation-error.type-kD4_qNZ9.cjs';
5
+ import { j as BaseValueObject, i as BaseUuidV7Vo } from '../../base-uuid-v7.vo-BjqKX44G.cjs';
6
+ export { B as BaseAuditByVo, b as BaseAuditInfoVo, c as BaseAuditOnVo, d as BaseEmailVo, e as BaseLongTextVo, f as BaseMediumTextVo, g as BasePaginationVo, h as BaseShortTextVo, a as BaseUuidV4Vo, S as SKIP_VALUE_OBJECT_VALIDATION, k as SkipValueObjectValidation } from '../../base-uuid-v7.vo-BjqKX44G.cjs';
7
+ export { C as Controller, H as HttpRequest, a as HttpResponse } from '../../http-response-BAhi8lF4.cjs';
8
+ export { H as HttpMethod, b as RequestDtoFactory, R as RouteInput, a as RouteMetadata } from '../../routing.type-DF2BIL7x.cjs';
9
+
10
+ /**
11
+ * Abstract base class for use case handlers (inbound adapters).
12
+ *
13
+ * Implements the {@link BaseInboundPort} interface and provides:
14
+ * - Automatic error wrapping for unexpected exceptions
15
+ * - Pass-through for known error types (UseCaseError, DomainError, InfraError)
16
+ *
17
+ * Subclasses implement the `handle` method with the actual use case logic.
18
+ *
19
+ * @typeParam TInDto - Input DTO type, must extend BaseDto
20
+ * @typeParam TOutDto - Output DTO type, must extend BaseDto
21
+ *
22
+ * @example
23
+ * ```typescript
24
+ * class CreateUserUseCase extends BaseInboundAdapter<CreateUserInputDto, CreateUserOutputDto> {
25
+ * protected async handle(input: CreateUserInputDto): Promise<CreateUserOutputDto> {
26
+ * const user = await this.userRepo.create(input.value);
27
+ * return CreateUserOutputDto.create(user);
28
+ * }
29
+ * }
30
+ * ```
31
+ */
32
+ declare abstract class BaseInboundAdapter<TInDto extends BaseDto<unknown>, TOutDto extends BaseDto<unknown>> implements BaseInboundPort<TInDto, TOutDto> {
33
+ /**
34
+ * Implements the use case logic. Override this method in subclasses.
35
+ *
36
+ * @param input - Validated input DTO
37
+ * @returns Promise resolving to the output DTO
38
+ */
39
+ protected abstract handle(input: TInDto): Promise<TOutDto>;
40
+ /**
41
+ * Executes the use case with error boundary protection.
42
+ *
43
+ * Known error types are re-thrown as-is to preserve error semantics.
44
+ * Unknown errors are wrapped in a UseCaseError to maintain error hierarchy.
45
+ *
46
+ * @param input - Validated input DTO
47
+ * @returns Promise resolving to the output DTO
48
+ * @throws {ObjectValidationError} For validation failures (propagated to controller)
49
+ * @throws {UseCaseError} For use case failures or wrapped unknown errors
50
+ * @throws {DomainError} For domain invariant violations
51
+ * @throws {InfraError} For infrastructure failures
52
+ */
53
+ execute(input: TInDto): Promise<TOutDto>;
54
+ }
55
+
56
+ /**
57
+ * Base error class for application layer (use case) failures.
58
+ *
59
+ * Use case errors represent failures in the application's business logic
60
+ * orchestration, such as resource conflicts, missing entities, or
61
+ * unprocessable requests. They bridge domain errors to the presentation layer.
62
+ *
63
+ * **When to throw:**
64
+ * - Resource not found (e.g., "User with ID X not found")
65
+ * - Conflict states (e.g., "Email already registered")
66
+ * - Unprocessable business operations
67
+ *
68
+ * **Child classes:**
69
+ * - {@link ConflictError} - Resource state conflicts (HTTP 409)
70
+ * - {@link NotFoundError} - Resource not found (HTTP 404)
71
+ * - {@link UnprocessableError} - Valid but unprocessable request (HTTP 422)
72
+ *
73
+ * @example
74
+ * ```typescript
75
+ * const user = await this.userRepo.findById(id);
76
+ * if (!user) {
77
+ * throw new NotFoundError({
78
+ * message: `User with ID ${id} not found`,
79
+ * code: 'USER_NOT_FOUND',
80
+ * });
81
+ * }
82
+ * ```
83
+ */
84
+ declare class UseCaseError extends CodedError {
85
+ /**
86
+ * Creates a new UseCaseError instance.
87
+ *
88
+ * @param options - Error configuration
89
+ * @param options.message - Human-readable error description
90
+ * @param options.code - Machine-readable error code (default: 'USE_CASE_ERROR')
91
+ * @param options.cause - Optional underlying error
92
+ */
93
+ constructor({ message, code, cause, }: {
94
+ message: string;
95
+ code?: AppErrorCode | string;
96
+ cause?: unknown;
97
+ });
98
+ /**
99
+ * Creates a UseCaseError from a caught error.
100
+ *
101
+ * @param cause - The original caught error
102
+ * @returns A new UseCaseError instance with the cause attached
103
+ */
104
+ static fromError(cause: unknown): UseCaseError;
105
+ }
106
+
107
+ /**
108
+ * Error thrown when a requested resource does not exist.
109
+ *
110
+ * Indicates that the entity or resource referenced by the request
111
+ * could not be found in the system.
112
+ *
113
+ * **When to throw:**
114
+ * - Entity lookup by ID returns null
115
+ * - Referenced resource doesn't exist
116
+ * - Parent entity for a child operation not found
117
+ *
118
+ * @example
119
+ * ```typescript
120
+ * const user = await this.userRepo.findById(userId);
121
+ * if (!user) {
122
+ * throw new NotFoundError({
123
+ * message: `User with ID ${userId} not found`,
124
+ * code: 'USER_NOT_FOUND',
125
+ * });
126
+ * }
127
+ * ```
128
+ *
129
+ * @extends UseCaseError
130
+ */
131
+ declare class NotFoundError extends UseCaseError {
132
+ /**
133
+ * Creates a new NotFoundError instance.
134
+ *
135
+ * @param options - Error configuration
136
+ * @param options.message - Description of what was not found
137
+ * @param options.code - Machine-readable error code (default: 'NOT_FOUND')
138
+ * @param options.cause - Optional underlying error
139
+ */
140
+ constructor({ message, code, cause, }: {
141
+ message: string;
142
+ code?: AppErrorCode | string;
143
+ cause?: unknown;
144
+ });
145
+ /**
146
+ * Creates a NotFoundError from a caught error.
147
+ *
148
+ * @param cause - The original caught error
149
+ * @returns A new NotFoundError instance with the cause attached
150
+ */
151
+ static fromError(cause: unknown): NotFoundError;
152
+ }
153
+
154
+ /**
155
+ * Error thrown when an operation conflicts with existing state.
156
+ *
157
+ * Indicates that the requested operation cannot be completed because
158
+ * it would violate uniqueness constraints or cause state conflicts.
159
+ *
160
+ * **When to throw:**
161
+ * - Duplicate unique field (e.g., email already registered)
162
+ * - Optimistic locking conflict (stale version)
163
+ * - Concurrent modification detected
164
+ *
165
+ * @example
166
+ * ```typescript
167
+ * const existing = await this.userRepo.findByEmail(email);
168
+ * if (existing) {
169
+ * throw new ConflictError({
170
+ * message: 'Email already registered',
171
+ * code: 'EMAIL_ALREADY_EXISTS',
172
+ * });
173
+ * }
174
+ * ```
175
+ *
176
+ * @extends UseCaseError
177
+ */
178
+ declare class ConflictError extends UseCaseError {
179
+ /**
180
+ * Creates a new ConflictError instance.
181
+ *
182
+ * @param options - Error configuration
183
+ * @param options.message - Description of the conflict
184
+ * @param options.code - Machine-readable error code (default: 'CONFLICT')
185
+ * @param options.cause - Optional underlying error
186
+ */
187
+ constructor({ message, code, cause, }: {
188
+ message: string;
189
+ code?: AppErrorCode | string;
190
+ cause?: unknown;
191
+ });
192
+ /**
193
+ * Creates a ConflictError from a caught error.
194
+ *
195
+ * @param cause - The original caught error
196
+ * @returns A new ConflictError instance with the cause attached
197
+ */
198
+ static fromError(cause: unknown): ConflictError;
199
+ }
200
+
201
+ /**
202
+ * Error thrown when a request is valid but cannot be processed.
203
+ *
204
+ * The request is syntactically correct and passes validation, but
205
+ * business logic prevents the operation from being completed.
206
+ *
207
+ * **When to throw:**
208
+ * - Business rule prevents operation (e.g., insufficient balance)
209
+ * - Invalid state transition (e.g., canceling a completed order)
210
+ * - Preconditions not met for the operation
211
+ *
212
+ * @example
213
+ * ```typescript
214
+ * if (account.balance < amount) {
215
+ * throw new UnprocessableError({
216
+ * message: 'Insufficient balance for withdrawal',
217
+ * code: 'INSUFFICIENT_BALANCE',
218
+ * });
219
+ * }
220
+ * ```
221
+ *
222
+ * @extends UseCaseError
223
+ */
224
+ declare class UnprocessableError extends UseCaseError {
225
+ /**
226
+ * Creates a new UnprocessableError instance.
227
+ *
228
+ * @param options - Error configuration
229
+ * @param options.message - Description of why the request cannot be processed
230
+ * @param options.code - Machine-readable error code (default: 'UNPROCESSABLE')
231
+ * @param options.cause - Optional underlying error
232
+ */
233
+ constructor({ message, code, cause, }: {
234
+ message: string;
235
+ code?: AppErrorCode | string;
236
+ cause?: unknown;
237
+ });
238
+ /**
239
+ * Creates an UnprocessableError from a caught error.
240
+ *
241
+ * @param cause - The original caught error
242
+ * @returns A new UnprocessableError instance with the cause attached
243
+ */
244
+ static fromError(cause: unknown): UnprocessableError;
245
+ }
246
+
247
+ /**
248
+ * Base class for Domain-Driven Design Entities.
249
+ *
250
+ * Entities are domain objects that have a distinct identity that runs through
251
+ * time and different states. Unlike Value Objects (compared by value),
252
+ * Entities are compared by their identity (ID).
253
+ *
254
+ * **Note:** Entities should be composed of Value Objects, which are self-validating.
255
+ * Therefore, entity-level validation is not needed - VOs validate themselves
256
+ * at construction time. Cross-property invariants should be checked in factory methods.
257
+ *
258
+ * Key characteristics:
259
+ * - **Identity**: Each entity has a unique identifier (must be a Value Object)
260
+ * - **Equality by identity**: Two entities with the same ID are considered equal
261
+ * - **Mutable state**: Entity properties can change while identity remains
262
+ * - **Composed of VOs**: Properties should be Value Objects (self-validating)
263
+ * - **Versioning**: Optional version field for optimistic locking
264
+ *
265
+ * @typeParam TId - The identity type (must extend BaseValueObject)
266
+ * @typeParam TProps - The properties type containing entity state (must be an object)
267
+ *
268
+ * @example
269
+ * ```typescript
270
+ * interface UserProps {
271
+ * name: PersonName;
272
+ * email: Email;
273
+ * createdAt: DateVo;
274
+ * }
275
+ *
276
+ * class User extends BaseEntity<UserId, UserProps> {
277
+ * private constructor(id: UserId, props: UserProps, version?: number) {
278
+ * super(id, props, version);
279
+ * }
280
+ *
281
+ * static create(name: PersonName, email: Email): User {
282
+ * const id = UserId.create();
283
+ * return new User(id, {
284
+ * name,
285
+ * email,
286
+ * createdAt: DateVo.now(),
287
+ * });
288
+ * }
289
+ *
290
+ * static fromPersistence(id: UserId, props: UserProps, version: number): User {
291
+ * return new User(id, props, version);
292
+ * }
293
+ *
294
+ * get name(): PersonName {
295
+ * return this.props.name;
296
+ * }
297
+ *
298
+ * get email(): Email {
299
+ * return this.props.email;
300
+ * }
301
+ *
302
+ * changeName(newName: PersonName): void {
303
+ * this._props.name = newName;
304
+ * }
305
+ * }
306
+ *
307
+ * const user1 = User.create(PersonName.create('John'), Email.create('john@example.com'));
308
+ * const user2 = User.fromPersistence(user1.id, { ...user1.props }, user1.version);
309
+ * user1.equals(user2); // true - same ID
310
+ * ```
311
+ */
312
+ declare abstract class BaseEntity<TId extends BaseValueObject<unknown>, TProps extends object> {
313
+ private readonly _id;
314
+ protected _props: TProps;
315
+ private readonly _version;
316
+ /**
317
+ * Creates a new Entity instance.
318
+ *
319
+ * @param id - The unique identifier for this entity
320
+ * @param props - The entity's properties/state (should be composed of Value Objects)
321
+ * @param version - Optional version number for optimistic locking (defaults to 0)
322
+ */
323
+ protected constructor(id: TId, props: TProps, version?: number);
324
+ /**
325
+ * The unique identifier for this entity.
326
+ *
327
+ * @returns The entity's ID of type TId
328
+ */
329
+ get id(): TId;
330
+ /**
331
+ * The entity's properties/state.
332
+ *
333
+ * Protected to encourage encapsulation via specific getters.
334
+ * Subclasses should expose individual properties as needed.
335
+ *
336
+ * @returns The entity's properties of type TProps
337
+ */
338
+ protected get props(): TProps;
339
+ /**
340
+ * The version number for optimistic locking.
341
+ *
342
+ * Use this to detect concurrent modifications:
343
+ * - Load entity with version N
344
+ * - Attempt to save with "WHERE version = N"
345
+ * - If rows affected = 0, another process modified the entity
346
+ *
347
+ * @returns The current version number
348
+ */
349
+ get version(): number;
350
+ /**
351
+ * Compares this Entity with another for equality.
352
+ *
353
+ * Entities are equal if they have the same identity (ID).
354
+ * This differs from Value Objects which compare by value.
355
+ *
356
+ * @param other - The Entity to compare with
357
+ * @returns `true` if the IDs are equal, `false` otherwise
358
+ *
359
+ * @example
360
+ * ```typescript
361
+ * const user1 = User.create(PersonName.create('John'), Email.create('john@example.com'));
362
+ * const user2 = User.fromPersistence(user1.id, { name: PersonName.create('John Updated'), ... }, 1);
363
+ * user1.equals(user2); // true - same ID, different state
364
+ * ```
365
+ */
366
+ equals(other: BaseEntity<TId, TProps>): boolean;
367
+ /**
368
+ * Compares two IDs for equality.
369
+ *
370
+ * Since TId must extend BaseValueObject, we use the value object's
371
+ * `equals` method for comparison.
372
+ *
373
+ * @param a - First ID to compare
374
+ * @param b - Second ID to compare
375
+ * @returns `true` if IDs are equal, `false` otherwise
376
+ */
377
+ protected idEquals(a: TId, b: TId): boolean;
378
+ /**
379
+ * Returns the next version number.
380
+ *
381
+ * Call this when persisting changes to implement optimistic locking.
382
+ * The repository should save with version + 1.
383
+ *
384
+ * @returns The next version number (current + 1)
385
+ *
386
+ * @example
387
+ * ```typescript
388
+ * // In repository
389
+ * async save(entity: User): Promise<void> {
390
+ * await this.db.update({
391
+ * ...entity.toPersistence(),
392
+ * version: entity.nextVersion(),
393
+ * }).where({ id: entity.id, version: entity.version });
394
+ * }
395
+ * ```
396
+ */
397
+ protected nextVersion(): number;
398
+ }
399
+
400
+ /**
401
+ * Base class for Domain Events in Domain-Driven Design.
402
+ *
403
+ * Domain Events represent something meaningful that happened in the domain.
404
+ * They are immutable records of past occurrences that other parts of the
405
+ * system can react to.
406
+ *
407
+ * Key characteristics:
408
+ * - **Immutable**: Events are facts about the past, they cannot change
409
+ * - **Named in past tense**: e.g., OrderPlaced, UserRegistered, PaymentReceived
410
+ * - **Contain relevant data**: Include all information needed by handlers
411
+ * - **Raised by Aggregate Roots**: Events are collected and published after persistence
412
+ *
413
+ * @typeParam TPayload - The event-specific data payload type
414
+ *
415
+ * @example
416
+ * ```typescript
417
+ * interface OrderPlacedPayload {
418
+ * orderId: string;
419
+ * customerId: string;
420
+ * items: Array<{ productId: string; quantity: number }>;
421
+ * totalAmount: number;
422
+ * }
423
+ *
424
+ * class OrderPlacedEvent extends BaseDomainEvent<OrderPlacedPayload> {
425
+ * constructor(payload: OrderPlacedPayload) {
426
+ * super('OrderPlaced', payload.orderId, payload);
427
+ * }
428
+ * }
429
+ *
430
+ * // In aggregate root
431
+ * class Order extends BaseAggregateRoot<OrderId, OrderProps> {
432
+ * static create(customerId: string, items: OrderItem[]): Order {
433
+ * const order = new Order(...);
434
+ * order.addDomainEvent(new OrderPlacedEvent({
435
+ * orderId: order.id.value,
436
+ * customerId,
437
+ * items: items.map(i => ({ productId: i.productId, quantity: i.quantity })),
438
+ * totalAmount: order.totalAmount,
439
+ * }));
440
+ * return order;
441
+ * }
442
+ * }
443
+ * ```
444
+ */
445
+ declare abstract class BaseDomainEvent<TPayload = unknown> {
446
+ private readonly _eventId;
447
+ private readonly _eventName;
448
+ private readonly _aggregateId;
449
+ private readonly _occurredOn;
450
+ private readonly _payload;
451
+ /**
452
+ * Deep clones an object, handling Date objects specially.
453
+ *
454
+ * @param obj - The object to clone
455
+ * @returns A deep copy of the object
456
+ */
457
+ private static deepClone;
458
+ /**
459
+ * Recursively freezes an object and all nested objects.
460
+ *
461
+ * @param obj - The object to deep freeze
462
+ * @returns The frozen object
463
+ */
464
+ private static deepFreeze;
465
+ /**
466
+ * Creates an immutable copy of the payload.
467
+ *
468
+ * Clones the payload first to avoid mutating the original object,
469
+ * then deep-freezes the clone to ensure immutability.
470
+ *
471
+ * @param payload - The payload to clone and freeze
472
+ * @returns An immutable copy of the payload
473
+ */
474
+ private static cloneAndFreeze;
475
+ /**
476
+ * Creates a new Domain Event.
477
+ *
478
+ * The payload is cloned and deep-frozen to ensure immutability. The original
479
+ * object passed in remains unmodified. Any attempt to modify the event's
480
+ * payload after creation will throw a TypeError in strict mode.
481
+ *
482
+ * @param eventName - The name of the event (e.g., 'OrderPlaced', 'UserRegistered')
483
+ * @param aggregateId - The ID of the aggregate that raised this event
484
+ * @param payload - The event-specific data (will be cloned and deep-frozen)
485
+ * @param eventId - Optional custom event ID (defaults to crypto.randomUUID())
486
+ * @param occurredOn - Optional timestamp (defaults to now)
487
+ */
488
+ protected constructor(eventName: string, aggregateId: string, payload: TPayload, eventId?: string, occurredOn?: Date);
489
+ /**
490
+ * Unique identifier for this event instance.
491
+ *
492
+ * Useful for idempotency checks and event deduplication.
493
+ */
494
+ get eventId(): string;
495
+ /**
496
+ * The name/type of this event.
497
+ *
498
+ * Used for routing events to appropriate handlers.
499
+ * Should be in PastTense format (e.g., 'OrderPlaced', 'UserRegistered').
500
+ */
501
+ get eventName(): string;
502
+ /**
503
+ * The ID of the aggregate that raised this event.
504
+ *
505
+ * Useful for event sourcing and aggregate-specific event streams.
506
+ */
507
+ get aggregateId(): string;
508
+ /**
509
+ * Timestamp when this event occurred.
510
+ *
511
+ * Represents the moment the domain action happened.
512
+ */
513
+ get occurredOn(): Date;
514
+ /**
515
+ * The event-specific data payload.
516
+ *
517
+ * Contains all information needed by event handlers.
518
+ */
519
+ get payload(): TPayload;
520
+ /**
521
+ * Serializes the event to a plain object for persistence or messaging.
522
+ *
523
+ * @returns A plain object representation of the event
524
+ *
525
+ * @example
526
+ * ```typescript
527
+ * const event = new OrderPlacedEvent({ orderId: '123', ... });
528
+ * const serialized = event.toJSON();
529
+ * // {
530
+ * // eventId: 'uuid',
531
+ * // eventName: 'OrderPlaced',
532
+ * // aggregateId: '123',
533
+ * // occurredOn: '2024-01-15T10:30:00.000Z',
534
+ * // payload: { orderId: '123', ... }
535
+ * // }
536
+ * ```
537
+ */
538
+ toJSON(): {
539
+ eventId: string;
540
+ eventName: string;
541
+ aggregateId: string;
542
+ occurredOn: string;
543
+ payload: TPayload;
544
+ };
545
+ }
546
+
547
+ /**
548
+ * Base class for Aggregate Roots in Domain-Driven Design.
549
+ *
550
+ * An Aggregate Root is a special Entity that serves as the entry point to an
551
+ * aggregate - a cluster of domain objects that are treated as a single unit
552
+ * for data changes. The Aggregate Root enforces invariants across the entire
553
+ * aggregate and manages domain events.
554
+ *
555
+ * **Note:** Like entities, aggregate roots should be composed of Value Objects,
556
+ * which are self-validating. Cross-property invariants should be checked in
557
+ * factory methods or domain methods.
558
+ *
559
+ * Key characteristics:
560
+ * - **Entry point**: External objects can only reference the Aggregate Root
561
+ * - **Consistency boundary**: All changes within the aggregate are atomic
562
+ * - **Invariant enforcement**: The root ensures all business rules are satisfied
563
+ * - **Event management**: Collects domain events raised during operations
564
+ *
565
+ * @typeParam TId - The identity type (must extend BaseValueObject)
566
+ * @typeParam TProps - The properties type containing aggregate state (must be an object)
567
+ *
568
+ * @example
569
+ * ```typescript
570
+ * interface OrderProps {
571
+ * customerId: CustomerId;
572
+ * items: OrderItem[];
573
+ * status: OrderStatus;
574
+ * placedAt: DateVo;
575
+ * }
576
+ *
577
+ * class Order extends BaseAggregateRoot<OrderId, OrderProps> {
578
+ * private constructor(id: OrderId, props: OrderProps, version?: number) {
579
+ * super(id, props, version);
580
+ * }
581
+ *
582
+ * static create(customerId: CustomerId, items: OrderItem[]): Order {
583
+ * const id = OrderId.create();
584
+ * const order = new Order(id, {
585
+ * customerId,
586
+ * items,
587
+ * status: OrderStatus.pending(),
588
+ * placedAt: DateVo.now(),
589
+ * });
590
+ *
591
+ * // Raise domain event
592
+ * order.addDomainEvent(new OrderPlacedEvent({
593
+ * orderId: id.value,
594
+ * customerId: customerId.value,
595
+ * itemCount: items.length,
596
+ * }));
597
+ *
598
+ * return order;
599
+ * }
600
+ *
601
+ * static fromPersistence(id: OrderId, props: OrderProps, version: number): Order {
602
+ * return new Order(id, props, version);
603
+ * }
604
+ *
605
+ * addItem(item: OrderItem): void {
606
+ * if (!this.props.status.isPending()) {
607
+ * throw new InvariantViolationError({
608
+ * message: 'Cannot add items to a non-pending order',
609
+ * });
610
+ * }
611
+ * this._props.items.push(item);
612
+ * this.addDomainEvent(new OrderItemAddedEvent({
613
+ * orderId: this.id.value,
614
+ * productId: item.productId.value,
615
+ * }));
616
+ * }
617
+ *
618
+ * confirm(): void {
619
+ * this._props.status = OrderStatus.confirmed();
620
+ * this.addDomainEvent(new OrderConfirmedEvent({ orderId: this.id.value }));
621
+ * }
622
+ * }
623
+ *
624
+ * // In repository after save:
625
+ * async save(order: Order): Promise<void> {
626
+ * await this.db.save(order.toPersistence());
627
+ * const events = order.pullDomainEvents();
628
+ * await this.eventPublisher.publishAll(events);
629
+ * }
630
+ * ```
631
+ */
632
+ declare abstract class BaseAggregateRoot<TId extends BaseValueObject<unknown>, TProps extends object> extends BaseEntity<TId, TProps> {
633
+ private _domainEvents;
634
+ /**
635
+ * Creates a new Aggregate Root instance.
636
+ *
637
+ * @param id - The unique identifier for this aggregate
638
+ * @param props - The aggregate's properties/state (should be composed of Value Objects)
639
+ * @param version - Optional version number for optimistic locking (defaults to 0)
640
+ */
641
+ protected constructor(id: TId, props: TProps, version?: number);
642
+ /**
643
+ * Adds a domain event to be published after persistence.
644
+ *
645
+ * Call this method when a significant domain action occurs.
646
+ * Events are collected and should be published by the repository
647
+ * after successfully persisting the aggregate.
648
+ *
649
+ * @param event - The domain event to add
650
+ *
651
+ * @example
652
+ * ```typescript
653
+ * confirm(): void {
654
+ * this._props.status = OrderStatus.confirmed();
655
+ * this.addDomainEvent(new OrderConfirmedEvent({
656
+ * orderId: this.id.value,
657
+ * confirmedAt: new Date(),
658
+ * }));
659
+ * }
660
+ * ```
661
+ */
662
+ protected addDomainEvent(event: BaseDomainEvent): void;
663
+ /**
664
+ * Returns and clears all pending domain events.
665
+ *
666
+ * This method should be called by the repository after successfully
667
+ * persisting the aggregate. The events are cleared to prevent
668
+ * duplicate publishing.
669
+ *
670
+ * @returns Array of domain events that were pending
671
+ *
672
+ * @example
673
+ * ```typescript
674
+ * // In repository
675
+ * async save(order: Order): Promise<void> {
676
+ * await this.db.transaction(async (tx) => {
677
+ * await tx.orders.upsert(order.toPersistence());
678
+ * });
679
+ *
680
+ * // Only publish after successful persistence
681
+ * const events = order.pullDomainEvents();
682
+ * for (const event of events) {
683
+ * await this.eventBus.publish(event);
684
+ * }
685
+ * }
686
+ * ```
687
+ */
688
+ pullDomainEvents(): BaseDomainEvent[];
689
+ /**
690
+ * Returns pending domain events without clearing them.
691
+ *
692
+ * Useful for inspection or testing without affecting the event queue.
693
+ *
694
+ * @returns Array of pending domain events
695
+ */
696
+ peekDomainEvents(): readonly BaseDomainEvent[];
697
+ /**
698
+ * Checks if there are any pending domain events.
699
+ *
700
+ * @returns `true` if there are events waiting to be published
701
+ *
702
+ * @example
703
+ * ```typescript
704
+ * if (order.hasDomainEvents) {
705
+ * const events = order.pullDomainEvents();
706
+ * await eventBus.publishAll(events);
707
+ * }
708
+ * ```
709
+ */
710
+ get hasDomainEvents(): boolean;
711
+ /**
712
+ * Clears all pending domain events without returning them.
713
+ *
714
+ * Use with caution - this discards events that haven't been published.
715
+ * Useful in testing or when intentionally discarding events.
716
+ */
717
+ protected clearDomainEvents(): void;
718
+ }
719
+
720
+ /**
721
+ * Base error class for domain layer failures.
722
+ *
723
+ * Domain errors represent violations of business rules, invariants,
724
+ * or aggregate consistency. They originate from the core domain logic
725
+ * and should be caught and handled by the application layer.
726
+ *
727
+ * **When to throw:**
728
+ * - Business rule violations (e.g., "Cannot withdraw more than balance")
729
+ * - Invariant violations (e.g., "Email format invalid")
730
+ * - Aggregate consistency failures
731
+ *
732
+ * **Child classes:**
733
+ * - {@link InvariantViolationError} - Value object or entity invariant failures
734
+ * - {@link PartialLoadError} - Incomplete aggregate reconstitution
735
+ *
736
+ * @example
737
+ * ```typescript
738
+ * if (account.balance < amount) {
739
+ * throw new DomainError({
740
+ * message: 'Insufficient funds for withdrawal',
741
+ * code: 'INSUFFICIENT_FUNDS',
742
+ * });
743
+ * }
744
+ * ```
745
+ */
746
+ declare class DomainError extends CodedError {
747
+ /**
748
+ * Creates a new DomainError instance.
749
+ *
750
+ * @param options - Error configuration
751
+ * @param options.message - Human-readable error description
752
+ * @param options.code - Machine-readable error code (default: 'DOMAIN_ERROR')
753
+ * @param options.cause - Optional underlying error
754
+ */
755
+ constructor({ message, code, cause, }: {
756
+ message: string;
757
+ code?: DomainErrorCode | string;
758
+ cause?: unknown;
759
+ });
760
+ /**
761
+ * Creates a DomainError from a caught error.
762
+ *
763
+ * @param cause - The original caught error
764
+ * @returns A new DomainError instance with the cause attached
765
+ */
766
+ static fromError(cause: unknown): DomainError;
767
+ }
768
+
769
+ /**
770
+ * Error thrown when a domain invariant is violated.
771
+ *
772
+ * Invariants are business rules that must always be true. This error
773
+ * indicates a programming error or corrupted state—if inputs are
774
+ * properly validated, this should never occur in production.
775
+ *
776
+ * **When to throw:**
777
+ * - Business rule violations (e.g., `updatedAt < createdAt`)
778
+ * - Assert-style guards in domain logic
779
+ * - Invalid state transitions
780
+ *
781
+ * @example
782
+ * ```typescript
783
+ * if (order.status === 'shipped' && order.items.length === 0) {
784
+ * throw new InvariantViolationError({
785
+ * message: 'Shipped order must have at least one item',
786
+ * code: 'EMPTY_SHIPPED_ORDER',
787
+ * });
788
+ * }
789
+ * ```
790
+ *
791
+ * @extends DomainError
792
+ */
793
+ declare class InvariantViolationError extends DomainError {
794
+ /**
795
+ * Creates a new InvariantViolationError instance.
796
+ *
797
+ * @param options - Error configuration
798
+ * @param options.message - Description of the violated invariant
799
+ * @param options.code - Machine-readable error code (default: 'INVARIANT_VIOLATION')
800
+ * @param options.cause - Optional underlying error
801
+ */
802
+ constructor({ message, code, cause, }: {
803
+ message: string;
804
+ code?: DomainErrorCode | string;
805
+ cause?: unknown;
806
+ });
807
+ /**
808
+ * Creates an InvariantViolationError from a caught error.
809
+ *
810
+ * @param cause - The original caught error
811
+ * @returns A new InvariantViolationError instance with the cause attached
812
+ */
813
+ static fromError(cause: unknown): InvariantViolationError;
814
+ }
815
+
816
+ /**
817
+ * Error thrown when an entity or aggregate is partially loaded.
818
+ *
819
+ * Indicates that required data is missing, typically due to incomplete
820
+ * database queries or lazy loading issues. This error should not escape
821
+ * the application boundary—it represents an internal system failure.
822
+ *
823
+ * **When to throw:**
824
+ * - Required relation not loaded
825
+ * - Aggregate missing expected child entities
826
+ * - Incomplete projection from data layer
827
+ *
828
+ * @example
829
+ * ```typescript
830
+ * if (!order.customer) {
831
+ * throw new PartialLoadError({
832
+ * message: 'Order customer relation not loaded',
833
+ * code: 'ORDER_CUSTOMER_NOT_LOADED',
834
+ * });
835
+ * }
836
+ * ```
837
+ *
838
+ * @extends DomainError
839
+ */
840
+ declare class PartialLoadError extends DomainError {
841
+ /**
842
+ * Creates a new PartialLoadError instance.
843
+ *
844
+ * @param options - Error configuration
845
+ * @param options.message - Description of what was not loaded
846
+ * @param options.code - Machine-readable error code (default: 'PARTIAL_LOAD')
847
+ * @param options.cause - Optional underlying error
848
+ */
849
+ constructor({ message, code, cause, }: {
850
+ message: string;
851
+ code?: DomainErrorCode | string;
852
+ cause?: unknown;
853
+ });
854
+ /**
855
+ * Creates a PartialLoadError from a caught error.
856
+ *
857
+ * @param cause - The original caught error
858
+ * @returns A new PartialLoadError instance with the cause attached
859
+ */
860
+ static fromError(cause: unknown): PartialLoadError;
861
+ }
862
+
863
+ /**
864
+ * The underlying value structure for Money.
865
+ */
866
+ interface MoneyValue {
867
+ amount: number;
868
+ currency: string;
869
+ }
870
+ /**
871
+ * Value Object representing a monetary amount with currency.
872
+ *
873
+ * Provides arithmetic operations and comparison methods.
874
+ * Prevents operations between different currencies.
875
+ *
876
+ * @example
877
+ * ```typescript
878
+ * const price = Money.usd(29.99);
879
+ * const tax = Money.usd(2.40);
880
+ * const total = price.add(tax);
881
+ *
882
+ * console.log(total.amount); // 32.39
883
+ * console.log(total.currency); // 'USD'
884
+ *
885
+ * if (total.isGreaterThan(Money.usd(30))) {
886
+ * // Apply discount
887
+ * }
888
+ * ```
889
+ */
890
+ declare class Money extends BaseValueObject<MoneyValue> {
891
+ /**
892
+ * Creates a Money instance with USD currency.
893
+ *
894
+ * @param amount - The monetary amount
895
+ */
896
+ static usd(amount: number): Money;
897
+ /**
898
+ * Creates a Money instance with EUR currency.
899
+ *
900
+ * @param amount - The monetary amount
901
+ */
902
+ static eur(amount: number): Money;
903
+ /**
904
+ * Creates a zero amount in the specified currency.
905
+ *
906
+ * @param currency - The currency code (default: 'USD')
907
+ */
908
+ static zero(currency?: string): Money;
909
+ /**
910
+ * Reconstitutes a Money from a persisted value.
911
+ *
912
+ * @param value - The money value from persistence
913
+ */
914
+ static fromPersistence(value: MoneyValue): Money;
915
+ /**
916
+ * The monetary amount.
917
+ */
918
+ get amount(): number;
919
+ /**
920
+ * The currency code.
921
+ */
922
+ get currency(): string;
923
+ /**
924
+ * Adds another Money value to this one.
925
+ *
926
+ * @param other - The Money to add
927
+ * @throws {InvariantViolationError} If currencies don't match
928
+ */
929
+ add(other: Money): Money;
930
+ /**
931
+ * Subtracts another Money value from this one.
932
+ *
933
+ * @param other - The Money to subtract
934
+ * @throws {InvariantViolationError} If currencies don't match
935
+ */
936
+ subtract(other: Money): Money;
937
+ /**
938
+ * Multiplies this Money by a factor.
939
+ *
940
+ * @param factor - The multiplication factor
941
+ */
942
+ multiply(factor: number): Money;
943
+ /**
944
+ * Checks if this Money is greater than another.
945
+ *
946
+ * @param other - The Money to compare with
947
+ * @throws {InvariantViolationError} If currencies don't match
948
+ */
949
+ isGreaterThan(other: Money): boolean;
950
+ /**
951
+ * Checks if this Money is less than another.
952
+ *
953
+ * @param other - The Money to compare with
954
+ * @throws {InvariantViolationError} If currencies don't match
955
+ */
956
+ isLessThan(other: Money): boolean;
957
+ /**
958
+ * Checks if this Money represents zero.
959
+ */
960
+ isZero(): boolean;
961
+ /**
962
+ * Asserts that two Money values have the same currency.
963
+ * @internal
964
+ */
965
+ private assertSameCurrency;
966
+ }
967
+
968
+ /**
969
+ * Value Object representing an Order's unique identifier.
970
+ *
971
+ * Extends BaseUuidV7Vo to use time-ordered UUIDs for better
972
+ * database indexing and natural ordering.
973
+ *
974
+ * @example
975
+ * ```typescript
976
+ * const orderId = OrderId.create();
977
+ * console.log(orderId.value); // '01902e8a-7c3b-7def-8a1b-...'
978
+ *
979
+ * orderId.equals(anotherOrderId); // true if same value
980
+ * ```
981
+ */
982
+ declare class OrderId extends BaseUuidV7Vo {
983
+ }
984
+
985
+ /**
986
+ * Possible values for an order's status.
987
+ */
988
+ type OrderStatusValue = 'pending' | 'confirmed' | 'shipped' | 'cancelled';
989
+ /**
990
+ * Value Object representing an Order's status.
991
+ *
992
+ * Provides type-safe status values with behavior methods for checking state.
993
+ * Uses static factory methods to ensure only valid statuses can be created.
994
+ *
995
+ * @example
996
+ * ```typescript
997
+ * const status = OrderStatus.pending();
998
+ *
999
+ * if (status.isPending()) {
1000
+ * // Can modify order
1001
+ * }
1002
+ *
1003
+ * if (status.isShipped()) {
1004
+ * // Cannot cancel
1005
+ * }
1006
+ * ```
1007
+ */
1008
+ declare class OrderStatus extends BaseValueObject<OrderStatusValue> {
1009
+ /**
1010
+ * Creates a new OrderStatus with 'pending' value.
1011
+ * Use when creating new orders.
1012
+ */
1013
+ static pending(): OrderStatus;
1014
+ /**
1015
+ * Creates a new OrderStatus with 'confirmed' value.
1016
+ * Use when payment is received.
1017
+ */
1018
+ static confirmed(): OrderStatus;
1019
+ /**
1020
+ * Creates a new OrderStatus with 'shipped' value.
1021
+ * Use when order is dispatched.
1022
+ */
1023
+ static shipped(): OrderStatus;
1024
+ /**
1025
+ * Creates a new OrderStatus with 'cancelled' value.
1026
+ * Use when order is cancelled by customer or system.
1027
+ */
1028
+ static cancelled(): OrderStatus;
1029
+ /**
1030
+ * Reconstitutes an OrderStatus from a persisted value.
1031
+ *
1032
+ * @param value - The status value from persistence
1033
+ */
1034
+ static fromPersistence(value: OrderStatusValue): OrderStatus;
1035
+ /**
1036
+ * Checks if the order is in pending status.
1037
+ */
1038
+ isPending(): boolean;
1039
+ /**
1040
+ * Checks if the order is confirmed.
1041
+ */
1042
+ isConfirmed(): boolean;
1043
+ /**
1044
+ * Checks if the order has been shipped.
1045
+ */
1046
+ isShipped(): boolean;
1047
+ /**
1048
+ * Checks if the order has been cancelled.
1049
+ */
1050
+ isCancelled(): boolean;
1051
+ /**
1052
+ * Checks if the order can still be modified (pending or confirmed).
1053
+ */
1054
+ isModifiable(): boolean;
1055
+ }
1056
+
1057
+ /**
1058
+ * Value Object representing an OrderItem's unique identifier.
1059
+ */
1060
+ declare class OrderItemId extends BaseUuidV7Vo {
1061
+ }
1062
+
1063
+ /**
1064
+ * Properties for an OrderItem entity.
1065
+ */
1066
+ interface OrderItemProps {
1067
+ productId: string;
1068
+ productName: string;
1069
+ quantity: number;
1070
+ unitPrice: Money;
1071
+ }
1072
+ /**
1073
+ * Entity representing a line item within an Order aggregate.
1074
+ *
1075
+ * OrderItem is not an aggregate root - it's accessed through the Order aggregate.
1076
+ * It has its own identity but cannot exist independently of an Order.
1077
+ *
1078
+ * @example
1079
+ * ```typescript
1080
+ * const item = OrderItem.create({
1081
+ * productId: 'prod-123',
1082
+ * productName: 'Widget',
1083
+ * quantity: 2,
1084
+ * unitPrice: Money.usd(29.99),
1085
+ * });
1086
+ *
1087
+ * console.log(item.totalPrice.amount); // 59.98
1088
+ * ```
1089
+ */
1090
+ declare class OrderItem extends BaseEntity<OrderItemId, OrderItemProps> {
1091
+ private constructor();
1092
+ /**
1093
+ * Creates a new OrderItem.
1094
+ */
1095
+ static create(props: OrderItemProps): OrderItem;
1096
+ /**
1097
+ * Reconstitutes an OrderItem from persistence.
1098
+ */
1099
+ static fromPersistence(id: OrderItemId, props: OrderItemProps): OrderItem;
1100
+ get productId(): string;
1101
+ get productName(): string;
1102
+ get quantity(): number;
1103
+ get unitPrice(): Money;
1104
+ /**
1105
+ * Calculates the total price for this line item.
1106
+ */
1107
+ get totalPrice(): Money;
1108
+ /**
1109
+ * Updates the quantity of this item.
1110
+ */
1111
+ updateQuantity(newQuantity: number): void;
1112
+ /**
1113
+ * Converts to a plain object for events or persistence.
1114
+ */
1115
+ toPlain(): {
1116
+ id: string;
1117
+ productId: string;
1118
+ productName: string;
1119
+ quantity: number;
1120
+ unitPrice: {
1121
+ amount: number;
1122
+ currency: string;
1123
+ };
1124
+ };
1125
+ }
1126
+
1127
+ /**
1128
+ * Properties for the Order aggregate.
1129
+ */
1130
+ interface OrderProps {
1131
+ customerId: string;
1132
+ items: OrderItem[];
1133
+ status: OrderStatus;
1134
+ totalAmount: Money;
1135
+ placedAt: Date;
1136
+ }
1137
+ /**
1138
+ * Order Aggregate Root.
1139
+ *
1140
+ * Represents a customer's order with line items. The Order is the aggregate root
1141
+ * and controls access to its OrderItems. All modifications go through the Order
1142
+ * to ensure business invariants are maintained.
1143
+ *
1144
+ * **Policies used:**
1145
+ * - Value: `defaultOrderStatus` - New orders start as 'pending'
1146
+ * - Business: `canAddOrderItem` - Items can only be added to pending orders
1147
+ * - Business: `canCancelOrder` - Orders can only be cancelled if not shipped
1148
+ *
1149
+ * **Events raised:**
1150
+ * - `OrderPlacedEvent` - When order is created
1151
+ * - `OrderCancelledEvent` - When order is cancelled
1152
+ *
1153
+ * @example
1154
+ * ```typescript
1155
+ * // Create a new order
1156
+ * const order = Order.create('customer-123', [
1157
+ * OrderItem.create({
1158
+ * productId: 'prod-1',
1159
+ * productName: 'Widget',
1160
+ * quantity: 2,
1161
+ * unitPrice: Money.usd(29.99),
1162
+ * }),
1163
+ * ]);
1164
+ *
1165
+ * // Add another item
1166
+ * order.addItem(OrderItem.create({
1167
+ * productId: 'prod-2',
1168
+ * productName: 'Gadget',
1169
+ * quantity: 1,
1170
+ * unitPrice: Money.usd(49.99),
1171
+ * }));
1172
+ *
1173
+ * // Cancel the order
1174
+ * order.cancel('Customer changed their mind');
1175
+ *
1176
+ * // Get events for publishing
1177
+ * const events = order.pullDomainEvents();
1178
+ * ```
1179
+ */
1180
+ declare class Order extends BaseAggregateRoot<OrderId, OrderProps> {
1181
+ private constructor();
1182
+ /**
1183
+ * Creates a new Order.
1184
+ *
1185
+ * @param customerId - The customer placing the order
1186
+ * @param items - Initial order items
1187
+ * @returns A new Order instance with OrderPlacedEvent raised
1188
+ */
1189
+ static create(customerId: string, items: OrderItem[]): Order;
1190
+ /**
1191
+ * Reconstitutes an Order from persistence.
1192
+ *
1193
+ * @param id - The order ID
1194
+ * @param props - The order properties
1195
+ * @param version - The version for optimistic locking
1196
+ */
1197
+ static fromPersistence(id: OrderId, props: OrderProps, version: number): Order;
1198
+ get customerId(): string;
1199
+ get items(): readonly OrderItem[];
1200
+ get status(): OrderStatus;
1201
+ get totalAmount(): Money;
1202
+ get placedAt(): Date;
1203
+ /**
1204
+ * Adds an item to the order.
1205
+ *
1206
+ * Uses the `canAddOrderItem` business policy to check if the operation is allowed.
1207
+ *
1208
+ * @param item - The item to add
1209
+ * @throws {InvariantViolationError} If the order is not in pending status
1210
+ */
1211
+ addItem(item: OrderItem): void;
1212
+ /**
1213
+ * Confirms the order (e.g., after payment received).
1214
+ *
1215
+ * @throws {InvariantViolationError} If the order is not in pending status
1216
+ */
1217
+ confirm(): void;
1218
+ /**
1219
+ * Marks the order as shipped.
1220
+ *
1221
+ * @throws {InvariantViolationError} If the order is not confirmed
1222
+ */
1223
+ ship(): void;
1224
+ /**
1225
+ * Cancels the order.
1226
+ *
1227
+ * Uses the `canCancelOrder` business policy to check if the operation is allowed.
1228
+ *
1229
+ * @param reason - The reason for cancellation
1230
+ * @throws {InvariantViolationError} If the order cannot be cancelled
1231
+ */
1232
+ cancel(reason: string): void;
1233
+ }
1234
+
1235
+ /**
1236
+ * Business Policy: Determines if items can be added to an order.
1237
+ *
1238
+ * Items can only be added to orders that are still in 'pending' status.
1239
+ * Once an order is confirmed, shipped, or cancelled, items cannot be added.
1240
+ *
1241
+ * @param order - The order to check
1242
+ * @returns `true` if items can be added to the order
1243
+ *
1244
+ * @example
1245
+ * ```typescript
1246
+ * if (!canAddOrderItem(order)) {
1247
+ * throw new InvariantViolationError({
1248
+ * message: 'Cannot add items to non-pending order',
1249
+ * code: 'ORDER_NOT_PENDING',
1250
+ * });
1251
+ * }
1252
+ * ```
1253
+ */
1254
+ declare const canAddOrderItem: (order: Order) => boolean;
1255
+
1256
+ /**
1257
+ * Business Policy: Determines if an order can be cancelled.
1258
+ *
1259
+ * Orders can only be cancelled if they have not yet been shipped.
1260
+ * Once an order is shipped or delivered, it cannot be cancelled.
1261
+ *
1262
+ * @param order - The order to check
1263
+ * @returns `true` if the order can be cancelled
1264
+ *
1265
+ * @example
1266
+ * ```typescript
1267
+ * if (!canCancelOrder(order)) {
1268
+ * throw new InvariantViolationError({
1269
+ * message: 'Order cannot be cancelled',
1270
+ * code: 'ORDER_CANNOT_CANCEL',
1271
+ * });
1272
+ * }
1273
+ * ```
1274
+ */
1275
+ declare const canCancelOrder: (order: Order) => boolean;
1276
+
1277
+ /**
1278
+ * Value Policy: Default order status for new orders.
1279
+ *
1280
+ * New orders start in 'pending' status, awaiting payment confirmation.
1281
+ *
1282
+ * @returns The default OrderStatus (pending)
1283
+ *
1284
+ * @example
1285
+ * ```typescript
1286
+ * const order = new Order(id, {
1287
+ * status: defaultOrderStatus(),
1288
+ * // ...
1289
+ * });
1290
+ * ```
1291
+ */
1292
+ declare const defaultOrderStatus: () => OrderStatus;
1293
+
1294
+ /**
1295
+ * Payload for the OrderCancelled domain event.
1296
+ */
1297
+ interface OrderCancelledPayload {
1298
+ orderId: string;
1299
+ reason: string;
1300
+ cancelledAt: string;
1301
+ }
1302
+ /**
1303
+ * Domain event raised when an order is cancelled.
1304
+ *
1305
+ * @example
1306
+ * ```typescript
1307
+ * order.addDomainEvent(new OrderCancelledEvent({
1308
+ * orderId: order.id.value,
1309
+ * reason: 'Customer requested cancellation',
1310
+ * cancelledAt: new Date().toISOString(),
1311
+ * }));
1312
+ * ```
1313
+ */
1314
+ declare class OrderCancelledEvent extends BaseDomainEvent<OrderCancelledPayload> {
1315
+ constructor(payload: OrderCancelledPayload);
1316
+ }
1317
+
1318
+ /**
1319
+ * Payload for the OrderPlaced domain event.
1320
+ */
1321
+ interface OrderPlacedPayload {
1322
+ orderId: string;
1323
+ customerId: string;
1324
+ itemCount: number;
1325
+ totalAmount: number;
1326
+ currency: string;
1327
+ placedAt: string;
1328
+ }
1329
+ /**
1330
+ * Domain event raised when a new order is placed.
1331
+ *
1332
+ * @example
1333
+ * ```typescript
1334
+ * order.addDomainEvent(new OrderPlacedEvent({
1335
+ * orderId: order.id.value,
1336
+ * customerId: order.customerId,
1337
+ * itemCount: order.items.length,
1338
+ * totalAmount: order.totalAmount.amount,
1339
+ * currency: order.totalAmount.currency,
1340
+ * placedAt: new Date().toISOString(),
1341
+ * }));
1342
+ * ```
1343
+ */
1344
+ declare class OrderPlacedEvent extends BaseDomainEvent<OrderPlacedPayload> {
1345
+ constructor(payload: OrderPlacedPayload);
1346
+ }
1347
+
1348
+ /**
1349
+ * Error thrown when attempting to modify an order that has already been shipped.
1350
+ *
1351
+ * @example
1352
+ * ```typescript
1353
+ * if (order.status.isShipped()) {
1354
+ * throw new OrderAlreadyShippedError(order.id.value);
1355
+ * }
1356
+ * ```
1357
+ */
1358
+ declare class OrderAlreadyShippedError extends InvariantViolationError {
1359
+ constructor(orderId: string);
1360
+ }
1361
+
1362
+ /**
1363
+ * Base error class for infrastructure layer failures.
1364
+ *
1365
+ * Infrastructure errors represent failures in external dependencies
1366
+ * such as databases, network services, file systems, or third-party APIs.
1367
+ * They are automatically created by {@link BaseOutboundAdapter} when
1368
+ * repository or gateway methods fail.
1369
+ *
1370
+ * **When to throw:**
1371
+ * - Database connection or query failures
1372
+ * - Network timeouts or connection errors
1373
+ * - External API failures
1374
+ * - File system errors
1375
+ *
1376
+ * **Child classes:**
1377
+ * - {@link DbError} - Database operation failures
1378
+ * - {@link NetworkError} - Network connectivity issues
1379
+ * - {@link TimeoutError} - Operation timeout
1380
+ * - {@link ExternalServiceError} - Third-party service failures
1381
+ *
1382
+ * @example
1383
+ * ```typescript
1384
+ * // In a repository extending BaseOutboundAdapter
1385
+ * protected override createInfraError(error: unknown, methodName: string): InfraError {
1386
+ * return new DbError({
1387
+ * message: `Database error in ${methodName}`,
1388
+ * cause: error,
1389
+ * });
1390
+ * }
1391
+ * ```
1392
+ */
1393
+ declare class InfraError extends CodedError {
1394
+ /**
1395
+ * Creates a new InfraError instance.
1396
+ *
1397
+ * @param options - Error configuration
1398
+ * @param options.message - Human-readable error description
1399
+ * @param options.code - Machine-readable error code (default: 'INFRA_ERROR')
1400
+ * @param options.cause - Optional underlying error
1401
+ */
1402
+ constructor({ message, code, cause, }: {
1403
+ message: string;
1404
+ code?: InfraErrorCode | string;
1405
+ cause?: unknown;
1406
+ });
1407
+ /**
1408
+ * Creates an InfraError from a caught error.
1409
+ *
1410
+ * @param cause - The original caught error
1411
+ * @returns A new InfraError instance with the cause attached
1412
+ */
1413
+ static fromError(cause: unknown): InfraError;
1414
+ }
1415
+
1416
+ /**
1417
+ * Abstract base class for outbound adapters (secondary/driven ports).
1418
+ *
1419
+ * Provides automatic error handling for all subclass methods by:
1420
+ * - Wrapping synchronous methods with try/catch
1421
+ * - Attaching `.catch()` handlers to Promise-returning methods
1422
+ * - Converting all errors to {@link InfraError} with the original as `cause`
1423
+ *
1424
+ * This ensures infrastructure errors are properly typed and don't leak
1425
+ * implementation details to the application layer.
1426
+ *
1427
+ * @example
1428
+ * ```typescript
1429
+ * class UserRepository extends BaseOutboundAdapter {
1430
+ * constructor(private db: Database) {
1431
+ * super();
1432
+ * }
1433
+ *
1434
+ * async findById(id: string): Promise<User | null> {
1435
+ * return this.db.users.findUnique({ where: { id } });
1436
+ * }
1437
+ *
1438
+ * protected override createInfraError(error: unknown, methodName: string): InfraError {
1439
+ * return new DbError({
1440
+ * message: `Database error in ${methodName}`,
1441
+ * cause: error,
1442
+ * });
1443
+ * }
1444
+ * }
1445
+ * ```
1446
+ */
1447
+ declare abstract class BaseOutboundAdapter {
1448
+ /**
1449
+ * Initializes the adapter and wraps all subclass methods with error handling.
1450
+ * Must be called via `super()` in subclass constructors.
1451
+ */
1452
+ protected constructor();
1453
+ /**
1454
+ * Factory method for creating infrastructure errors.
1455
+ *
1456
+ * Override this in subclasses to return specific error types
1457
+ * (e.g., `DbError`, `NetworkError`, `ExternalServiceError`).
1458
+ *
1459
+ * @param error - The original error that was caught
1460
+ * @param methodName - Name of the method where the error occurred (for debugging)
1461
+ * @returns An InfraError instance wrapping the original error
1462
+ */
1463
+ protected createInfraError(error: unknown, methodName: string): InfraError;
1464
+ /**
1465
+ * Walks the prototype chain and wraps all methods with error handling.
1466
+ * Uses prototype-level Symbol markers to prevent re-wrapping across instances.
1467
+ * @internal
1468
+ */
1469
+ private wrapAllSubclassMethods;
1470
+ }
1471
+
1472
+ /**
1473
+ * Error thrown when a database operation fails.
1474
+ *
1475
+ * Wraps database-specific errors (connection failures, query errors,
1476
+ * constraint violations) into a transport-agnostic infrastructure error.
1477
+ *
1478
+ * **When to throw:**
1479
+ * - Database connection lost
1480
+ * - Query execution failed
1481
+ * - Transaction rollback
1482
+ * - Constraint violation (unique, foreign key)
1483
+ *
1484
+ * @example
1485
+ * ```typescript
1486
+ * try {
1487
+ * await this.db.query('SELECT * FROM users');
1488
+ * } catch (error) {
1489
+ * throw new DbError({
1490
+ * message: 'Failed to fetch users',
1491
+ * code: 'USER_QUERY_FAILED',
1492
+ * cause: error,
1493
+ * });
1494
+ * }
1495
+ * ```
1496
+ *
1497
+ * @extends InfraError
1498
+ */
1499
+ declare class DbError extends InfraError {
1500
+ /**
1501
+ * Creates a new DbError instance.
1502
+ *
1503
+ * @param options - Error configuration
1504
+ * @param options.message - Description of the database failure
1505
+ * @param options.code - Machine-readable error code (default: 'DB_ERROR')
1506
+ * @param options.cause - Optional underlying database error
1507
+ */
1508
+ constructor({ message, code, cause, }: {
1509
+ message: string;
1510
+ code?: InfraErrorCode | string;
1511
+ cause?: unknown;
1512
+ });
1513
+ /**
1514
+ * Creates a DbError from a caught error.
1515
+ *
1516
+ * @param cause - The original caught error
1517
+ * @returns A new DbError instance with the cause attached
1518
+ */
1519
+ static fromError(cause: unknown): DbError;
1520
+ }
1521
+
1522
+ /**
1523
+ * Error thrown when a network operation fails.
1524
+ *
1525
+ * Indicates connectivity issues such as DNS resolution failures,
1526
+ * connection refused, or network unreachable errors.
1527
+ *
1528
+ * **When to throw:**
1529
+ * - Connection refused
1530
+ * - DNS resolution failed
1531
+ * - Network unreachable
1532
+ * - Socket errors
1533
+ *
1534
+ * @example
1535
+ * ```typescript
1536
+ * try {
1537
+ * await fetch('https://api.example.com/data');
1538
+ * } catch (error) {
1539
+ * throw new NetworkError({
1540
+ * message: 'Failed to connect to API',
1541
+ * code: 'API_CONNECTION_FAILED',
1542
+ * cause: error,
1543
+ * });
1544
+ * }
1545
+ * ```
1546
+ *
1547
+ * @extends InfraError
1548
+ */
1549
+ declare class NetworkError extends InfraError {
1550
+ /**
1551
+ * Creates a new NetworkError instance.
1552
+ *
1553
+ * @param options - Error configuration
1554
+ * @param options.message - Description of the network failure
1555
+ * @param options.code - Machine-readable error code (default: 'NETWORK_ERROR')
1556
+ * @param options.cause - Optional underlying network error
1557
+ */
1558
+ constructor({ message, code, cause, }: {
1559
+ message: string;
1560
+ code?: InfraErrorCode | string;
1561
+ cause?: unknown;
1562
+ });
1563
+ /**
1564
+ * Creates a NetworkError from a caught error.
1565
+ *
1566
+ * @param cause - The original caught error
1567
+ * @returns A new NetworkError instance with the cause attached
1568
+ */
1569
+ static fromError(cause: unknown): NetworkError;
1570
+ }
1571
+
1572
+ /**
1573
+ * Error thrown when an operation exceeds its time limit.
1574
+ *
1575
+ * Indicates that a request or operation took longer than the
1576
+ * configured timeout threshold.
1577
+ *
1578
+ * **When to throw:**
1579
+ * - Request timeout exceeded
1580
+ * - Database query timeout
1581
+ * - External API response timeout
1582
+ * - Lock acquisition timeout
1583
+ *
1584
+ * @example
1585
+ * ```typescript
1586
+ * const controller = new AbortController();
1587
+ * setTimeout(() => controller.abort(), 5000);
1588
+ *
1589
+ * try {
1590
+ * await fetch(url, { signal: controller.signal });
1591
+ * } catch (error) {
1592
+ * throw new TimeoutError({
1593
+ * message: 'Request timed out after 5 seconds',
1594
+ * code: 'REQUEST_TIMEOUT',
1595
+ * cause: error,
1596
+ * });
1597
+ * }
1598
+ * ```
1599
+ *
1600
+ * @extends InfraError
1601
+ */
1602
+ declare class TimeoutError extends InfraError {
1603
+ /**
1604
+ * Creates a new TimeoutError instance.
1605
+ *
1606
+ * @param options - Error configuration
1607
+ * @param options.message - Description of what timed out
1608
+ * @param options.code - Machine-readable error code (default: 'TIMEOUT_ERROR')
1609
+ * @param options.cause - Optional underlying timeout error
1610
+ */
1611
+ constructor({ message, code, cause, }: {
1612
+ message: string;
1613
+ code?: InfraErrorCode | string;
1614
+ cause?: unknown;
1615
+ });
1616
+ /**
1617
+ * Creates a TimeoutError from a caught error.
1618
+ *
1619
+ * @param cause - The original caught error
1620
+ * @returns A new TimeoutError instance with the cause attached
1621
+ */
1622
+ static fromError(cause: unknown): TimeoutError;
1623
+ }
1624
+
1625
+ /**
1626
+ * Error thrown when a third-party service call fails.
1627
+ *
1628
+ * Wraps errors from external APIs, payment gateways, email services,
1629
+ * or any other third-party dependency.
1630
+ *
1631
+ * **When to throw:**
1632
+ * - Third-party API returns an error
1633
+ * - External service is unavailable
1634
+ * - Unexpected response from external service
1635
+ * - Rate limiting by external service
1636
+ *
1637
+ * @example
1638
+ * ```typescript
1639
+ * try {
1640
+ * await this.paymentGateway.charge(amount);
1641
+ * } catch (error) {
1642
+ * throw new ExternalServiceError({
1643
+ * message: 'Payment gateway charge failed',
1644
+ * code: 'PAYMENT_GATEWAY_ERROR',
1645
+ * cause: error,
1646
+ * });
1647
+ * }
1648
+ * ```
1649
+ *
1650
+ * @extends InfraError
1651
+ */
1652
+ declare class ExternalServiceError extends InfraError {
1653
+ /**
1654
+ * Creates a new ExternalServiceError instance.
1655
+ *
1656
+ * @param options - Error configuration
1657
+ * @param options.message - Description of the external service failure
1658
+ * @param options.code - Machine-readable error code (default: 'EXTERNAL_SERVICE_ERROR')
1659
+ * @param options.cause - Optional underlying service error
1660
+ */
1661
+ constructor({ message, code, cause, }: {
1662
+ message: string;
1663
+ code?: InfraErrorCode | string;
1664
+ cause?: unknown;
1665
+ });
1666
+ /**
1667
+ * Creates an ExternalServiceError from a caught error.
1668
+ *
1669
+ * @param cause - The original caught error
1670
+ * @returns A new ExternalServiceError instance with the cause attached
1671
+ */
1672
+ static fromError(cause: unknown): ExternalServiceError;
1673
+ }
1674
+
1675
+ export { BaseAggregateRoot, BaseDomainEvent, BaseEntity, BaseInboundAdapter, BaseInboundPort, BaseOutboundAdapter, BaseUuidV7Vo, BaseValueObject, ConflictError, DbError, DomainError, ExternalServiceError, InfraError, InvariantViolationError, Money, type MoneyValue, NetworkError, NotFoundError, Order, OrderAlreadyShippedError, OrderCancelledEvent, type OrderCancelledPayload, OrderId, OrderItem, OrderItemId, type OrderItemProps, OrderPlacedEvent, type OrderPlacedPayload, type OrderProps, OrderStatus, type OrderStatusValue, PartialLoadError, TimeoutError, UnprocessableError, UseCaseError, canAddOrderItem, canCancelOrder, defaultOrderStatus };