@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,1158 @@
1
+ import {
2
+ BaseController,
3
+ GuardedController,
4
+ assertHttpResponse,
5
+ computeRoutePath,
6
+ defineSystemMetadata,
7
+ isHttpResponse
8
+ } from "../../chunk-DDAHJZVK.js";
9
+ import {
10
+ wrapErrorUnlessAsync
11
+ } from "../../chunk-OKFXZHBC.js";
12
+ import {
13
+ BaseAuditByVo,
14
+ BaseAuditInfoVo,
15
+ BaseAuditOnVo,
16
+ BaseEmailVo,
17
+ BaseLongTextVo,
18
+ BaseMediumTextVo,
19
+ BasePaginationVo,
20
+ BaseShortTextVo,
21
+ BaseUuidV4Vo,
22
+ BaseUuidV7Vo,
23
+ BaseValueObject,
24
+ InvariantViolationError,
25
+ SKIP_VALUE_OBJECT_VALIDATION
26
+ } from "../../chunk-VCHFXT5W.js";
27
+ import {
28
+ ConflictError,
29
+ InfraError,
30
+ NotFoundError,
31
+ UnprocessableError,
32
+ UseCaseError
33
+ } from "../../chunk-RLLWYFPI.js";
34
+ import {
35
+ AccessDeniedError,
36
+ ControllerError,
37
+ InvalidRequestError
38
+ } from "../../chunk-74IKUOSE.js";
39
+ import {
40
+ DomainError
41
+ } from "../../chunk-ZWLYNGO3.js";
42
+ import {
43
+ ErrorCodes,
44
+ ObjectValidationError
45
+ } from "../../chunk-MQD5GXMT.js";
46
+ import "../../chunk-CGZBV6BD.js";
47
+
48
+ // src/backend/core/onion-layers/app/classes/base-inbound-adapter.class.ts
49
+ var BaseInboundAdapter = class {
50
+ /**
51
+ * Executes the use case with error boundary protection.
52
+ *
53
+ * Known error types are re-thrown as-is to preserve error semantics.
54
+ * Unknown errors are wrapped in a UseCaseError to maintain error hierarchy.
55
+ *
56
+ * @param input - Validated input DTO
57
+ * @returns Promise resolving to the output DTO
58
+ * @throws {ObjectValidationError} For validation failures (propagated to controller)
59
+ * @throws {UseCaseError} For use case failures or wrapped unknown errors
60
+ * @throws {DomainError} For domain invariant violations
61
+ * @throws {InfraError} For infrastructure failures
62
+ */
63
+ async execute(input) {
64
+ return wrapErrorUnlessAsync(
65
+ () => this.handle(input),
66
+ (cause) => new UseCaseError({ message: "Unexpected use case handler error", cause }),
67
+ [ObjectValidationError, UseCaseError, DomainError, InfraError]
68
+ );
69
+ }
70
+ };
71
+
72
+ // src/backend/core/onion-layers/domain/classes/base-entity.class.ts
73
+ var BaseEntity = class {
74
+ _id;
75
+ _props;
76
+ _version;
77
+ /**
78
+ * Creates a new Entity instance.
79
+ *
80
+ * @param id - The unique identifier for this entity
81
+ * @param props - The entity's properties/state (should be composed of Value Objects)
82
+ * @param version - Optional version number for optimistic locking (defaults to 0)
83
+ */
84
+ constructor(id, props, version = 0) {
85
+ this._id = id;
86
+ this._props = props;
87
+ this._version = version;
88
+ }
89
+ /**
90
+ * The unique identifier for this entity.
91
+ *
92
+ * @returns The entity's ID of type TId
93
+ */
94
+ get id() {
95
+ return this._id;
96
+ }
97
+ /**
98
+ * The entity's properties/state.
99
+ *
100
+ * Protected to encourage encapsulation via specific getters.
101
+ * Subclasses should expose individual properties as needed.
102
+ *
103
+ * @returns The entity's properties of type TProps
104
+ */
105
+ get props() {
106
+ return this._props;
107
+ }
108
+ /**
109
+ * The version number for optimistic locking.
110
+ *
111
+ * Use this to detect concurrent modifications:
112
+ * - Load entity with version N
113
+ * - Attempt to save with "WHERE version = N"
114
+ * - If rows affected = 0, another process modified the entity
115
+ *
116
+ * @returns The current version number
117
+ */
118
+ get version() {
119
+ return this._version;
120
+ }
121
+ /**
122
+ * Compares this Entity with another for equality.
123
+ *
124
+ * Entities are equal if they have the same identity (ID).
125
+ * This differs from Value Objects which compare by value.
126
+ *
127
+ * @param other - The Entity to compare with
128
+ * @returns `true` if the IDs are equal, `false` otherwise
129
+ *
130
+ * @example
131
+ * ```typescript
132
+ * const user1 = User.create(PersonName.create('John'), Email.create('john@example.com'));
133
+ * const user2 = User.fromPersistence(user1.id, { name: PersonName.create('John Updated'), ... }, 1);
134
+ * user1.equals(user2); // true - same ID, different state
135
+ * ```
136
+ */
137
+ equals(other) {
138
+ if (this === other) return true;
139
+ return this.idEquals(this._id, other._id);
140
+ }
141
+ /**
142
+ * Compares two IDs for equality.
143
+ *
144
+ * Since TId must extend BaseValueObject, we use the value object's
145
+ * `equals` method for comparison.
146
+ *
147
+ * @param a - First ID to compare
148
+ * @param b - Second ID to compare
149
+ * @returns `true` if IDs are equal, `false` otherwise
150
+ */
151
+ idEquals(a, b) {
152
+ if (a === b) return true;
153
+ return a.equals(b);
154
+ }
155
+ /**
156
+ * Returns the next version number.
157
+ *
158
+ * Call this when persisting changes to implement optimistic locking.
159
+ * The repository should save with version + 1.
160
+ *
161
+ * @returns The next version number (current + 1)
162
+ *
163
+ * @example
164
+ * ```typescript
165
+ * // In repository
166
+ * async save(entity: User): Promise<void> {
167
+ * await this.db.update({
168
+ * ...entity.toPersistence(),
169
+ * version: entity.nextVersion(),
170
+ * }).where({ id: entity.id, version: entity.version });
171
+ * }
172
+ * ```
173
+ */
174
+ nextVersion() {
175
+ return this._version + 1;
176
+ }
177
+ };
178
+
179
+ // src/backend/core/onion-layers/domain/classes/base-aggregate-root.class.ts
180
+ var BaseAggregateRoot = class extends BaseEntity {
181
+ _domainEvents = [];
182
+ /**
183
+ * Creates a new Aggregate Root instance.
184
+ *
185
+ * @param id - The unique identifier for this aggregate
186
+ * @param props - The aggregate's properties/state (should be composed of Value Objects)
187
+ * @param version - Optional version number for optimistic locking (defaults to 0)
188
+ */
189
+ constructor(id, props, version) {
190
+ super(id, props, version);
191
+ }
192
+ /**
193
+ * Adds a domain event to be published after persistence.
194
+ *
195
+ * Call this method when a significant domain action occurs.
196
+ * Events are collected and should be published by the repository
197
+ * after successfully persisting the aggregate.
198
+ *
199
+ * @param event - The domain event to add
200
+ *
201
+ * @example
202
+ * ```typescript
203
+ * confirm(): void {
204
+ * this._props.status = OrderStatus.confirmed();
205
+ * this.addDomainEvent(new OrderConfirmedEvent({
206
+ * orderId: this.id.value,
207
+ * confirmedAt: new Date(),
208
+ * }));
209
+ * }
210
+ * ```
211
+ */
212
+ addDomainEvent(event) {
213
+ this._domainEvents.push(event);
214
+ }
215
+ /**
216
+ * Returns and clears all pending domain events.
217
+ *
218
+ * This method should be called by the repository after successfully
219
+ * persisting the aggregate. The events are cleared to prevent
220
+ * duplicate publishing.
221
+ *
222
+ * @returns Array of domain events that were pending
223
+ *
224
+ * @example
225
+ * ```typescript
226
+ * // In repository
227
+ * async save(order: Order): Promise<void> {
228
+ * await this.db.transaction(async (tx) => {
229
+ * await tx.orders.upsert(order.toPersistence());
230
+ * });
231
+ *
232
+ * // Only publish after successful persistence
233
+ * const events = order.pullDomainEvents();
234
+ * for (const event of events) {
235
+ * await this.eventBus.publish(event);
236
+ * }
237
+ * }
238
+ * ```
239
+ */
240
+ pullDomainEvents() {
241
+ const events = [...this._domainEvents];
242
+ this._domainEvents = [];
243
+ return events;
244
+ }
245
+ /**
246
+ * Returns pending domain events without clearing them.
247
+ *
248
+ * Useful for inspection or testing without affecting the event queue.
249
+ *
250
+ * @returns Array of pending domain events
251
+ */
252
+ peekDomainEvents() {
253
+ return [...this._domainEvents];
254
+ }
255
+ /**
256
+ * Checks if there are any pending domain events.
257
+ *
258
+ * @returns `true` if there are events waiting to be published
259
+ *
260
+ * @example
261
+ * ```typescript
262
+ * if (order.hasDomainEvents) {
263
+ * const events = order.pullDomainEvents();
264
+ * await eventBus.publishAll(events);
265
+ * }
266
+ * ```
267
+ */
268
+ get hasDomainEvents() {
269
+ return this._domainEvents.length > 0;
270
+ }
271
+ /**
272
+ * Clears all pending domain events without returning them.
273
+ *
274
+ * Use with caution - this discards events that haven't been published.
275
+ * Useful in testing or when intentionally discarding events.
276
+ */
277
+ clearDomainEvents() {
278
+ this._domainEvents = [];
279
+ }
280
+ };
281
+
282
+ // src/backend/core/onion-layers/domain/classes/base-domain-event.class.ts
283
+ var BaseDomainEvent = class _BaseDomainEvent {
284
+ _eventId;
285
+ _eventName;
286
+ _aggregateId;
287
+ _occurredOn;
288
+ _payload;
289
+ /**
290
+ * Deep clones an object, handling Date objects specially.
291
+ *
292
+ * @param obj - The object to clone
293
+ * @returns A deep copy of the object
294
+ */
295
+ static deepClone(obj) {
296
+ if (obj === null || typeof obj !== "object") {
297
+ return obj;
298
+ }
299
+ if (obj instanceof Date) {
300
+ return new Date(obj.getTime());
301
+ }
302
+ if (Array.isArray(obj)) {
303
+ return obj.map((item) => _BaseDomainEvent.deepClone(item));
304
+ }
305
+ const cloned = {};
306
+ for (const key of Object.keys(obj)) {
307
+ cloned[key] = _BaseDomainEvent.deepClone(obj[key]);
308
+ }
309
+ return cloned;
310
+ }
311
+ /**
312
+ * Recursively freezes an object and all nested objects.
313
+ *
314
+ * @param obj - The object to deep freeze
315
+ * @returns The frozen object
316
+ */
317
+ static deepFreeze(obj) {
318
+ if (obj === null || typeof obj !== "object") {
319
+ return obj;
320
+ }
321
+ if (Array.isArray(obj)) {
322
+ obj.forEach((item) => _BaseDomainEvent.deepFreeze(item));
323
+ return Object.freeze(obj);
324
+ }
325
+ for (const key of Object.keys(obj)) {
326
+ const value = obj[key];
327
+ if (value !== null && typeof value === "object") {
328
+ _BaseDomainEvent.deepFreeze(value);
329
+ }
330
+ }
331
+ return Object.freeze(obj);
332
+ }
333
+ /**
334
+ * Creates an immutable copy of the payload.
335
+ *
336
+ * Clones the payload first to avoid mutating the original object,
337
+ * then deep-freezes the clone to ensure immutability.
338
+ *
339
+ * @param payload - The payload to clone and freeze
340
+ * @returns An immutable copy of the payload
341
+ */
342
+ static cloneAndFreeze(payload) {
343
+ const cloned = _BaseDomainEvent.deepClone(payload);
344
+ return _BaseDomainEvent.deepFreeze(cloned);
345
+ }
346
+ /**
347
+ * Creates a new Domain Event.
348
+ *
349
+ * The payload is cloned and deep-frozen to ensure immutability. The original
350
+ * object passed in remains unmodified. Any attempt to modify the event's
351
+ * payload after creation will throw a TypeError in strict mode.
352
+ *
353
+ * @param eventName - The name of the event (e.g., 'OrderPlaced', 'UserRegistered')
354
+ * @param aggregateId - The ID of the aggregate that raised this event
355
+ * @param payload - The event-specific data (will be cloned and deep-frozen)
356
+ * @param eventId - Optional custom event ID (defaults to crypto.randomUUID())
357
+ * @param occurredOn - Optional timestamp (defaults to now)
358
+ */
359
+ constructor(eventName, aggregateId, payload, eventId, occurredOn) {
360
+ this._eventId = eventId ?? crypto.randomUUID();
361
+ this._eventName = eventName;
362
+ this._aggregateId = aggregateId;
363
+ this._occurredOn = occurredOn ?? /* @__PURE__ */ new Date();
364
+ this._payload = _BaseDomainEvent.cloneAndFreeze(payload);
365
+ }
366
+ /**
367
+ * Unique identifier for this event instance.
368
+ *
369
+ * Useful for idempotency checks and event deduplication.
370
+ */
371
+ get eventId() {
372
+ return this._eventId;
373
+ }
374
+ /**
375
+ * The name/type of this event.
376
+ *
377
+ * Used for routing events to appropriate handlers.
378
+ * Should be in PastTense format (e.g., 'OrderPlaced', 'UserRegistered').
379
+ */
380
+ get eventName() {
381
+ return this._eventName;
382
+ }
383
+ /**
384
+ * The ID of the aggregate that raised this event.
385
+ *
386
+ * Useful for event sourcing and aggregate-specific event streams.
387
+ */
388
+ get aggregateId() {
389
+ return this._aggregateId;
390
+ }
391
+ /**
392
+ * Timestamp when this event occurred.
393
+ *
394
+ * Represents the moment the domain action happened.
395
+ */
396
+ get occurredOn() {
397
+ return this._occurredOn;
398
+ }
399
+ /**
400
+ * The event-specific data payload.
401
+ *
402
+ * Contains all information needed by event handlers.
403
+ */
404
+ get payload() {
405
+ return this._payload;
406
+ }
407
+ /**
408
+ * Serializes the event to a plain object for persistence or messaging.
409
+ *
410
+ * @returns A plain object representation of the event
411
+ *
412
+ * @example
413
+ * ```typescript
414
+ * const event = new OrderPlacedEvent({ orderId: '123', ... });
415
+ * const serialized = event.toJSON();
416
+ * // {
417
+ * // eventId: 'uuid',
418
+ * // eventName: 'OrderPlaced',
419
+ * // aggregateId: '123',
420
+ * // occurredOn: '2024-01-15T10:30:00.000Z',
421
+ * // payload: { orderId: '123', ... }
422
+ * // }
423
+ * ```
424
+ */
425
+ toJSON() {
426
+ return {
427
+ eventId: this._eventId,
428
+ eventName: this._eventName,
429
+ aggregateId: this._aggregateId,
430
+ occurredOn: this._occurredOn.toISOString(),
431
+ payload: this._payload
432
+ };
433
+ }
434
+ };
435
+
436
+ // src/backend/core/onion-layers/domain/exceptions/partial-load.error.ts
437
+ var PartialLoadError = class _PartialLoadError extends DomainError {
438
+ /**
439
+ * Creates a new PartialLoadError instance.
440
+ *
441
+ * @param options - Error configuration
442
+ * @param options.message - Description of what was not loaded
443
+ * @param options.code - Machine-readable error code (default: 'PARTIAL_LOAD')
444
+ * @param options.cause - Optional underlying error
445
+ */
446
+ constructor({
447
+ message,
448
+ code = ErrorCodes.Domain.PARTIAL_LOAD,
449
+ cause
450
+ }) {
451
+ super({ message, code, cause });
452
+ }
453
+ /**
454
+ * Creates a PartialLoadError from a caught error.
455
+ *
456
+ * @param cause - The original caught error
457
+ * @returns A new PartialLoadError instance with the cause attached
458
+ */
459
+ static fromError(cause) {
460
+ return new _PartialLoadError({
461
+ message: cause instanceof Error ? cause.message : "Partial load error",
462
+ cause
463
+ });
464
+ }
465
+ };
466
+
467
+ // src/backend/core/onion-layers/domain/example-domain/value-objects/money.vo.ts
468
+ var Money = class _Money extends BaseValueObject {
469
+ /**
470
+ * Creates a Money instance with USD currency.
471
+ *
472
+ * @param amount - The monetary amount
473
+ */
474
+ static usd(amount) {
475
+ return new _Money({ amount, currency: "USD" }, SKIP_VALUE_OBJECT_VALIDATION);
476
+ }
477
+ /**
478
+ * Creates a Money instance with EUR currency.
479
+ *
480
+ * @param amount - The monetary amount
481
+ */
482
+ static eur(amount) {
483
+ return new _Money({ amount, currency: "EUR" }, SKIP_VALUE_OBJECT_VALIDATION);
484
+ }
485
+ /**
486
+ * Creates a zero amount in the specified currency.
487
+ *
488
+ * @param currency - The currency code (default: 'USD')
489
+ */
490
+ static zero(currency = "USD") {
491
+ return new _Money({ amount: 0, currency }, SKIP_VALUE_OBJECT_VALIDATION);
492
+ }
493
+ /**
494
+ * Reconstitutes a Money from a persisted value.
495
+ *
496
+ * @param value - The money value from persistence
497
+ */
498
+ static fromPersistence(value) {
499
+ return new _Money(value, SKIP_VALUE_OBJECT_VALIDATION);
500
+ }
501
+ /**
502
+ * The monetary amount.
503
+ */
504
+ get amount() {
505
+ return this.value.amount;
506
+ }
507
+ /**
508
+ * The currency code.
509
+ */
510
+ get currency() {
511
+ return this.value.currency;
512
+ }
513
+ /**
514
+ * Adds another Money value to this one.
515
+ *
516
+ * @param other - The Money to add
517
+ * @throws {InvariantViolationError} If currencies don't match
518
+ */
519
+ add(other) {
520
+ this.assertSameCurrency(other);
521
+ return new _Money(
522
+ { amount: this.amount + other.amount, currency: this.currency },
523
+ SKIP_VALUE_OBJECT_VALIDATION
524
+ );
525
+ }
526
+ /**
527
+ * Subtracts another Money value from this one.
528
+ *
529
+ * @param other - The Money to subtract
530
+ * @throws {InvariantViolationError} If currencies don't match
531
+ */
532
+ subtract(other) {
533
+ this.assertSameCurrency(other);
534
+ return new _Money(
535
+ { amount: this.amount - other.amount, currency: this.currency },
536
+ SKIP_VALUE_OBJECT_VALIDATION
537
+ );
538
+ }
539
+ /**
540
+ * Multiplies this Money by a factor.
541
+ *
542
+ * @param factor - The multiplication factor
543
+ */
544
+ multiply(factor) {
545
+ return new _Money(
546
+ { amount: this.amount * factor, currency: this.currency },
547
+ SKIP_VALUE_OBJECT_VALIDATION
548
+ );
549
+ }
550
+ /**
551
+ * Checks if this Money is greater than another.
552
+ *
553
+ * @param other - The Money to compare with
554
+ * @throws {InvariantViolationError} If currencies don't match
555
+ */
556
+ isGreaterThan(other) {
557
+ this.assertSameCurrency(other);
558
+ return this.amount > other.amount;
559
+ }
560
+ /**
561
+ * Checks if this Money is less than another.
562
+ *
563
+ * @param other - The Money to compare with
564
+ * @throws {InvariantViolationError} If currencies don't match
565
+ */
566
+ isLessThan(other) {
567
+ this.assertSameCurrency(other);
568
+ return this.amount < other.amount;
569
+ }
570
+ /**
571
+ * Checks if this Money represents zero.
572
+ */
573
+ isZero() {
574
+ return this.amount === 0;
575
+ }
576
+ /**
577
+ * Asserts that two Money values have the same currency.
578
+ * @internal
579
+ */
580
+ assertSameCurrency(other) {
581
+ if (this.currency !== other.currency) {
582
+ throw new InvariantViolationError({
583
+ message: `Cannot operate on different currencies: ${this.currency} vs ${other.currency}`,
584
+ code: "CURRENCY_MISMATCH"
585
+ });
586
+ }
587
+ }
588
+ };
589
+
590
+ // src/backend/core/onion-layers/domain/example-domain/value-objects/order-id.vo.ts
591
+ var OrderId = class extends BaseUuidV7Vo {
592
+ };
593
+
594
+ // src/backend/core/onion-layers/domain/example-domain/value-objects/order-status.vo.ts
595
+ var OrderStatus = class _OrderStatus extends BaseValueObject {
596
+ /**
597
+ * Creates a new OrderStatus with 'pending' value.
598
+ * Use when creating new orders.
599
+ */
600
+ static pending() {
601
+ return new _OrderStatus("pending", SKIP_VALUE_OBJECT_VALIDATION);
602
+ }
603
+ /**
604
+ * Creates a new OrderStatus with 'confirmed' value.
605
+ * Use when payment is received.
606
+ */
607
+ static confirmed() {
608
+ return new _OrderStatus("confirmed", SKIP_VALUE_OBJECT_VALIDATION);
609
+ }
610
+ /**
611
+ * Creates a new OrderStatus with 'shipped' value.
612
+ * Use when order is dispatched.
613
+ */
614
+ static shipped() {
615
+ return new _OrderStatus("shipped", SKIP_VALUE_OBJECT_VALIDATION);
616
+ }
617
+ /**
618
+ * Creates a new OrderStatus with 'cancelled' value.
619
+ * Use when order is cancelled by customer or system.
620
+ */
621
+ static cancelled() {
622
+ return new _OrderStatus("cancelled", SKIP_VALUE_OBJECT_VALIDATION);
623
+ }
624
+ /**
625
+ * Reconstitutes an OrderStatus from a persisted value.
626
+ *
627
+ * @param value - The status value from persistence
628
+ */
629
+ static fromPersistence(value) {
630
+ return new _OrderStatus(value, SKIP_VALUE_OBJECT_VALIDATION);
631
+ }
632
+ /**
633
+ * Checks if the order is in pending status.
634
+ */
635
+ isPending() {
636
+ return this.value === "pending";
637
+ }
638
+ /**
639
+ * Checks if the order is confirmed.
640
+ */
641
+ isConfirmed() {
642
+ return this.value === "confirmed";
643
+ }
644
+ /**
645
+ * Checks if the order has been shipped.
646
+ */
647
+ isShipped() {
648
+ return this.value === "shipped";
649
+ }
650
+ /**
651
+ * Checks if the order has been cancelled.
652
+ */
653
+ isCancelled() {
654
+ return this.value === "cancelled";
655
+ }
656
+ /**
657
+ * Checks if the order can still be modified (pending or confirmed).
658
+ */
659
+ isModifiable() {
660
+ return this.isPending() || this.isConfirmed();
661
+ }
662
+ };
663
+
664
+ // src/backend/core/onion-layers/domain/example-domain/events/order-cancelled.event.ts
665
+ var OrderCancelledEvent = class extends BaseDomainEvent {
666
+ constructor(payload) {
667
+ super("OrderCancelled", payload.orderId, payload);
668
+ }
669
+ };
670
+
671
+ // src/backend/core/onion-layers/domain/example-domain/events/order-placed.event.ts
672
+ var OrderPlacedEvent = class extends BaseDomainEvent {
673
+ constructor(payload) {
674
+ super("OrderPlaced", payload.orderId, payload);
675
+ }
676
+ };
677
+
678
+ // src/backend/core/onion-layers/domain/example-domain/aggregates/order/policies/value/default-order-status.policy.ts
679
+ var defaultOrderStatus = () => {
680
+ return OrderStatus.pending();
681
+ };
682
+
683
+ // src/backend/core/onion-layers/domain/example-domain/aggregates/order/policies/business/can-add-order-item.policy.ts
684
+ var canAddOrderItem = (order) => {
685
+ return order.status.isPending();
686
+ };
687
+
688
+ // src/backend/core/onion-layers/domain/example-domain/aggregates/order/policies/business/can-cancel-order.policy.ts
689
+ var canCancelOrder = (order) => {
690
+ return order.status.isPending() || order.status.isConfirmed();
691
+ };
692
+
693
+ // src/backend/core/onion-layers/domain/example-domain/aggregates/order/order.aggregate.ts
694
+ var Order = class _Order extends BaseAggregateRoot {
695
+ constructor(id, props, version) {
696
+ super(id, props, version);
697
+ }
698
+ /**
699
+ * Creates a new Order.
700
+ *
701
+ * @param customerId - The customer placing the order
702
+ * @param items - Initial order items
703
+ * @returns A new Order instance with OrderPlacedEvent raised
704
+ */
705
+ static create(customerId, items) {
706
+ const id = OrderId.generate();
707
+ const totalAmount = items.reduce((sum, item) => sum.add(item.totalPrice), Money.zero());
708
+ const order = new _Order(id, {
709
+ customerId,
710
+ items,
711
+ status: defaultOrderStatus(),
712
+ totalAmount,
713
+ placedAt: /* @__PURE__ */ new Date()
714
+ });
715
+ order.addDomainEvent(
716
+ new OrderPlacedEvent({
717
+ orderId: id.value,
718
+ customerId,
719
+ itemCount: items.length,
720
+ totalAmount: totalAmount.amount,
721
+ currency: totalAmount.currency,
722
+ placedAt: order.placedAt.toISOString()
723
+ })
724
+ );
725
+ return order;
726
+ }
727
+ /**
728
+ * Reconstitutes an Order from persistence.
729
+ *
730
+ * @param id - The order ID
731
+ * @param props - The order properties
732
+ * @param version - The version for optimistic locking
733
+ */
734
+ static fromPersistence(id, props, version) {
735
+ return new _Order(id, props, version);
736
+ }
737
+ get customerId() {
738
+ return this.props.customerId;
739
+ }
740
+ get items() {
741
+ return this.props.items;
742
+ }
743
+ get status() {
744
+ return this.props.status;
745
+ }
746
+ get totalAmount() {
747
+ return this.props.totalAmount;
748
+ }
749
+ get placedAt() {
750
+ return this.props.placedAt;
751
+ }
752
+ /**
753
+ * Adds an item to the order.
754
+ *
755
+ * Uses the `canAddOrderItem` business policy to check if the operation is allowed.
756
+ *
757
+ * @param item - The item to add
758
+ * @throws {InvariantViolationError} If the order is not in pending status
759
+ */
760
+ addItem(item) {
761
+ if (!canAddOrderItem(this)) {
762
+ throw new InvariantViolationError({
763
+ message: "Cannot add items to non-pending order",
764
+ code: "ORDER_NOT_PENDING"
765
+ });
766
+ }
767
+ this._props.items.push(item);
768
+ this._props.totalAmount = this._props.totalAmount.add(item.totalPrice);
769
+ }
770
+ /**
771
+ * Confirms the order (e.g., after payment received).
772
+ *
773
+ * @throws {InvariantViolationError} If the order is not in pending status
774
+ */
775
+ confirm() {
776
+ if (!this.status.isPending()) {
777
+ throw new InvariantViolationError({
778
+ message: "Only pending orders can be confirmed",
779
+ code: "ORDER_NOT_PENDING"
780
+ });
781
+ }
782
+ this._props.status = OrderStatus.confirmed();
783
+ }
784
+ /**
785
+ * Marks the order as shipped.
786
+ *
787
+ * @throws {InvariantViolationError} If the order is not confirmed
788
+ */
789
+ ship() {
790
+ if (!this.status.isConfirmed()) {
791
+ throw new InvariantViolationError({
792
+ message: "Only confirmed orders can be shipped",
793
+ code: "ORDER_NOT_CONFIRMED"
794
+ });
795
+ }
796
+ this._props.status = OrderStatus.shipped();
797
+ }
798
+ /**
799
+ * Cancels the order.
800
+ *
801
+ * Uses the `canCancelOrder` business policy to check if the operation is allowed.
802
+ *
803
+ * @param reason - The reason for cancellation
804
+ * @throws {InvariantViolationError} If the order cannot be cancelled
805
+ */
806
+ cancel(reason) {
807
+ if (!canCancelOrder(this)) {
808
+ throw new InvariantViolationError({
809
+ message: "Order cannot be cancelled - already shipped or cancelled",
810
+ code: "ORDER_CANNOT_CANCEL"
811
+ });
812
+ }
813
+ this._props.status = OrderStatus.cancelled();
814
+ this.addDomainEvent(
815
+ new OrderCancelledEvent({
816
+ orderId: this.id.value,
817
+ reason,
818
+ cancelledAt: (/* @__PURE__ */ new Date()).toISOString()
819
+ })
820
+ );
821
+ }
822
+ };
823
+
824
+ // src/backend/core/onion-layers/domain/example-domain/entities/order-item-id.vo.ts
825
+ var OrderItemId = class extends BaseUuidV7Vo {
826
+ };
827
+
828
+ // src/backend/core/onion-layers/domain/example-domain/entities/order-item.entity.ts
829
+ var OrderItem = class _OrderItem extends BaseEntity {
830
+ constructor(id, props) {
831
+ super(id, props);
832
+ }
833
+ /**
834
+ * Creates a new OrderItem.
835
+ */
836
+ static create(props) {
837
+ return new _OrderItem(OrderItemId.generate(), props);
838
+ }
839
+ /**
840
+ * Reconstitutes an OrderItem from persistence.
841
+ */
842
+ static fromPersistence(id, props) {
843
+ return new _OrderItem(id, props);
844
+ }
845
+ get productId() {
846
+ return this.props.productId;
847
+ }
848
+ get productName() {
849
+ return this.props.productName;
850
+ }
851
+ get quantity() {
852
+ return this.props.quantity;
853
+ }
854
+ get unitPrice() {
855
+ return this.props.unitPrice;
856
+ }
857
+ /**
858
+ * Calculates the total price for this line item.
859
+ */
860
+ get totalPrice() {
861
+ return this.props.unitPrice.multiply(this.props.quantity);
862
+ }
863
+ /**
864
+ * Updates the quantity of this item.
865
+ */
866
+ updateQuantity(newQuantity) {
867
+ this._props.quantity = newQuantity;
868
+ }
869
+ /**
870
+ * Converts to a plain object for events or persistence.
871
+ */
872
+ toPlain() {
873
+ return {
874
+ id: this.id.value,
875
+ productId: this.props.productId,
876
+ productName: this.props.productName,
877
+ quantity: this.props.quantity,
878
+ unitPrice: {
879
+ amount: this.props.unitPrice.amount,
880
+ currency: this.props.unitPrice.currency
881
+ }
882
+ };
883
+ }
884
+ };
885
+
886
+ // src/backend/core/onion-layers/domain/example-domain/exceptions/order-already-shipped.error.ts
887
+ var OrderAlreadyShippedError = class extends InvariantViolationError {
888
+ constructor(orderId) {
889
+ super({
890
+ message: `Order ${orderId} has already been shipped and cannot be modified`,
891
+ code: "ORDER_ALREADY_SHIPPED"
892
+ });
893
+ }
894
+ };
895
+
896
+ // src/backend/core/onion-layers/infra/classes/base-outbound-adapter.class.ts
897
+ var WRAPPED_METHODS_SYMBOL = /* @__PURE__ */ Symbol.for("onion-lasagna:wrapped-methods");
898
+ function getWrappedMethods(proto) {
899
+ const existing = proto[WRAPPED_METHODS_SYMBOL];
900
+ if (existing) return existing;
901
+ const newSet = /* @__PURE__ */ new Set();
902
+ Object.defineProperty(proto, WRAPPED_METHODS_SYMBOL, {
903
+ value: newSet,
904
+ writable: false,
905
+ enumerable: false,
906
+ configurable: false
907
+ });
908
+ return newSet;
909
+ }
910
+ var BaseOutboundAdapter = class _BaseOutboundAdapter {
911
+ /**
912
+ * Initializes the adapter and wraps all subclass methods with error handling.
913
+ * Must be called via `super()` in subclass constructors.
914
+ */
915
+ constructor() {
916
+ this.wrapAllSubclassMethods();
917
+ }
918
+ /**
919
+ * Factory method for creating infrastructure errors.
920
+ *
921
+ * Override this in subclasses to return specific error types
922
+ * (e.g., `DbError`, `NetworkError`, `ExternalServiceError`).
923
+ *
924
+ * @param error - The original error that was caught
925
+ * @param methodName - Name of the method where the error occurred (for debugging)
926
+ * @returns An InfraError instance wrapping the original error
927
+ */
928
+ createInfraError(error, methodName) {
929
+ return new InfraError({
930
+ message: `Outbound adapter error in ${methodName}`,
931
+ cause: error
932
+ });
933
+ }
934
+ /**
935
+ * Walks the prototype chain and wraps all methods with error handling.
936
+ * Uses prototype-level Symbol markers to prevent re-wrapping across instances.
937
+ * @internal
938
+ */
939
+ wrapAllSubclassMethods() {
940
+ const wrapMethod = (methodName, original) => {
941
+ const wrapped = (...args) => {
942
+ try {
943
+ const result = Reflect.apply(original, this, args);
944
+ if (result instanceof Promise) {
945
+ return result.catch((error) => {
946
+ throw this.createInfraError(error, methodName);
947
+ });
948
+ }
949
+ return result;
950
+ } catch (error) {
951
+ throw this.createInfraError(error, methodName);
952
+ }
953
+ };
954
+ Object.defineProperty(this, methodName, {
955
+ value: wrapped,
956
+ writable: false,
957
+ enumerable: false,
958
+ configurable: false
959
+ });
960
+ };
961
+ const methodsToWrap = [];
962
+ let proto = Object.getPrototypeOf(this);
963
+ while (proto && proto !== _BaseOutboundAdapter.prototype && proto !== Object.prototype) {
964
+ const wrappedOnProto = getWrappedMethods(proto);
965
+ for (const key of Object.getOwnPropertyNames(proto)) {
966
+ if (key === "constructor") continue;
967
+ if (wrappedOnProto.has(key)) continue;
968
+ const descriptor = Object.getOwnPropertyDescriptor(proto, key);
969
+ if (!descriptor) continue;
970
+ if (descriptor.get || descriptor.set) continue;
971
+ if (typeof descriptor.value !== "function") continue;
972
+ methodsToWrap.push({ name: key, fn: descriptor.value });
973
+ wrappedOnProto.add(key);
974
+ }
975
+ proto = Object.getPrototypeOf(proto);
976
+ }
977
+ for (const { name, fn } of methodsToWrap) {
978
+ wrapMethod(name, fn);
979
+ }
980
+ }
981
+ };
982
+
983
+ // src/backend/core/onion-layers/infra/exceptions/db.error.ts
984
+ var DbError = class _DbError extends InfraError {
985
+ /**
986
+ * Creates a new DbError instance.
987
+ *
988
+ * @param options - Error configuration
989
+ * @param options.message - Description of the database failure
990
+ * @param options.code - Machine-readable error code (default: 'DB_ERROR')
991
+ * @param options.cause - Optional underlying database error
992
+ */
993
+ constructor({
994
+ message,
995
+ code = ErrorCodes.Infra.DB_ERROR,
996
+ cause
997
+ }) {
998
+ super({ message, code, cause });
999
+ }
1000
+ /**
1001
+ * Creates a DbError from a caught error.
1002
+ *
1003
+ * @param cause - The original caught error
1004
+ * @returns A new DbError instance with the cause attached
1005
+ */
1006
+ static fromError(cause) {
1007
+ return new _DbError({
1008
+ message: cause instanceof Error ? cause.message : "Database error",
1009
+ cause
1010
+ });
1011
+ }
1012
+ };
1013
+
1014
+ // src/backend/core/onion-layers/infra/exceptions/network.error.ts
1015
+ var NetworkError = class _NetworkError extends InfraError {
1016
+ /**
1017
+ * Creates a new NetworkError instance.
1018
+ *
1019
+ * @param options - Error configuration
1020
+ * @param options.message - Description of the network failure
1021
+ * @param options.code - Machine-readable error code (default: 'NETWORK_ERROR')
1022
+ * @param options.cause - Optional underlying network error
1023
+ */
1024
+ constructor({
1025
+ message,
1026
+ code = ErrorCodes.Infra.NETWORK_ERROR,
1027
+ cause
1028
+ }) {
1029
+ super({ message, code, cause });
1030
+ }
1031
+ /**
1032
+ * Creates a NetworkError from a caught error.
1033
+ *
1034
+ * @param cause - The original caught error
1035
+ * @returns A new NetworkError instance with the cause attached
1036
+ */
1037
+ static fromError(cause) {
1038
+ return new _NetworkError({
1039
+ message: cause instanceof Error ? cause.message : "Network error",
1040
+ cause
1041
+ });
1042
+ }
1043
+ };
1044
+
1045
+ // src/backend/core/onion-layers/infra/exceptions/timeout.error.ts
1046
+ var TimeoutError = class _TimeoutError extends InfraError {
1047
+ /**
1048
+ * Creates a new TimeoutError instance.
1049
+ *
1050
+ * @param options - Error configuration
1051
+ * @param options.message - Description of what timed out
1052
+ * @param options.code - Machine-readable error code (default: 'TIMEOUT_ERROR')
1053
+ * @param options.cause - Optional underlying timeout error
1054
+ */
1055
+ constructor({
1056
+ message,
1057
+ code = ErrorCodes.Infra.TIMEOUT_ERROR,
1058
+ cause
1059
+ }) {
1060
+ super({ message, code, cause });
1061
+ }
1062
+ /**
1063
+ * Creates a TimeoutError from a caught error.
1064
+ *
1065
+ * @param cause - The original caught error
1066
+ * @returns A new TimeoutError instance with the cause attached
1067
+ */
1068
+ static fromError(cause) {
1069
+ return new _TimeoutError({
1070
+ message: cause instanceof Error ? cause.message : "Operation timed out",
1071
+ cause
1072
+ });
1073
+ }
1074
+ };
1075
+
1076
+ // src/backend/core/onion-layers/infra/exceptions/external-service.error.ts
1077
+ var ExternalServiceError = class _ExternalServiceError extends InfraError {
1078
+ /**
1079
+ * Creates a new ExternalServiceError instance.
1080
+ *
1081
+ * @param options - Error configuration
1082
+ * @param options.message - Description of the external service failure
1083
+ * @param options.code - Machine-readable error code (default: 'EXTERNAL_SERVICE_ERROR')
1084
+ * @param options.cause - Optional underlying service error
1085
+ */
1086
+ constructor({
1087
+ message,
1088
+ code = ErrorCodes.Infra.EXTERNAL_SERVICE_ERROR,
1089
+ cause
1090
+ }) {
1091
+ super({ message, code, cause });
1092
+ }
1093
+ /**
1094
+ * Creates an ExternalServiceError from a caught error.
1095
+ *
1096
+ * @param cause - The original caught error
1097
+ * @returns A new ExternalServiceError instance with the cause attached
1098
+ */
1099
+ static fromError(cause) {
1100
+ return new _ExternalServiceError({
1101
+ message: cause instanceof Error ? cause.message : "External service error",
1102
+ cause
1103
+ });
1104
+ }
1105
+ };
1106
+ export {
1107
+ AccessDeniedError,
1108
+ BaseAggregateRoot,
1109
+ BaseAuditByVo,
1110
+ BaseAuditInfoVo,
1111
+ BaseAuditOnVo,
1112
+ BaseController,
1113
+ BaseDomainEvent,
1114
+ BaseEmailVo,
1115
+ BaseEntity,
1116
+ BaseInboundAdapter,
1117
+ BaseLongTextVo,
1118
+ BaseMediumTextVo,
1119
+ BaseOutboundAdapter,
1120
+ BasePaginationVo,
1121
+ BaseShortTextVo,
1122
+ BaseUuidV4Vo,
1123
+ BaseUuidV7Vo,
1124
+ BaseValueObject,
1125
+ ConflictError,
1126
+ ControllerError,
1127
+ DbError,
1128
+ DomainError,
1129
+ ExternalServiceError,
1130
+ GuardedController,
1131
+ InfraError,
1132
+ InvalidRequestError,
1133
+ InvariantViolationError,
1134
+ Money,
1135
+ NetworkError,
1136
+ NotFoundError,
1137
+ Order,
1138
+ OrderAlreadyShippedError,
1139
+ OrderCancelledEvent,
1140
+ OrderId,
1141
+ OrderItem,
1142
+ OrderItemId,
1143
+ OrderPlacedEvent,
1144
+ OrderStatus,
1145
+ PartialLoadError,
1146
+ SKIP_VALUE_OBJECT_VALIDATION,
1147
+ TimeoutError,
1148
+ UnprocessableError,
1149
+ UseCaseError,
1150
+ assertHttpResponse,
1151
+ canAddOrderItem,
1152
+ canCancelOrder,
1153
+ computeRoutePath,
1154
+ defaultOrderStatus,
1155
+ defineSystemMetadata,
1156
+ isHttpResponse
1157
+ };
1158
+ //# sourceMappingURL=onion-layers.js.map