@woltz/rich-domain 1.3.1 → 1.3.2

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/src/exceptions.ts DELETED
@@ -1,435 +0,0 @@
1
- /**
2
- * Base exception class for all Rich Domain exceptions
3
- */
4
- abstract class DomainException extends Error {
5
- public readonly code: string;
6
- public readonly timestamp: Date;
7
- public readonly __isDomainException = true;
8
-
9
- constructor(message: string, code?: string) {
10
- super(message);
11
- this.name = this.constructor.name;
12
- this.code = code || this.constructor.name;
13
- this.timestamp = new Date();
14
-
15
- // Maintain proper stack trace
16
- if (Error.captureStackTrace) {
17
- Error.captureStackTrace(this, this.constructor);
18
- }
19
- }
20
-
21
- /**
22
- * Check if an error is a DomainException
23
- */
24
- static isDomainException(error: unknown): error is DomainException {
25
- return (
26
- error instanceof DomainException ||
27
- (error instanceof Error &&
28
- "__isDomainException" in error &&
29
- (error as any).__isDomainException === true)
30
- );
31
- }
32
-
33
- /**
34
- * Convert to JSON for serialization
35
- */
36
- toJSON(): {
37
- name: string;
38
- message: string;
39
- code: string;
40
- timestamp: string;
41
- } {
42
- return {
43
- name: this.name,
44
- message: this.message,
45
- code: this.code,
46
- timestamp: this.timestamp.toISOString(),
47
- };
48
- }
49
- }
50
-
51
- /**
52
- * Thrown when a domain rule or business logic is violated
53
- */
54
- export class DomainError extends DomainException {
55
- constructor(message: string, code?: string) {
56
- super(message, code || "DOMAIN_ERROR");
57
- }
58
- }
59
-
60
- // ============================================================================
61
- // Entity & Aggregate Exceptions
62
- // ============================================================================
63
-
64
- /**
65
- * Thrown when an entity or aggregate is not found
66
- */
67
- export class EntityNotFoundError extends DomainException {
68
- public readonly entityType: string;
69
- public readonly entityId?: string;
70
-
71
- constructor(entityType: string, entityId?: string, message?: string) {
72
- const defaultMessage = entityId
73
- ? `${entityType} with id '${entityId}' not found`
74
- : `${entityType} not found`;
75
-
76
- super(message || defaultMessage, "ENTITY_NOT_FOUND");
77
- this.entityType = entityType;
78
- this.entityId = entityId;
79
- }
80
-
81
- toJSON() {
82
- return {
83
- ...super.toJSON(),
84
- entityType: this.entityType,
85
- entityId: this.entityId,
86
- };
87
- }
88
- }
89
-
90
- /**
91
- * Thrown when trying to create an entity that already exists
92
- */
93
- export class EntityAlreadyExistsError extends DomainException {
94
- public readonly entityType: string;
95
- public readonly entityId?: string;
96
-
97
- constructor(entityType: string, entityId?: string, message?: string) {
98
- const defaultMessage = entityId
99
- ? `${entityType} with id '${entityId}' already exists`
100
- : `${entityType} already exists`;
101
-
102
- super(message || defaultMessage, "ENTITY_ALREADY_EXISTS");
103
- this.entityType = entityType;
104
- this.entityId = entityId;
105
- }
106
-
107
- toJSON() {
108
- return {
109
- ...super.toJSON(),
110
- entityType: this.entityType,
111
- entityId: this.entityId,
112
- };
113
- }
114
- }
115
-
116
- // ============================================================================
117
- // Repository & Persistence Exceptions
118
- // ============================================================================
119
-
120
- /**
121
- * Base exception for repository operations
122
- */
123
- export class RepositoryError extends DomainException {
124
- constructor(message: string, code?: string) {
125
- super(message, code || "REPOSITORY_ERROR");
126
- }
127
- }
128
-
129
- /**
130
- * Thrown when a persistence operation fails
131
- */
132
- export class PersistenceError extends RepositoryError {
133
- public readonly operation: string;
134
- public readonly cause?: Error;
135
-
136
- constructor(operation: string, message?: string, cause?: Error) {
137
- const defaultMessage = `Persistence operation '${operation}' failed${
138
- message ? `: ${message}` : ""
139
- }`;
140
-
141
- super(defaultMessage, "PERSISTENCE_ERROR");
142
- this.operation = operation;
143
- this.cause = cause;
144
- }
145
-
146
- toJSON() {
147
- return {
148
- ...super.toJSON(),
149
- operation: this.operation,
150
- cause: this.cause?.message,
151
- };
152
- }
153
- }
154
-
155
- /**
156
- * Thrown when a concurrency conflict occurs (optimistic locking)
157
- */
158
- export class ConcurrencyError extends RepositoryError {
159
- public readonly entityType: string;
160
- public readonly entityId: string;
161
-
162
- constructor(entityType: string, entityId: string, message?: string) {
163
- const defaultMessage =
164
- message ||
165
- `Concurrency conflict detected for ${entityType} with id '${entityId}'`;
166
-
167
- super(defaultMessage, "CONCURRENCY_ERROR");
168
- this.entityType = entityType;
169
- this.entityId = entityId;
170
- }
171
-
172
- toJSON() {
173
- return {
174
- ...super.toJSON(),
175
- entityType: this.entityType,
176
- entityId: this.entityId,
177
- };
178
- }
179
- }
180
-
181
- /**
182
- * Thrown when a database constraint is violated
183
- */
184
- export class ConstraintViolationError extends RepositoryError {
185
- public readonly constraint: string;
186
-
187
- constructor(constraint: string, message?: string) {
188
- const defaultMessage =
189
- message || `Database constraint '${constraint}' violated`;
190
-
191
- super(defaultMessage, "CONSTRAINT_VIOLATION");
192
- this.constraint = constraint;
193
- }
194
-
195
- toJSON() {
196
- return {
197
- ...super.toJSON(),
198
- constraint: this.constraint,
199
- };
200
- }
201
- }
202
-
203
- // ============================================================================
204
- // Value Object Exceptions
205
- // ============================================================================
206
-
207
- /**
208
- * Thrown when a value object has invalid data
209
- */
210
- export class InvalidValueObjectError extends DomainException {
211
- public readonly valueObjectType: string;
212
- public readonly invalidValue?: any;
213
-
214
- constructor(valueObjectType: string, message: string, invalidValue?: any) {
215
- super(message, "INVALID_VALUE_OBJECT");
216
- this.valueObjectType = valueObjectType;
217
- this.invalidValue = invalidValue;
218
- }
219
-
220
- toJSON() {
221
- return {
222
- ...super.toJSON(),
223
- valueObjectType: this.valueObjectType,
224
- invalidValue: this.invalidValue,
225
- };
226
- }
227
- }
228
-
229
- // ============================================================================
230
- // Domain Event Exceptions
231
- // ============================================================================
232
-
233
- /**
234
- * Thrown when a domain event operation fails
235
- */
236
- export class DomainEventError extends DomainException {
237
- public readonly eventType?: string;
238
-
239
- constructor(message: string, eventType?: string) {
240
- super(message, "DOMAIN_EVENT_ERROR");
241
- this.eventType = eventType;
242
- }
243
-
244
- toJSON() {
245
- return {
246
- ...super.toJSON(),
247
- eventType: this.eventType,
248
- };
249
- }
250
- }
251
-
252
- /**
253
- * Thrown when an event handler fails
254
- */
255
- export class EventHandlerError extends DomainEventError {
256
- public readonly handlerName: string;
257
- public readonly cause?: Error;
258
-
259
- constructor(handlerName: string, eventType: string, cause?: Error) {
260
- const message = `Event handler '${handlerName}' failed for event '${eventType}'${
261
- cause ? `: ${cause.message}` : ""
262
- }`;
263
-
264
- super(message, eventType);
265
- this.handlerName = handlerName;
266
- this.cause = cause;
267
- }
268
-
269
- toJSON() {
270
- return {
271
- ...super.toJSON(),
272
- handlerName: this.handlerName,
273
- cause: this.cause?.message,
274
- };
275
- }
276
- }
277
-
278
- // ============================================================================
279
- // Criteria & Query Exceptions
280
- // ============================================================================
281
-
282
- /**
283
- * Thrown when a criteria or query is invalid
284
- */
285
- export class InvalidCriteriaError extends DomainException {
286
- public readonly field?: string;
287
-
288
- constructor(message: string, field?: string) {
289
- super(message, "INVALID_CRITERIA");
290
- this.field = field;
291
- }
292
-
293
- toJSON() {
294
- return {
295
- ...super.toJSON(),
296
- field: this.field,
297
- };
298
- }
299
- }
300
-
301
- // ============================================================================
302
- // Unit of Work Exceptions
303
- // ============================================================================
304
-
305
- /**
306
- * Thrown when a transaction operation fails
307
- */
308
- export class TransactionError extends DomainException {
309
- public readonly operation: string;
310
- public readonly cause?: Error;
311
-
312
- constructor(operation: string, message?: string, cause?: Error) {
313
- const defaultMessage = `Transaction ${operation} failed${
314
- message ? `: ${message}` : ""
315
- }`;
316
-
317
- super(defaultMessage, "TRANSACTION_ERROR");
318
- this.operation = operation;
319
- this.cause = cause;
320
- }
321
-
322
- toJSON() {
323
- return {
324
- ...super.toJSON(),
325
- operation: this.operation,
326
- cause: this.cause?.message,
327
- };
328
- }
329
- }
330
-
331
- // ============================================================================
332
- // Generic/Unknown Exceptions
333
- // ============================================================================
334
-
335
- /**
336
- * Thrown when an unexpected or unknown error occurs
337
- */
338
- export class UnknownError extends DomainException {
339
- public readonly originalError?: Error;
340
-
341
- constructor(message?: string, originalError?: Error) {
342
- const defaultMessage =
343
- message || originalError?.message || "An unknown error occurred";
344
-
345
- super(defaultMessage, "UNKNOWN_ERROR");
346
- this.originalError = originalError;
347
- }
348
-
349
- toJSON() {
350
- return {
351
- ...super.toJSON(),
352
- originalError: this.originalError?.message,
353
- };
354
- }
355
- }
356
-
357
- /**
358
- * Thrown when a feature is not implemented yet
359
- */
360
- export class NotImplementedError extends DomainException {
361
- public readonly feature: string;
362
-
363
- constructor(feature: string, message?: string) {
364
- const defaultMessage = message || `Feature '${feature}' is not implemented`;
365
-
366
- super(defaultMessage, "NOT_IMPLEMENTED");
367
- this.feature = feature;
368
- }
369
-
370
- toJSON() {
371
- return {
372
- ...super.toJSON(),
373
- feature: this.feature,
374
- };
375
- }
376
- }
377
-
378
- /**
379
- * Thrown when a required configuration is missing
380
- */
381
- export class ConfigurationError extends DomainException {
382
- public readonly configKey?: string;
383
-
384
- constructor(message: string, configKey?: string) {
385
- super(message, "CONFIGURATION_ERROR");
386
- this.configKey = configKey;
387
- }
388
-
389
- toJSON() {
390
- return {
391
- ...super.toJSON(),
392
- configKey: this.configKey,
393
- };
394
- }
395
- }
396
-
397
- // ============================================================================
398
- // Mapper Exceptions
399
- // ============================================================================
400
-
401
- /**
402
- * Thrown when mapping between domain and persistence fails
403
- */
404
- export class MapperError extends DomainException {
405
- public readonly direction: "toDomain" | "toPersistence";
406
- public readonly entityType: string;
407
- public readonly cause?: Error;
408
-
409
- constructor(
410
- direction: "toDomain" | "toPersistence",
411
- entityType: string,
412
- message?: string,
413
- cause?: Error
414
- ) {
415
- const defaultMessage =
416
- message ||
417
- `Failed to map ${entityType} ${
418
- direction === "toDomain" ? "to domain" : "to persistence"
419
- }`;
420
-
421
- super(defaultMessage, "MAPPER_ERROR");
422
- this.direction = direction;
423
- this.entityType = entityType;
424
- this.cause = cause;
425
- }
426
-
427
- toJSON() {
428
- return {
429
- ...super.toJSON(),
430
- direction: this.direction,
431
- entityType: this.entityType,
432
- cause: this.cause?.message,
433
- };
434
- }
435
- }
package/src/id.ts DELETED
@@ -1,98 +0,0 @@
1
- // ============================================================================
2
- // Id Class - Smart Identity Management
3
- // ============================================================================
4
-
5
- import UUID from "./crypto";
6
-
7
- export class Id {
8
- private readonly _value: string;
9
- private readonly _isNew: boolean;
10
-
11
-
12
- /**
13
- * Create a new Id
14
- * @param value - Optional existing ID value. If not provided, generates a new UUID.
15
- *
16
- * @example
17
- * // New entity (generates UUID)
18
- * const newId = new Id();
19
- * newuser.isNew() // true
20
- *
21
- * // Existing entity (uses provided ID)
22
- * const existingId = new Id("550e8400-e29b-41d4-a716-446655440000");
23
- * existinguser.isNew() // false
24
- */
25
- constructor(value: string, isNew?: boolean);
26
- constructor(value?: string);
27
- constructor(value?: string, isNew?: boolean) {
28
- if (value !== undefined) {
29
- // ID was provided - this is an existing entity
30
- this._value = value;
31
- this._isNew = isNew ?? false;
32
- } else {
33
- // No ID provided - generate new one, this is a new entity
34
- this._value = this.generateUUID();
35
- this._isNew = true;
36
- }
37
- }
38
-
39
- /**
40
- * Get the string value of the ID
41
- */
42
- get value(): string {
43
- return this._value;
44
- }
45
-
46
- /**
47
- * Check if this ID represents a new entity
48
- */
49
- public isNew(): boolean {
50
- return this._isNew;
51
- }
52
-
53
- /**
54
- * Convert to string (for JSON serialization and comparisons)
55
- */
56
- toString(): string {
57
- return this._value;
58
- }
59
-
60
- /**
61
- * Convert to JSON (returns the string value)
62
- */
63
- toJSON(): string {
64
- return this._value;
65
- }
66
-
67
- /**
68
- * Check equality with another Id or string
69
- */
70
- equals(other: Id | string): boolean {
71
- if (other instanceof Id) {
72
- return this._value === other._value;
73
- }
74
- return this._value === other;
75
- }
76
-
77
- /**
78
- * Generate a UUID v4
79
- */
80
- private generateUUID(): string {
81
- // Simple UUID v4 implementation
82
- return UUID();
83
- }
84
-
85
- /**
86
- * Create a new Id (convenience static method)
87
- */
88
- static create(): Id {
89
- return new Id();
90
- }
91
-
92
- /**
93
- * Create an Id from an existing value
94
- */
95
- static from(value: string): Id {
96
- return new Id(value);
97
- }
98
- }
package/src/index.ts DELETED
@@ -1,52 +0,0 @@
1
- export * from "./validation-error";
2
- export * from "./domain-event";
3
- export * from "./domain-event-bus";
4
- export * from "./exceptions";
5
- export * from "./criteria";
6
- export * from "./paginated-result";
7
- export * from "./repository";
8
- export { Id } from "./id";
9
- export { Entity, Aggregate } from "./entity";
10
- export { ValueObject } from "./value-object";
11
- export { Mapper } from "./mapper";
12
- export { EntitySchemaRegistry } from "./entity-schema-registry";
13
- export { AggregateChanges } from "./aggregate-changes";
14
- export type {
15
- DomainEventHandler,
16
- EntityHooks,
17
- Filter,
18
- EntityValidation,
19
- IDomainEvent,
20
- VOValidation,
21
- VOHooks,
22
- ValidationConfig,
23
- Primitive,
24
- TransactionContext,
25
- PaginationMeta,
26
- Pagination,
27
- OrderDirection,
28
- Order,
29
- IUnitOfWork,
30
- IDomainEventHandler,
31
- FieldPath,
32
- FilterOperator,
33
- Search,
34
- FilterValueFor,
35
- PathValue,
36
- OperatorsForType,
37
- DateOperators,
38
- NumberOperators,
39
- StringOperators,
40
- BooleanOperators,
41
- ArrayOperators,
42
- CriteriaOptions,
43
- } from "./types";
44
- export {
45
- ARRAY_OPERATORS,
46
- BOOLEAN_OPERATORS,
47
- DATE_OPERATORS,
48
- NUMBER_OPERATORS,
49
- STRING_OPERATORS,
50
- FILTER_OPERATORS,
51
- } from "./constants";
52
- export { isValidOperatorForType } from "./utils/criteria-operator-validation";
package/src/mapper.ts DELETED
@@ -1,6 +0,0 @@
1
- export abstract class Mapper<Input, Output> {
2
- public abstract build(
3
- input: Input,
4
- ...args: unknown[]
5
- ): Output | Promise<Output>;
6
- }