@rineex/ddd 0.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/LICENSE +201 -0
- package/dist/index.d.mts +351 -0
- package/dist/index.d.ts +351 -0
- package/dist/index.js +447 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +404 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +59 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Port interface for application services that execute commands or queries.
|
|
3
|
+
*
|
|
4
|
+
* @template I - The input type for the service execution
|
|
5
|
+
* @template O - The output type returned by the service execution
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* interface CreateUserInput {
|
|
10
|
+
* name: string;
|
|
11
|
+
* email: string;
|
|
12
|
+
* }
|
|
13
|
+
*
|
|
14
|
+
* interface CreateUserOutput {
|
|
15
|
+
* id: string;
|
|
16
|
+
* name: string;
|
|
17
|
+
* }
|
|
18
|
+
*
|
|
19
|
+
* class CreateUserService implements ApplicationServicePort<CreateUserInput, CreateUserOutput> {
|
|
20
|
+
* async execute(args: CreateUserInput): Promise<CreateUserOutput> {
|
|
21
|
+
* // implementation
|
|
22
|
+
* }
|
|
23
|
+
* }
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
interface ApplicationServicePort<I, O> {
|
|
27
|
+
execute: (args: I) => Promise<O>;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
interface DomainErrorMetadata {
|
|
31
|
+
cause?: {
|
|
32
|
+
name: string;
|
|
33
|
+
message: string;
|
|
34
|
+
stack?: string;
|
|
35
|
+
};
|
|
36
|
+
[key: string]: unknown;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Base class for all Domain Errors in the application.
|
|
40
|
+
*
|
|
41
|
+
* This class ensures:
|
|
42
|
+
* 1. Serializable and structured for logs or API responses.
|
|
43
|
+
* 2. Identifiable via stable error codes (not just class names).
|
|
44
|
+
* 3. Contextual with optional structured metadata.
|
|
45
|
+
* 4. Supports error chaining (cause) and stack trace preservation.
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* export class InsufficientFundsError extends DomainError {
|
|
49
|
+
* constructor(accountId: string, currentBalance: number) {
|
|
50
|
+
* super(
|
|
51
|
+
* `Account ${accountId} has insufficient funds.`,
|
|
52
|
+
* 'INSUFFICIENT_FUNDS',
|
|
53
|
+
* { accountId, currentBalance }
|
|
54
|
+
* );
|
|
55
|
+
* }
|
|
56
|
+
* }
|
|
57
|
+
*/
|
|
58
|
+
declare abstract class DomainError extends Error {
|
|
59
|
+
/** Stable, machine-readable error code */
|
|
60
|
+
readonly code: string;
|
|
61
|
+
/** Structured, immutable domain metadata */
|
|
62
|
+
readonly metadata: Readonly<DomainErrorMetadata>;
|
|
63
|
+
/**
|
|
64
|
+
* @param message - Human-readable error message
|
|
65
|
+
* @param code - Stable error code
|
|
66
|
+
* @param metadata - Domain-specific structured data; optional `cause` can be included
|
|
67
|
+
*/
|
|
68
|
+
protected constructor(message: string, code: string, metadata?: DomainErrorMetadata);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
declare abstract class ValueObject<T> {
|
|
72
|
+
get value(): T;
|
|
73
|
+
protected readonly props: Readonly<T>;
|
|
74
|
+
protected constructor(props: T);
|
|
75
|
+
/**
|
|
76
|
+
* Type guard to check if an unknown object is an instance of ValueObject.
|
|
77
|
+
* This is useful for runtime type checking.
|
|
78
|
+
*
|
|
79
|
+
* @param vo The object to check.
|
|
80
|
+
* @returns True if the object is a ValueObject instance, false otherwise.
|
|
81
|
+
*/
|
|
82
|
+
static is(vo: unknown): vo is ValueObject<unknown>;
|
|
83
|
+
/**
|
|
84
|
+
* Deep equality comparison of ValueObjects
|
|
85
|
+
*/
|
|
86
|
+
equals(other?: ValueObject<T>): boolean;
|
|
87
|
+
/**
|
|
88
|
+
* Validates the value object props
|
|
89
|
+
* @throws InvalidValueObjectError if validation fails
|
|
90
|
+
*/
|
|
91
|
+
protected abstract validate(props: T): void;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Custom error class for entity validation failures.
|
|
96
|
+
*/
|
|
97
|
+
declare class EntityValidationError extends DomainError {
|
|
98
|
+
constructor(message: string, cause?: Error);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
declare class InvalidValueObjectError extends DomainError {
|
|
102
|
+
constructor(message: string);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* AggregateId is a ValueObject that represents a unique identifier for an aggregate.
|
|
107
|
+
*/
|
|
108
|
+
declare class AggregateId extends ValueObject<string> {
|
|
109
|
+
/**
|
|
110
|
+
* The schema for the AggregateId
|
|
111
|
+
*/
|
|
112
|
+
private static readonly schema;
|
|
113
|
+
/**
|
|
114
|
+
* Get the UUID of the AggregateId
|
|
115
|
+
* @returns The UUID of the AggregateId
|
|
116
|
+
*/
|
|
117
|
+
get uuid(): string;
|
|
118
|
+
/**
|
|
119
|
+
* Create a new AggregateId
|
|
120
|
+
* @param value The value to create the AggregateId from
|
|
121
|
+
* @returns The new AggregateId
|
|
122
|
+
*/
|
|
123
|
+
static create(value: string): AggregateId;
|
|
124
|
+
/**
|
|
125
|
+
* Create a new AggregateId with a random UUID v4
|
|
126
|
+
*/
|
|
127
|
+
static generate(): AggregateId;
|
|
128
|
+
/**
|
|
129
|
+
* Check if the AggregateId is empty
|
|
130
|
+
* @returns True if the AggregateId is empty, false otherwise
|
|
131
|
+
*/
|
|
132
|
+
isEmpty(): boolean;
|
|
133
|
+
/**
|
|
134
|
+
* Convert the AggregateId to a string
|
|
135
|
+
* @returns The string representation of the AggregateId
|
|
136
|
+
*/
|
|
137
|
+
toString(): string;
|
|
138
|
+
/**
|
|
139
|
+
* Validate the AggregateId
|
|
140
|
+
* @param value The value to validate
|
|
141
|
+
* @throws InvalidValueObjectException if the value is invalid
|
|
142
|
+
*/
|
|
143
|
+
protected validate(value: string): void;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* HTTP status code catalog.
|
|
148
|
+
*
|
|
149
|
+
* This object provides a typed, immutable map of standard HTTP status names
|
|
150
|
+
* to their numeric codes. Designed for server-side frameworks such as Fastify.
|
|
151
|
+
*
|
|
152
|
+
* - All identifiers use clear, canonical semantic names.
|
|
153
|
+
* - Values are numeric status codes.
|
|
154
|
+
* - Frozen to prevent runtime mutation.
|
|
155
|
+
* - Exporting `HttpStatus` ensures type-safe usage across the codebase.
|
|
156
|
+
*/
|
|
157
|
+
declare const HttpStatus: Readonly<{
|
|
158
|
+
readonly REQUEST_HEADER_FIELDS_TOO_LARGE: 431;
|
|
159
|
+
readonly NETWORK_AUTHENTICATION_REQUIRED: 511;
|
|
160
|
+
readonly NON_AUTHORITATIVE_INFORMATION: 203;
|
|
161
|
+
readonly PROXY_AUTHENTICATION_REQUIRED: 407;
|
|
162
|
+
readonly UNAVAILABLE_FOR_LEGAL_REASONS: 451;
|
|
163
|
+
readonly HTTP_VERSION_NOT_SUPPORTED: 505;
|
|
164
|
+
readonly BANDWIDTH_LIMIT_EXCEEDED: 509;
|
|
165
|
+
readonly VARIANT_ALSO_NEGOTIATES: 506;
|
|
166
|
+
readonly UNSUPPORTED_MEDIA_TYPE: 415;
|
|
167
|
+
readonly RANGE_NOT_SATISFIABLE: 416;
|
|
168
|
+
readonly PRECONDITION_REQUIRED: 428;
|
|
169
|
+
readonly INTERNAL_SERVER_ERROR: 500;
|
|
170
|
+
readonly UNPROCESSABLE_ENTITY: 422;
|
|
171
|
+
readonly INSUFFICIENT_STORAGE: 507;
|
|
172
|
+
readonly SWITCHING_PROTOCOLS: 101;
|
|
173
|
+
readonly PRECONDITION_FAILED: 412;
|
|
174
|
+
readonly MISDIRECTED_REQUEST: 421;
|
|
175
|
+
readonly SERVICE_UNAVAILABLE: 503;
|
|
176
|
+
readonly TEMPORARY_REDIRECT: 307;
|
|
177
|
+
readonly PERMANENT_REDIRECT: 308;
|
|
178
|
+
readonly METHOD_NOT_ALLOWED: 405;
|
|
179
|
+
readonly EXPECTATION_FAILED: 417;
|
|
180
|
+
readonly MOVED_PERMANENTLY: 301;
|
|
181
|
+
readonly PAYLOAD_TOO_LARGE: 413;
|
|
182
|
+
readonly FAILED_DEPENDENCY: 424;
|
|
183
|
+
readonly TOO_MANY_REQUESTS: 429;
|
|
184
|
+
readonly ALREADY_REPORTED: 208;
|
|
185
|
+
readonly MULTIPLE_CHOICES: 300;
|
|
186
|
+
readonly PAYMENT_REQUIRED: 402;
|
|
187
|
+
readonly UPGRADE_REQUIRED: 426;
|
|
188
|
+
readonly PARTIAL_CONTENT: 206;
|
|
189
|
+
readonly REQUEST_TIMEOUT: 408;
|
|
190
|
+
readonly LENGTH_REQUIRED: 411;
|
|
191
|
+
readonly NOT_IMPLEMENTED: 501;
|
|
192
|
+
readonly GATEWAY_TIMEOUT: 504;
|
|
193
|
+
readonly NOT_ACCEPTABLE: 406;
|
|
194
|
+
readonly RESET_CONTENT: 205;
|
|
195
|
+
readonly LOOP_DETECTED: 508;
|
|
196
|
+
readonly MULTI_STATUS: 207;
|
|
197
|
+
readonly NOT_MODIFIED: 304;
|
|
198
|
+
readonly UNAUTHORIZED: 401;
|
|
199
|
+
readonly URI_TOO_LONG: 414;
|
|
200
|
+
readonly NOT_EXTENDED: 510;
|
|
201
|
+
readonly EARLY_HINTS: 103;
|
|
202
|
+
readonly BAD_REQUEST: 400;
|
|
203
|
+
readonly IM_A_TEAPOT: 418;
|
|
204
|
+
readonly BAD_GATEWAY: 502;
|
|
205
|
+
readonly PROCESSING: 102;
|
|
206
|
+
readonly NO_CONTENT: 204;
|
|
207
|
+
readonly SEE_OTHER: 303;
|
|
208
|
+
readonly USE_PROXY: 305;
|
|
209
|
+
readonly FORBIDDEN: 403;
|
|
210
|
+
readonly NOT_FOUND: 404;
|
|
211
|
+
readonly TOO_EARLY: 425;
|
|
212
|
+
readonly CONTINUE: 100;
|
|
213
|
+
readonly ACCEPTED: 202;
|
|
214
|
+
readonly CONFLICT: 409;
|
|
215
|
+
readonly CREATED: 201;
|
|
216
|
+
readonly IM_USED: 226;
|
|
217
|
+
readonly LOCKED: 423;
|
|
218
|
+
readonly FOUND: 302;
|
|
219
|
+
readonly GONE: 410;
|
|
220
|
+
readonly OK: 200;
|
|
221
|
+
}>;
|
|
222
|
+
type HttpStatusCode = keyof typeof HttpStatusMessage;
|
|
223
|
+
/**
|
|
224
|
+
* HTTP status messages mapped by numeric code.
|
|
225
|
+
* Use for sending descriptive text in responses or logging.
|
|
226
|
+
*/
|
|
227
|
+
declare const HttpStatusMessage: {
|
|
228
|
+
readonly 431: "Request Header Fields Too Large";
|
|
229
|
+
readonly 511: "Network Authentication Required";
|
|
230
|
+
readonly 203: "Non-Authoritative Information";
|
|
231
|
+
readonly 407: "Proxy Authentication Required";
|
|
232
|
+
readonly 451: "Unavailable For Legal Reasons";
|
|
233
|
+
readonly 505: "HTTP Version Not Supported";
|
|
234
|
+
readonly 509: "Bandwidth Limit Exceeded";
|
|
235
|
+
readonly 506: "Variant Also Negotiates";
|
|
236
|
+
readonly 415: "Unsupported Media Type";
|
|
237
|
+
readonly 416: "Range Not Satisfiable";
|
|
238
|
+
readonly 428: "Precondition Required";
|
|
239
|
+
readonly 500: "Internal Server Error";
|
|
240
|
+
readonly 422: "Unprocessable Entity";
|
|
241
|
+
readonly 507: "Insufficient Storage";
|
|
242
|
+
readonly 101: "Switching Protocols";
|
|
243
|
+
readonly 412: "Precondition Failed";
|
|
244
|
+
readonly 421: "Misdirected Request";
|
|
245
|
+
readonly 503: "Service Unavailable";
|
|
246
|
+
readonly 307: "Temporary Redirect";
|
|
247
|
+
readonly 308: "Permanent Redirect";
|
|
248
|
+
readonly 405: "Method Not Allowed";
|
|
249
|
+
readonly 417: "Expectation Failed";
|
|
250
|
+
readonly 301: "Moved Permanently";
|
|
251
|
+
readonly 413: "Payload Too Large";
|
|
252
|
+
readonly 424: "Failed Dependency";
|
|
253
|
+
readonly 429: "Too Many Requests";
|
|
254
|
+
readonly 208: "Already Reported";
|
|
255
|
+
readonly 300: "Multiple Choices";
|
|
256
|
+
readonly 402: "Payment Required";
|
|
257
|
+
readonly 426: "Upgrade Required";
|
|
258
|
+
readonly 206: "Partial Content";
|
|
259
|
+
readonly 408: "Request Timeout";
|
|
260
|
+
readonly 411: "Length Required";
|
|
261
|
+
readonly 501: "Not Implemented";
|
|
262
|
+
readonly 504: "Gateway Timeout";
|
|
263
|
+
readonly 406: "Not Acceptable";
|
|
264
|
+
readonly 205: "Reset Content";
|
|
265
|
+
readonly 508: "Loop Detected";
|
|
266
|
+
readonly 207: "Multi-Status";
|
|
267
|
+
readonly 304: "Not Modified";
|
|
268
|
+
readonly 401: "Unauthorized";
|
|
269
|
+
readonly 414: "URI Too Long";
|
|
270
|
+
readonly 418: "I'm a Teapot";
|
|
271
|
+
readonly 510: "Not Extended";
|
|
272
|
+
readonly 103: "Early Hints";
|
|
273
|
+
readonly 400: "Bad Request";
|
|
274
|
+
readonly 502: "Bad Gateway";
|
|
275
|
+
readonly 102: "Processing";
|
|
276
|
+
readonly 204: "No Content";
|
|
277
|
+
readonly 303: "See Other";
|
|
278
|
+
readonly 305: "Use Proxy";
|
|
279
|
+
readonly 403: "Forbidden";
|
|
280
|
+
readonly 404: "Not Found";
|
|
281
|
+
readonly 425: "Too Early";
|
|
282
|
+
readonly 100: "Continue";
|
|
283
|
+
readonly 202: "Accepted";
|
|
284
|
+
readonly 226: "I'm Used";
|
|
285
|
+
readonly 409: "Conflict";
|
|
286
|
+
readonly 201: "Created";
|
|
287
|
+
readonly 423: "Locked";
|
|
288
|
+
readonly 302: "Found";
|
|
289
|
+
readonly 410: "Gone";
|
|
290
|
+
readonly 200: "OK";
|
|
291
|
+
};
|
|
292
|
+
type HttpStatusMessage = (typeof HttpStatusMessage)[keyof typeof HttpStatusMessage];
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* Utility to deeply freeze objects to ensure immutability
|
|
296
|
+
*/
|
|
297
|
+
declare function deepFreeze<T>(obj: T, seen?: WeakSet<object>): Readonly<T>;
|
|
298
|
+
|
|
299
|
+
interface ErrorParams {
|
|
300
|
+
message: string;
|
|
301
|
+
code: HttpStatusMessage;
|
|
302
|
+
status?: HttpStatusCode;
|
|
303
|
+
metadata?: Record<string, unknown> | undefined;
|
|
304
|
+
isOperational?: boolean;
|
|
305
|
+
cause?: Error | undefined;
|
|
306
|
+
}
|
|
307
|
+
/**
|
|
308
|
+
* Abstract base class for application-level errors with structured error handling.
|
|
309
|
+
*
|
|
310
|
+
* Extends the native Error class to provide machine-readable error codes, HTTP status codes,
|
|
311
|
+
* operational error classification, and optional metadata for better error tracking and client communication.
|
|
312
|
+
*
|
|
313
|
+
* @abstract
|
|
314
|
+
* @extends {Error}
|
|
315
|
+
*
|
|
316
|
+
* @example
|
|
317
|
+
* ```typescript
|
|
318
|
+
* class UserNotFoundError extends ApplicationError {
|
|
319
|
+
* constructor(userId: string) {
|
|
320
|
+
* super({
|
|
321
|
+
* code: HttpStatusMessage['404'],
|
|
322
|
+
* status: 404,
|
|
323
|
+
* isOperational: true,
|
|
324
|
+
* message: `User with id ${userId} not found`,
|
|
325
|
+
* metadata: { userId }
|
|
326
|
+
* });
|
|
327
|
+
* }
|
|
328
|
+
* }
|
|
329
|
+
* ```
|
|
330
|
+
*/
|
|
331
|
+
declare abstract class ApplicationError extends Error {
|
|
332
|
+
/** Optional cause (linked error) */
|
|
333
|
+
readonly cause?: Error | undefined;
|
|
334
|
+
/** Machine-readable error code (e.g. `OTP_LOCKED`, `USER_NOT_FOUND`) */
|
|
335
|
+
readonly code: HttpStatusMessage;
|
|
336
|
+
/** Operational vs programmer error flag */
|
|
337
|
+
readonly isOperational: boolean;
|
|
338
|
+
/** Optional structured metadata for debugging or clients */
|
|
339
|
+
readonly metadata?: Record<string, unknown> | undefined;
|
|
340
|
+
/** HTTP status code intended for response layer */
|
|
341
|
+
readonly status: HttpStatusCode;
|
|
342
|
+
constructor({ code, isOperational, status, metadata, message, cause, }: ErrorParams);
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
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 ? {
|
|
346
|
+
[K in keyof T]: UnwrapValueObject<T[K]>;
|
|
347
|
+
} : T;
|
|
348
|
+
declare function unwrapValueObject<T>(input: T, seen?: WeakSet<object>): UnwrapValueObject<T>;
|
|
349
|
+
declare function ensureObject<T>(input: UnwrapValueObject<T>): object;
|
|
350
|
+
|
|
351
|
+
export { AggregateId, ApplicationError, type ApplicationServicePort, DomainError, type DomainErrorMetadata, EntityValidationError, HttpStatus, type HttpStatusCode, HttpStatusMessage, InvalidValueObjectError, type UnwrapValueObject, ValueObject, deepFreeze, ensureObject, unwrapValueObject };
|