@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.
- package/dist/backend/core/global.cjs +283 -0
- package/dist/backend/core/global.cjs.map +1 -0
- package/dist/backend/core/global.d.cts +294 -0
- package/dist/backend/core/global.d.ts +294 -0
- package/dist/backend/core/global.js +39 -0
- package/dist/backend/core/global.js.map +1 -0
- package/dist/backend/core/onion-layers.cjs +2302 -0
- package/dist/backend/core/onion-layers.cjs.map +1 -0
- package/dist/backend/core/onion-layers.d.cts +1675 -0
- package/dist/backend/core/onion-layers.d.ts +1675 -0
- package/dist/backend/core/onion-layers.js +1158 -0
- package/dist/backend/core/onion-layers.js.map +1 -0
- package/dist/backend/core/presentation.cjs +573 -0
- package/dist/backend/core/presentation.cjs.map +1 -0
- package/dist/backend/core/presentation.d.cts +5 -0
- package/dist/backend/core/presentation.d.ts +5 -0
- package/dist/backend/core/presentation.js +28 -0
- package/dist/backend/core/presentation.js.map +1 -0
- package/dist/backend/core/validators/arktype.cjs +947 -0
- package/dist/backend/core/validators/arktype.cjs.map +1 -0
- package/dist/backend/core/validators/arktype.d.cts +188 -0
- package/dist/backend/core/validators/arktype.d.ts +188 -0
- package/dist/backend/core/validators/arktype.js +287 -0
- package/dist/backend/core/validators/arktype.js.map +1 -0
- package/dist/backend/core/validators/typebox.cjs +939 -0
- package/dist/backend/core/validators/typebox.cjs.map +1 -0
- package/dist/backend/core/validators/typebox.d.cts +189 -0
- package/dist/backend/core/validators/typebox.d.ts +189 -0
- package/dist/backend/core/validators/typebox.js +281 -0
- package/dist/backend/core/validators/typebox.js.map +1 -0
- package/dist/backend/core/validators/valibot.cjs +942 -0
- package/dist/backend/core/validators/valibot.cjs.map +1 -0
- package/dist/backend/core/validators/valibot.d.cts +160 -0
- package/dist/backend/core/validators/valibot.d.ts +160 -0
- package/dist/backend/core/validators/valibot.js +294 -0
- package/dist/backend/core/validators/valibot.js.map +1 -0
- package/dist/backend/core/validators/zod.cjs +934 -0
- package/dist/backend/core/validators/zod.cjs.map +1 -0
- package/dist/backend/core/validators/zod.d.cts +188 -0
- package/dist/backend/core/validators/zod.d.ts +188 -0
- package/dist/backend/core/validators/zod.js +278 -0
- package/dist/backend/core/validators/zod.js.map +1 -0
- package/dist/backend/frameworks/elysia.cjs +715 -0
- package/dist/backend/frameworks/elysia.cjs.map +1 -0
- package/dist/backend/frameworks/elysia.d.cts +208 -0
- package/dist/backend/frameworks/elysia.d.ts +208 -0
- package/dist/backend/frameworks/elysia.js +251 -0
- package/dist/backend/frameworks/elysia.js.map +1 -0
- package/dist/backend/frameworks/fastify.cjs +677 -0
- package/dist/backend/frameworks/fastify.cjs.map +1 -0
- package/dist/backend/frameworks/fastify.d.cts +201 -0
- package/dist/backend/frameworks/fastify.d.ts +201 -0
- package/dist/backend/frameworks/fastify.js +213 -0
- package/dist/backend/frameworks/fastify.js.map +1 -0
- package/dist/backend/frameworks/hono.cjs +715 -0
- package/dist/backend/frameworks/hono.cjs.map +1 -0
- package/dist/backend/frameworks/hono.d.cts +163 -0
- package/dist/backend/frameworks/hono.d.ts +163 -0
- package/dist/backend/frameworks/hono.js +249 -0
- package/dist/backend/frameworks/hono.js.map +1 -0
- package/dist/backend/frameworks/nestjs.cjs +260 -0
- package/dist/backend/frameworks/nestjs.cjs.map +1 -0
- package/dist/backend/frameworks/nestjs.d.cts +168 -0
- package/dist/backend/frameworks/nestjs.d.ts +168 -0
- package/dist/backend/frameworks/nestjs.js +193 -0
- package/dist/backend/frameworks/nestjs.js.map +1 -0
- package/dist/base-dto.class-D7W9iqoU.d.cts +146 -0
- package/dist/base-dto.class-D7W9iqoU.d.ts +146 -0
- package/dist/base-uuid-v7.vo-BPGEIWLM.d.ts +799 -0
- package/dist/base-uuid-v7.vo-BjqKX44G.d.cts +799 -0
- package/dist/chunk-74IKUOSE.js +116 -0
- package/dist/chunk-74IKUOSE.js.map +1 -0
- package/dist/chunk-BKZOLGQW.js +29 -0
- package/dist/chunk-BKZOLGQW.js.map +1 -0
- package/dist/chunk-CGZBV6BD.js +54 -0
- package/dist/chunk-CGZBV6BD.js.map +1 -0
- package/dist/chunk-DDAHJZVK.js +258 -0
- package/dist/chunk-DDAHJZVK.js.map +1 -0
- package/dist/chunk-MQD5GXMT.js +171 -0
- package/dist/chunk-MQD5GXMT.js.map +1 -0
- package/dist/chunk-OKFXZHBC.js +43 -0
- package/dist/chunk-OKFXZHBC.js.map +1 -0
- package/dist/chunk-RLLWYFPI.js +168 -0
- package/dist/chunk-RLLWYFPI.js.map +1 -0
- package/dist/chunk-VCHFXT5W.js +425 -0
- package/dist/chunk-VCHFXT5W.js.map +1 -0
- package/dist/chunk-ZWLYNGO3.js +40 -0
- package/dist/chunk-ZWLYNGO3.js.map +1 -0
- package/dist/http-response-BAhi8lF4.d.cts +124 -0
- package/dist/http-response-BAhi8lF4.d.ts +124 -0
- package/dist/index-DingXh7B.d.cts +1187 -0
- package/dist/index-tOH7XBa3.d.ts +1187 -0
- package/dist/routing.type-DB4pt-d9.d.ts +184 -0
- package/dist/routing.type-DF2BIL7x.d.cts +184 -0
- package/dist/validation-error.type-kD4_qNZ9.d.cts +199 -0
- package/dist/validation-error.type-kD4_qNZ9.d.ts +199 -0
- package/package.json +191 -0
|
@@ -0,0 +1,2302 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/backend/core/onion-layers/index.ts
|
|
21
|
+
var onion_layers_exports = {};
|
|
22
|
+
__export(onion_layers_exports, {
|
|
23
|
+
AccessDeniedError: () => AccessDeniedError,
|
|
24
|
+
BaseAggregateRoot: () => BaseAggregateRoot,
|
|
25
|
+
BaseAuditByVo: () => BaseAuditByVo,
|
|
26
|
+
BaseAuditInfoVo: () => BaseAuditInfoVo,
|
|
27
|
+
BaseAuditOnVo: () => BaseAuditOnVo,
|
|
28
|
+
BaseController: () => BaseController,
|
|
29
|
+
BaseDomainEvent: () => BaseDomainEvent,
|
|
30
|
+
BaseEmailVo: () => BaseEmailVo,
|
|
31
|
+
BaseEntity: () => BaseEntity,
|
|
32
|
+
BaseInboundAdapter: () => BaseInboundAdapter,
|
|
33
|
+
BaseLongTextVo: () => BaseLongTextVo,
|
|
34
|
+
BaseMediumTextVo: () => BaseMediumTextVo,
|
|
35
|
+
BaseOutboundAdapter: () => BaseOutboundAdapter,
|
|
36
|
+
BasePaginationVo: () => BasePaginationVo,
|
|
37
|
+
BaseShortTextVo: () => BaseShortTextVo,
|
|
38
|
+
BaseUuidV4Vo: () => BaseUuidV4Vo,
|
|
39
|
+
BaseUuidV7Vo: () => BaseUuidV7Vo,
|
|
40
|
+
BaseValueObject: () => BaseValueObject,
|
|
41
|
+
ConflictError: () => ConflictError,
|
|
42
|
+
ControllerError: () => ControllerError,
|
|
43
|
+
DbError: () => DbError,
|
|
44
|
+
DomainError: () => DomainError,
|
|
45
|
+
ExternalServiceError: () => ExternalServiceError,
|
|
46
|
+
GuardedController: () => GuardedController,
|
|
47
|
+
InfraError: () => InfraError,
|
|
48
|
+
InvalidRequestError: () => InvalidRequestError,
|
|
49
|
+
InvariantViolationError: () => InvariantViolationError,
|
|
50
|
+
Money: () => Money,
|
|
51
|
+
NetworkError: () => NetworkError,
|
|
52
|
+
NotFoundError: () => NotFoundError,
|
|
53
|
+
Order: () => Order,
|
|
54
|
+
OrderAlreadyShippedError: () => OrderAlreadyShippedError,
|
|
55
|
+
OrderCancelledEvent: () => OrderCancelledEvent,
|
|
56
|
+
OrderId: () => OrderId,
|
|
57
|
+
OrderItem: () => OrderItem,
|
|
58
|
+
OrderItemId: () => OrderItemId,
|
|
59
|
+
OrderPlacedEvent: () => OrderPlacedEvent,
|
|
60
|
+
OrderStatus: () => OrderStatus,
|
|
61
|
+
PartialLoadError: () => PartialLoadError,
|
|
62
|
+
SKIP_VALUE_OBJECT_VALIDATION: () => SKIP_VALUE_OBJECT_VALIDATION,
|
|
63
|
+
TimeoutError: () => TimeoutError,
|
|
64
|
+
UnprocessableError: () => UnprocessableError,
|
|
65
|
+
UseCaseError: () => UseCaseError,
|
|
66
|
+
assertHttpResponse: () => assertHttpResponse,
|
|
67
|
+
canAddOrderItem: () => canAddOrderItem,
|
|
68
|
+
canCancelOrder: () => canCancelOrder,
|
|
69
|
+
computeRoutePath: () => computeRoutePath,
|
|
70
|
+
defaultOrderStatus: () => defaultOrderStatus,
|
|
71
|
+
defineSystemMetadata: () => defineSystemMetadata,
|
|
72
|
+
isHttpResponse: () => isHttpResponse
|
|
73
|
+
});
|
|
74
|
+
module.exports = __toCommonJS(onion_layers_exports);
|
|
75
|
+
|
|
76
|
+
// src/backend/core/global/exceptions/coded-error.error.ts
|
|
77
|
+
var CodedError = class extends Error {
|
|
78
|
+
/** Machine-readable error code for programmatic handling. */
|
|
79
|
+
code;
|
|
80
|
+
/**
|
|
81
|
+
* Creates a new CodedError instance.
|
|
82
|
+
*
|
|
83
|
+
* @param options - Error configuration
|
|
84
|
+
* @param options.message - Human-readable error message
|
|
85
|
+
* @param options.code - Machine-readable error code from ErrorCodes registry or custom string
|
|
86
|
+
* @param options.cause - Optional underlying error that caused this error
|
|
87
|
+
*/
|
|
88
|
+
constructor({
|
|
89
|
+
message,
|
|
90
|
+
code,
|
|
91
|
+
cause
|
|
92
|
+
}) {
|
|
93
|
+
super(message);
|
|
94
|
+
this.name = this.constructor.name;
|
|
95
|
+
this.code = code;
|
|
96
|
+
if (cause !== void 0) {
|
|
97
|
+
Object.defineProperty(this, "cause", {
|
|
98
|
+
value: cause,
|
|
99
|
+
writable: false,
|
|
100
|
+
enumerable: false,
|
|
101
|
+
configurable: true
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Factory method to create a typed error from a caught error.
|
|
107
|
+
*
|
|
108
|
+
* Subclasses should override this to provide proper error transformation.
|
|
109
|
+
* Designed for use with {@link wrapErrorAsync} and {@link wrapError}.
|
|
110
|
+
*
|
|
111
|
+
* @param _cause - The original caught error
|
|
112
|
+
* @returns A new CodedError instance
|
|
113
|
+
* @throws {Error} If not overridden by subclass
|
|
114
|
+
*
|
|
115
|
+
* @example
|
|
116
|
+
* ```typescript
|
|
117
|
+
* class NotFoundError extends UseCaseError {
|
|
118
|
+
* static override fromError(cause: unknown): NotFoundError {
|
|
119
|
+
* return new NotFoundError({
|
|
120
|
+
* message: 'Resource not found',
|
|
121
|
+
* cause,
|
|
122
|
+
* });
|
|
123
|
+
* }
|
|
124
|
+
* }
|
|
125
|
+
* ```
|
|
126
|
+
*/
|
|
127
|
+
static fromError(_cause) {
|
|
128
|
+
throw new Error(`${this.name}.fromError() must be implemented by subclass`);
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
// src/backend/core/global/exceptions/error-codes.const.ts
|
|
133
|
+
var ErrorCodes = {
|
|
134
|
+
/**
|
|
135
|
+
* Domain layer error codes.
|
|
136
|
+
* Used for business rule violations and invariant failures.
|
|
137
|
+
*/
|
|
138
|
+
Domain: {
|
|
139
|
+
/** Generic domain error */
|
|
140
|
+
DOMAIN_ERROR: "DOMAIN_ERROR",
|
|
141
|
+
/** Business invariant was violated */
|
|
142
|
+
INVARIANT_VIOLATION: "INVARIANT_VIOLATION",
|
|
143
|
+
/** Aggregate was partially loaded (missing required relations) */
|
|
144
|
+
PARTIAL_LOAD: "PARTIAL_LOAD"
|
|
145
|
+
},
|
|
146
|
+
/**
|
|
147
|
+
* Application layer (use case) error codes.
|
|
148
|
+
* Used for orchestration failures and business operation errors.
|
|
149
|
+
*/
|
|
150
|
+
App: {
|
|
151
|
+
/** Generic use case error */
|
|
152
|
+
USE_CASE_ERROR: "USE_CASE_ERROR",
|
|
153
|
+
/** Requested resource was not found */
|
|
154
|
+
NOT_FOUND: "NOT_FOUND",
|
|
155
|
+
/** Resource state conflict (e.g., duplicate, already exists) */
|
|
156
|
+
CONFLICT: "CONFLICT",
|
|
157
|
+
/** Request is valid but cannot be processed due to business rules */
|
|
158
|
+
UNPROCESSABLE: "UNPROCESSABLE"
|
|
159
|
+
},
|
|
160
|
+
/**
|
|
161
|
+
* Infrastructure layer error codes.
|
|
162
|
+
* Used for data access, external services, and I/O failures.
|
|
163
|
+
*/
|
|
164
|
+
Infra: {
|
|
165
|
+
/** Generic infrastructure error */
|
|
166
|
+
INFRA_ERROR: "INFRA_ERROR",
|
|
167
|
+
/** Database operation failed */
|
|
168
|
+
DB_ERROR: "DB_ERROR",
|
|
169
|
+
/** Network connectivity or communication error */
|
|
170
|
+
NETWORK_ERROR: "NETWORK_ERROR",
|
|
171
|
+
/** Operation timed out */
|
|
172
|
+
TIMEOUT_ERROR: "TIMEOUT_ERROR",
|
|
173
|
+
/** External/third-party service error */
|
|
174
|
+
EXTERNAL_SERVICE_ERROR: "EXTERNAL_SERVICE_ERROR"
|
|
175
|
+
},
|
|
176
|
+
/**
|
|
177
|
+
* Presentation layer error codes.
|
|
178
|
+
* Used for controller, request handling, and authorization errors.
|
|
179
|
+
*/
|
|
180
|
+
Presentation: {
|
|
181
|
+
/** Generic controller error */
|
|
182
|
+
CONTROLLER_ERROR: "CONTROLLER_ERROR",
|
|
183
|
+
/** Request denied due to authorization failure */
|
|
184
|
+
ACCESS_DENIED: "ACCESS_DENIED",
|
|
185
|
+
/** Request validation failed (malformed input) */
|
|
186
|
+
INVALID_REQUEST: "INVALID_REQUEST"
|
|
187
|
+
},
|
|
188
|
+
/**
|
|
189
|
+
* Global/cross-cutting error codes.
|
|
190
|
+
* Used for validation and other cross-layer concerns.
|
|
191
|
+
*/
|
|
192
|
+
Global: {
|
|
193
|
+
/** Object/schema validation failed */
|
|
194
|
+
OBJECT_VALIDATION_ERROR: "OBJECT_VALIDATION_ERROR"
|
|
195
|
+
}
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
// src/backend/core/global/exceptions/object-validation.error.ts
|
|
199
|
+
var ObjectValidationError = class _ObjectValidationError extends CodedError {
|
|
200
|
+
/**
|
|
201
|
+
* Array of field-level validation errors.
|
|
202
|
+
*
|
|
203
|
+
* Each entry contains:
|
|
204
|
+
* - `field`: Dot-notation path to the invalid field (e.g., 'user.email')
|
|
205
|
+
* - `message`: Human-readable validation failure message
|
|
206
|
+
*/
|
|
207
|
+
validationErrors;
|
|
208
|
+
/**
|
|
209
|
+
* Creates a new ObjectValidationError instance.
|
|
210
|
+
*
|
|
211
|
+
* @param options - Error configuration
|
|
212
|
+
* @param options.message - Human-readable summary message
|
|
213
|
+
* @param options.code - Machine-readable error code (default: 'OBJECT_VALIDATION_ERROR')
|
|
214
|
+
* @param options.cause - Optional underlying error from validation library
|
|
215
|
+
* @param options.validationErrors - Array of field-level validation errors
|
|
216
|
+
*/
|
|
217
|
+
constructor({
|
|
218
|
+
message,
|
|
219
|
+
code = ErrorCodes.Global.OBJECT_VALIDATION_ERROR,
|
|
220
|
+
cause,
|
|
221
|
+
validationErrors
|
|
222
|
+
}) {
|
|
223
|
+
super({ message, code, cause });
|
|
224
|
+
this.validationErrors = validationErrors;
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Creates an ObjectValidationError from a caught error.
|
|
228
|
+
*
|
|
229
|
+
* @param cause - The original caught error
|
|
230
|
+
* @returns A new ObjectValidationError instance with the cause attached
|
|
231
|
+
*/
|
|
232
|
+
static fromError(cause) {
|
|
233
|
+
return new _ObjectValidationError({
|
|
234
|
+
message: cause instanceof Error ? cause.message : "Validation failed",
|
|
235
|
+
cause,
|
|
236
|
+
validationErrors: []
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
// src/backend/core/global/utils/wrap-error.util.ts
|
|
242
|
+
function wrapErrorUnless(fn, errorFactory, passthroughTypes) {
|
|
243
|
+
try {
|
|
244
|
+
return fn();
|
|
245
|
+
} catch (error) {
|
|
246
|
+
if (passthroughTypes.some((Type) => error instanceof Type)) {
|
|
247
|
+
throw error;
|
|
248
|
+
}
|
|
249
|
+
throw errorFactory(error);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
async function wrapErrorUnlessAsync(fn, errorFactory, passthroughTypes) {
|
|
253
|
+
try {
|
|
254
|
+
return await fn();
|
|
255
|
+
} catch (error) {
|
|
256
|
+
if (passthroughTypes.some((Type) => error instanceof Type)) {
|
|
257
|
+
throw error;
|
|
258
|
+
}
|
|
259
|
+
throw errorFactory(error);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// src/backend/core/onion-layers/app/exceptions/use-case.error.ts
|
|
264
|
+
var UseCaseError = class _UseCaseError extends CodedError {
|
|
265
|
+
/**
|
|
266
|
+
* Creates a new UseCaseError instance.
|
|
267
|
+
*
|
|
268
|
+
* @param options - Error configuration
|
|
269
|
+
* @param options.message - Human-readable error description
|
|
270
|
+
* @param options.code - Machine-readable error code (default: 'USE_CASE_ERROR')
|
|
271
|
+
* @param options.cause - Optional underlying error
|
|
272
|
+
*/
|
|
273
|
+
constructor({
|
|
274
|
+
message,
|
|
275
|
+
code = ErrorCodes.App.USE_CASE_ERROR,
|
|
276
|
+
cause
|
|
277
|
+
}) {
|
|
278
|
+
super({ message, code, cause });
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Creates a UseCaseError from a caught error.
|
|
282
|
+
*
|
|
283
|
+
* @param cause - The original caught error
|
|
284
|
+
* @returns A new UseCaseError instance with the cause attached
|
|
285
|
+
*/
|
|
286
|
+
static fromError(cause) {
|
|
287
|
+
return new _UseCaseError({
|
|
288
|
+
message: cause instanceof Error ? cause.message : "Use case error",
|
|
289
|
+
cause
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
};
|
|
293
|
+
|
|
294
|
+
// src/backend/core/onion-layers/domain/exceptions/domain.error.ts
|
|
295
|
+
var DomainError = class _DomainError extends CodedError {
|
|
296
|
+
/**
|
|
297
|
+
* Creates a new DomainError instance.
|
|
298
|
+
*
|
|
299
|
+
* @param options - Error configuration
|
|
300
|
+
* @param options.message - Human-readable error description
|
|
301
|
+
* @param options.code - Machine-readable error code (default: 'DOMAIN_ERROR')
|
|
302
|
+
* @param options.cause - Optional underlying error
|
|
303
|
+
*/
|
|
304
|
+
constructor({
|
|
305
|
+
message,
|
|
306
|
+
code = ErrorCodes.Domain.DOMAIN_ERROR,
|
|
307
|
+
cause
|
|
308
|
+
}) {
|
|
309
|
+
super({ message, code, cause });
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* Creates a DomainError from a caught error.
|
|
313
|
+
*
|
|
314
|
+
* @param cause - The original caught error
|
|
315
|
+
* @returns A new DomainError instance with the cause attached
|
|
316
|
+
*/
|
|
317
|
+
static fromError(cause) {
|
|
318
|
+
return new _DomainError({
|
|
319
|
+
message: cause instanceof Error ? cause.message : "Domain error",
|
|
320
|
+
cause
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
};
|
|
324
|
+
|
|
325
|
+
// src/backend/core/onion-layers/infra/exceptions/infra.error.ts
|
|
326
|
+
var InfraError = class _InfraError extends CodedError {
|
|
327
|
+
/**
|
|
328
|
+
* Creates a new InfraError instance.
|
|
329
|
+
*
|
|
330
|
+
* @param options - Error configuration
|
|
331
|
+
* @param options.message - Human-readable error description
|
|
332
|
+
* @param options.code - Machine-readable error code (default: 'INFRA_ERROR')
|
|
333
|
+
* @param options.cause - Optional underlying error
|
|
334
|
+
*/
|
|
335
|
+
constructor({
|
|
336
|
+
message,
|
|
337
|
+
code = ErrorCodes.Infra.INFRA_ERROR,
|
|
338
|
+
cause
|
|
339
|
+
}) {
|
|
340
|
+
super({ message, code, cause });
|
|
341
|
+
}
|
|
342
|
+
/**
|
|
343
|
+
* Creates an InfraError from a caught error.
|
|
344
|
+
*
|
|
345
|
+
* @param cause - The original caught error
|
|
346
|
+
* @returns A new InfraError instance with the cause attached
|
|
347
|
+
*/
|
|
348
|
+
static fromError(cause) {
|
|
349
|
+
return new _InfraError({
|
|
350
|
+
message: cause instanceof Error ? cause.message : "Infrastructure error",
|
|
351
|
+
cause
|
|
352
|
+
});
|
|
353
|
+
}
|
|
354
|
+
};
|
|
355
|
+
|
|
356
|
+
// src/backend/core/onion-layers/app/classes/base-inbound-adapter.class.ts
|
|
357
|
+
var BaseInboundAdapter = class {
|
|
358
|
+
/**
|
|
359
|
+
* Executes the use case with error boundary protection.
|
|
360
|
+
*
|
|
361
|
+
* Known error types are re-thrown as-is to preserve error semantics.
|
|
362
|
+
* Unknown errors are wrapped in a UseCaseError to maintain error hierarchy.
|
|
363
|
+
*
|
|
364
|
+
* @param input - Validated input DTO
|
|
365
|
+
* @returns Promise resolving to the output DTO
|
|
366
|
+
* @throws {ObjectValidationError} For validation failures (propagated to controller)
|
|
367
|
+
* @throws {UseCaseError} For use case failures or wrapped unknown errors
|
|
368
|
+
* @throws {DomainError} For domain invariant violations
|
|
369
|
+
* @throws {InfraError} For infrastructure failures
|
|
370
|
+
*/
|
|
371
|
+
async execute(input) {
|
|
372
|
+
return wrapErrorUnlessAsync(
|
|
373
|
+
() => this.handle(input),
|
|
374
|
+
(cause) => new UseCaseError({ message: "Unexpected use case handler error", cause }),
|
|
375
|
+
[ObjectValidationError, UseCaseError, DomainError, InfraError]
|
|
376
|
+
);
|
|
377
|
+
}
|
|
378
|
+
};
|
|
379
|
+
|
|
380
|
+
// src/backend/core/onion-layers/app/exceptions/not-found.error.ts
|
|
381
|
+
var NotFoundError = class _NotFoundError extends UseCaseError {
|
|
382
|
+
/**
|
|
383
|
+
* Creates a new NotFoundError instance.
|
|
384
|
+
*
|
|
385
|
+
* @param options - Error configuration
|
|
386
|
+
* @param options.message - Description of what was not found
|
|
387
|
+
* @param options.code - Machine-readable error code (default: 'NOT_FOUND')
|
|
388
|
+
* @param options.cause - Optional underlying error
|
|
389
|
+
*/
|
|
390
|
+
constructor({
|
|
391
|
+
message,
|
|
392
|
+
code = ErrorCodes.App.NOT_FOUND,
|
|
393
|
+
cause
|
|
394
|
+
}) {
|
|
395
|
+
super({ message, code, cause });
|
|
396
|
+
}
|
|
397
|
+
/**
|
|
398
|
+
* Creates a NotFoundError from a caught error.
|
|
399
|
+
*
|
|
400
|
+
* @param cause - The original caught error
|
|
401
|
+
* @returns A new NotFoundError instance with the cause attached
|
|
402
|
+
*/
|
|
403
|
+
static fromError(cause) {
|
|
404
|
+
return new _NotFoundError({
|
|
405
|
+
message: cause instanceof Error ? cause.message : "Resource not found",
|
|
406
|
+
cause
|
|
407
|
+
});
|
|
408
|
+
}
|
|
409
|
+
};
|
|
410
|
+
|
|
411
|
+
// src/backend/core/onion-layers/app/exceptions/conflict.error.ts
|
|
412
|
+
var ConflictError = class _ConflictError extends UseCaseError {
|
|
413
|
+
/**
|
|
414
|
+
* Creates a new ConflictError instance.
|
|
415
|
+
*
|
|
416
|
+
* @param options - Error configuration
|
|
417
|
+
* @param options.message - Description of the conflict
|
|
418
|
+
* @param options.code - Machine-readable error code (default: 'CONFLICT')
|
|
419
|
+
* @param options.cause - Optional underlying error
|
|
420
|
+
*/
|
|
421
|
+
constructor({
|
|
422
|
+
message,
|
|
423
|
+
code = ErrorCodes.App.CONFLICT,
|
|
424
|
+
cause
|
|
425
|
+
}) {
|
|
426
|
+
super({ message, code, cause });
|
|
427
|
+
}
|
|
428
|
+
/**
|
|
429
|
+
* Creates a ConflictError from a caught error.
|
|
430
|
+
*
|
|
431
|
+
* @param cause - The original caught error
|
|
432
|
+
* @returns A new ConflictError instance with the cause attached
|
|
433
|
+
*/
|
|
434
|
+
static fromError(cause) {
|
|
435
|
+
return new _ConflictError({
|
|
436
|
+
message: cause instanceof Error ? cause.message : "Conflict error",
|
|
437
|
+
cause
|
|
438
|
+
});
|
|
439
|
+
}
|
|
440
|
+
};
|
|
441
|
+
|
|
442
|
+
// src/backend/core/onion-layers/app/exceptions/unprocessable.error.ts
|
|
443
|
+
var UnprocessableError = class _UnprocessableError extends UseCaseError {
|
|
444
|
+
/**
|
|
445
|
+
* Creates a new UnprocessableError instance.
|
|
446
|
+
*
|
|
447
|
+
* @param options - Error configuration
|
|
448
|
+
* @param options.message - Description of why the request cannot be processed
|
|
449
|
+
* @param options.code - Machine-readable error code (default: 'UNPROCESSABLE')
|
|
450
|
+
* @param options.cause - Optional underlying error
|
|
451
|
+
*/
|
|
452
|
+
constructor({
|
|
453
|
+
message,
|
|
454
|
+
code = ErrorCodes.App.UNPROCESSABLE,
|
|
455
|
+
cause
|
|
456
|
+
}) {
|
|
457
|
+
super({ message, code, cause });
|
|
458
|
+
}
|
|
459
|
+
/**
|
|
460
|
+
* Creates an UnprocessableError from a caught error.
|
|
461
|
+
*
|
|
462
|
+
* @param cause - The original caught error
|
|
463
|
+
* @returns A new UnprocessableError instance with the cause attached
|
|
464
|
+
*/
|
|
465
|
+
static fromError(cause) {
|
|
466
|
+
return new _UnprocessableError({
|
|
467
|
+
message: cause instanceof Error ? cause.message : "Unprocessable request",
|
|
468
|
+
cause
|
|
469
|
+
});
|
|
470
|
+
}
|
|
471
|
+
};
|
|
472
|
+
|
|
473
|
+
// src/backend/core/onion-layers/domain/classes/base-entity.class.ts
|
|
474
|
+
var BaseEntity = class {
|
|
475
|
+
_id;
|
|
476
|
+
_props;
|
|
477
|
+
_version;
|
|
478
|
+
/**
|
|
479
|
+
* Creates a new Entity instance.
|
|
480
|
+
*
|
|
481
|
+
* @param id - The unique identifier for this entity
|
|
482
|
+
* @param props - The entity's properties/state (should be composed of Value Objects)
|
|
483
|
+
* @param version - Optional version number for optimistic locking (defaults to 0)
|
|
484
|
+
*/
|
|
485
|
+
constructor(id, props, version = 0) {
|
|
486
|
+
this._id = id;
|
|
487
|
+
this._props = props;
|
|
488
|
+
this._version = version;
|
|
489
|
+
}
|
|
490
|
+
/**
|
|
491
|
+
* The unique identifier for this entity.
|
|
492
|
+
*
|
|
493
|
+
* @returns The entity's ID of type TId
|
|
494
|
+
*/
|
|
495
|
+
get id() {
|
|
496
|
+
return this._id;
|
|
497
|
+
}
|
|
498
|
+
/**
|
|
499
|
+
* The entity's properties/state.
|
|
500
|
+
*
|
|
501
|
+
* Protected to encourage encapsulation via specific getters.
|
|
502
|
+
* Subclasses should expose individual properties as needed.
|
|
503
|
+
*
|
|
504
|
+
* @returns The entity's properties of type TProps
|
|
505
|
+
*/
|
|
506
|
+
get props() {
|
|
507
|
+
return this._props;
|
|
508
|
+
}
|
|
509
|
+
/**
|
|
510
|
+
* The version number for optimistic locking.
|
|
511
|
+
*
|
|
512
|
+
* Use this to detect concurrent modifications:
|
|
513
|
+
* - Load entity with version N
|
|
514
|
+
* - Attempt to save with "WHERE version = N"
|
|
515
|
+
* - If rows affected = 0, another process modified the entity
|
|
516
|
+
*
|
|
517
|
+
* @returns The current version number
|
|
518
|
+
*/
|
|
519
|
+
get version() {
|
|
520
|
+
return this._version;
|
|
521
|
+
}
|
|
522
|
+
/**
|
|
523
|
+
* Compares this Entity with another for equality.
|
|
524
|
+
*
|
|
525
|
+
* Entities are equal if they have the same identity (ID).
|
|
526
|
+
* This differs from Value Objects which compare by value.
|
|
527
|
+
*
|
|
528
|
+
* @param other - The Entity to compare with
|
|
529
|
+
* @returns `true` if the IDs are equal, `false` otherwise
|
|
530
|
+
*
|
|
531
|
+
* @example
|
|
532
|
+
* ```typescript
|
|
533
|
+
* const user1 = User.create(PersonName.create('John'), Email.create('john@example.com'));
|
|
534
|
+
* const user2 = User.fromPersistence(user1.id, { name: PersonName.create('John Updated'), ... }, 1);
|
|
535
|
+
* user1.equals(user2); // true - same ID, different state
|
|
536
|
+
* ```
|
|
537
|
+
*/
|
|
538
|
+
equals(other) {
|
|
539
|
+
if (this === other) return true;
|
|
540
|
+
return this.idEquals(this._id, other._id);
|
|
541
|
+
}
|
|
542
|
+
/**
|
|
543
|
+
* Compares two IDs for equality.
|
|
544
|
+
*
|
|
545
|
+
* Since TId must extend BaseValueObject, we use the value object's
|
|
546
|
+
* `equals` method for comparison.
|
|
547
|
+
*
|
|
548
|
+
* @param a - First ID to compare
|
|
549
|
+
* @param b - Second ID to compare
|
|
550
|
+
* @returns `true` if IDs are equal, `false` otherwise
|
|
551
|
+
*/
|
|
552
|
+
idEquals(a, b) {
|
|
553
|
+
if (a === b) return true;
|
|
554
|
+
return a.equals(b);
|
|
555
|
+
}
|
|
556
|
+
/**
|
|
557
|
+
* Returns the next version number.
|
|
558
|
+
*
|
|
559
|
+
* Call this when persisting changes to implement optimistic locking.
|
|
560
|
+
* The repository should save with version + 1.
|
|
561
|
+
*
|
|
562
|
+
* @returns The next version number (current + 1)
|
|
563
|
+
*
|
|
564
|
+
* @example
|
|
565
|
+
* ```typescript
|
|
566
|
+
* // In repository
|
|
567
|
+
* async save(entity: User): Promise<void> {
|
|
568
|
+
* await this.db.update({
|
|
569
|
+
* ...entity.toPersistence(),
|
|
570
|
+
* version: entity.nextVersion(),
|
|
571
|
+
* }).where({ id: entity.id, version: entity.version });
|
|
572
|
+
* }
|
|
573
|
+
* ```
|
|
574
|
+
*/
|
|
575
|
+
nextVersion() {
|
|
576
|
+
return this._version + 1;
|
|
577
|
+
}
|
|
578
|
+
};
|
|
579
|
+
|
|
580
|
+
// src/backend/core/onion-layers/domain/classes/base-aggregate-root.class.ts
|
|
581
|
+
var BaseAggregateRoot = class extends BaseEntity {
|
|
582
|
+
_domainEvents = [];
|
|
583
|
+
/**
|
|
584
|
+
* Creates a new Aggregate Root instance.
|
|
585
|
+
*
|
|
586
|
+
* @param id - The unique identifier for this aggregate
|
|
587
|
+
* @param props - The aggregate's properties/state (should be composed of Value Objects)
|
|
588
|
+
* @param version - Optional version number for optimistic locking (defaults to 0)
|
|
589
|
+
*/
|
|
590
|
+
constructor(id, props, version) {
|
|
591
|
+
super(id, props, version);
|
|
592
|
+
}
|
|
593
|
+
/**
|
|
594
|
+
* Adds a domain event to be published after persistence.
|
|
595
|
+
*
|
|
596
|
+
* Call this method when a significant domain action occurs.
|
|
597
|
+
* Events are collected and should be published by the repository
|
|
598
|
+
* after successfully persisting the aggregate.
|
|
599
|
+
*
|
|
600
|
+
* @param event - The domain event to add
|
|
601
|
+
*
|
|
602
|
+
* @example
|
|
603
|
+
* ```typescript
|
|
604
|
+
* confirm(): void {
|
|
605
|
+
* this._props.status = OrderStatus.confirmed();
|
|
606
|
+
* this.addDomainEvent(new OrderConfirmedEvent({
|
|
607
|
+
* orderId: this.id.value,
|
|
608
|
+
* confirmedAt: new Date(),
|
|
609
|
+
* }));
|
|
610
|
+
* }
|
|
611
|
+
* ```
|
|
612
|
+
*/
|
|
613
|
+
addDomainEvent(event) {
|
|
614
|
+
this._domainEvents.push(event);
|
|
615
|
+
}
|
|
616
|
+
/**
|
|
617
|
+
* Returns and clears all pending domain events.
|
|
618
|
+
*
|
|
619
|
+
* This method should be called by the repository after successfully
|
|
620
|
+
* persisting the aggregate. The events are cleared to prevent
|
|
621
|
+
* duplicate publishing.
|
|
622
|
+
*
|
|
623
|
+
* @returns Array of domain events that were pending
|
|
624
|
+
*
|
|
625
|
+
* @example
|
|
626
|
+
* ```typescript
|
|
627
|
+
* // In repository
|
|
628
|
+
* async save(order: Order): Promise<void> {
|
|
629
|
+
* await this.db.transaction(async (tx) => {
|
|
630
|
+
* await tx.orders.upsert(order.toPersistence());
|
|
631
|
+
* });
|
|
632
|
+
*
|
|
633
|
+
* // Only publish after successful persistence
|
|
634
|
+
* const events = order.pullDomainEvents();
|
|
635
|
+
* for (const event of events) {
|
|
636
|
+
* await this.eventBus.publish(event);
|
|
637
|
+
* }
|
|
638
|
+
* }
|
|
639
|
+
* ```
|
|
640
|
+
*/
|
|
641
|
+
pullDomainEvents() {
|
|
642
|
+
const events = [...this._domainEvents];
|
|
643
|
+
this._domainEvents = [];
|
|
644
|
+
return events;
|
|
645
|
+
}
|
|
646
|
+
/**
|
|
647
|
+
* Returns pending domain events without clearing them.
|
|
648
|
+
*
|
|
649
|
+
* Useful for inspection or testing without affecting the event queue.
|
|
650
|
+
*
|
|
651
|
+
* @returns Array of pending domain events
|
|
652
|
+
*/
|
|
653
|
+
peekDomainEvents() {
|
|
654
|
+
return [...this._domainEvents];
|
|
655
|
+
}
|
|
656
|
+
/**
|
|
657
|
+
* Checks if there are any pending domain events.
|
|
658
|
+
*
|
|
659
|
+
* @returns `true` if there are events waiting to be published
|
|
660
|
+
*
|
|
661
|
+
* @example
|
|
662
|
+
* ```typescript
|
|
663
|
+
* if (order.hasDomainEvents) {
|
|
664
|
+
* const events = order.pullDomainEvents();
|
|
665
|
+
* await eventBus.publishAll(events);
|
|
666
|
+
* }
|
|
667
|
+
* ```
|
|
668
|
+
*/
|
|
669
|
+
get hasDomainEvents() {
|
|
670
|
+
return this._domainEvents.length > 0;
|
|
671
|
+
}
|
|
672
|
+
/**
|
|
673
|
+
* Clears all pending domain events without returning them.
|
|
674
|
+
*
|
|
675
|
+
* Use with caution - this discards events that haven't been published.
|
|
676
|
+
* Useful in testing or when intentionally discarding events.
|
|
677
|
+
*/
|
|
678
|
+
clearDomainEvents() {
|
|
679
|
+
this._domainEvents = [];
|
|
680
|
+
}
|
|
681
|
+
};
|
|
682
|
+
|
|
683
|
+
// src/backend/core/onion-layers/domain/classes/base-domain-event.class.ts
|
|
684
|
+
var BaseDomainEvent = class _BaseDomainEvent {
|
|
685
|
+
_eventId;
|
|
686
|
+
_eventName;
|
|
687
|
+
_aggregateId;
|
|
688
|
+
_occurredOn;
|
|
689
|
+
_payload;
|
|
690
|
+
/**
|
|
691
|
+
* Deep clones an object, handling Date objects specially.
|
|
692
|
+
*
|
|
693
|
+
* @param obj - The object to clone
|
|
694
|
+
* @returns A deep copy of the object
|
|
695
|
+
*/
|
|
696
|
+
static deepClone(obj) {
|
|
697
|
+
if (obj === null || typeof obj !== "object") {
|
|
698
|
+
return obj;
|
|
699
|
+
}
|
|
700
|
+
if (obj instanceof Date) {
|
|
701
|
+
return new Date(obj.getTime());
|
|
702
|
+
}
|
|
703
|
+
if (Array.isArray(obj)) {
|
|
704
|
+
return obj.map((item) => _BaseDomainEvent.deepClone(item));
|
|
705
|
+
}
|
|
706
|
+
const cloned = {};
|
|
707
|
+
for (const key of Object.keys(obj)) {
|
|
708
|
+
cloned[key] = _BaseDomainEvent.deepClone(obj[key]);
|
|
709
|
+
}
|
|
710
|
+
return cloned;
|
|
711
|
+
}
|
|
712
|
+
/**
|
|
713
|
+
* Recursively freezes an object and all nested objects.
|
|
714
|
+
*
|
|
715
|
+
* @param obj - The object to deep freeze
|
|
716
|
+
* @returns The frozen object
|
|
717
|
+
*/
|
|
718
|
+
static deepFreeze(obj) {
|
|
719
|
+
if (obj === null || typeof obj !== "object") {
|
|
720
|
+
return obj;
|
|
721
|
+
}
|
|
722
|
+
if (Array.isArray(obj)) {
|
|
723
|
+
obj.forEach((item) => _BaseDomainEvent.deepFreeze(item));
|
|
724
|
+
return Object.freeze(obj);
|
|
725
|
+
}
|
|
726
|
+
for (const key of Object.keys(obj)) {
|
|
727
|
+
const value = obj[key];
|
|
728
|
+
if (value !== null && typeof value === "object") {
|
|
729
|
+
_BaseDomainEvent.deepFreeze(value);
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
return Object.freeze(obj);
|
|
733
|
+
}
|
|
734
|
+
/**
|
|
735
|
+
* Creates an immutable copy of the payload.
|
|
736
|
+
*
|
|
737
|
+
* Clones the payload first to avoid mutating the original object,
|
|
738
|
+
* then deep-freezes the clone to ensure immutability.
|
|
739
|
+
*
|
|
740
|
+
* @param payload - The payload to clone and freeze
|
|
741
|
+
* @returns An immutable copy of the payload
|
|
742
|
+
*/
|
|
743
|
+
static cloneAndFreeze(payload) {
|
|
744
|
+
const cloned = _BaseDomainEvent.deepClone(payload);
|
|
745
|
+
return _BaseDomainEvent.deepFreeze(cloned);
|
|
746
|
+
}
|
|
747
|
+
/**
|
|
748
|
+
* Creates a new Domain Event.
|
|
749
|
+
*
|
|
750
|
+
* The payload is cloned and deep-frozen to ensure immutability. The original
|
|
751
|
+
* object passed in remains unmodified. Any attempt to modify the event's
|
|
752
|
+
* payload after creation will throw a TypeError in strict mode.
|
|
753
|
+
*
|
|
754
|
+
* @param eventName - The name of the event (e.g., 'OrderPlaced', 'UserRegistered')
|
|
755
|
+
* @param aggregateId - The ID of the aggregate that raised this event
|
|
756
|
+
* @param payload - The event-specific data (will be cloned and deep-frozen)
|
|
757
|
+
* @param eventId - Optional custom event ID (defaults to crypto.randomUUID())
|
|
758
|
+
* @param occurredOn - Optional timestamp (defaults to now)
|
|
759
|
+
*/
|
|
760
|
+
constructor(eventName, aggregateId, payload, eventId, occurredOn) {
|
|
761
|
+
this._eventId = eventId ?? crypto.randomUUID();
|
|
762
|
+
this._eventName = eventName;
|
|
763
|
+
this._aggregateId = aggregateId;
|
|
764
|
+
this._occurredOn = occurredOn ?? /* @__PURE__ */ new Date();
|
|
765
|
+
this._payload = _BaseDomainEvent.cloneAndFreeze(payload);
|
|
766
|
+
}
|
|
767
|
+
/**
|
|
768
|
+
* Unique identifier for this event instance.
|
|
769
|
+
*
|
|
770
|
+
* Useful for idempotency checks and event deduplication.
|
|
771
|
+
*/
|
|
772
|
+
get eventId() {
|
|
773
|
+
return this._eventId;
|
|
774
|
+
}
|
|
775
|
+
/**
|
|
776
|
+
* The name/type of this event.
|
|
777
|
+
*
|
|
778
|
+
* Used for routing events to appropriate handlers.
|
|
779
|
+
* Should be in PastTense format (e.g., 'OrderPlaced', 'UserRegistered').
|
|
780
|
+
*/
|
|
781
|
+
get eventName() {
|
|
782
|
+
return this._eventName;
|
|
783
|
+
}
|
|
784
|
+
/**
|
|
785
|
+
* The ID of the aggregate that raised this event.
|
|
786
|
+
*
|
|
787
|
+
* Useful for event sourcing and aggregate-specific event streams.
|
|
788
|
+
*/
|
|
789
|
+
get aggregateId() {
|
|
790
|
+
return this._aggregateId;
|
|
791
|
+
}
|
|
792
|
+
/**
|
|
793
|
+
* Timestamp when this event occurred.
|
|
794
|
+
*
|
|
795
|
+
* Represents the moment the domain action happened.
|
|
796
|
+
*/
|
|
797
|
+
get occurredOn() {
|
|
798
|
+
return this._occurredOn;
|
|
799
|
+
}
|
|
800
|
+
/**
|
|
801
|
+
* The event-specific data payload.
|
|
802
|
+
*
|
|
803
|
+
* Contains all information needed by event handlers.
|
|
804
|
+
*/
|
|
805
|
+
get payload() {
|
|
806
|
+
return this._payload;
|
|
807
|
+
}
|
|
808
|
+
/**
|
|
809
|
+
* Serializes the event to a plain object for persistence or messaging.
|
|
810
|
+
*
|
|
811
|
+
* @returns A plain object representation of the event
|
|
812
|
+
*
|
|
813
|
+
* @example
|
|
814
|
+
* ```typescript
|
|
815
|
+
* const event = new OrderPlacedEvent({ orderId: '123', ... });
|
|
816
|
+
* const serialized = event.toJSON();
|
|
817
|
+
* // {
|
|
818
|
+
* // eventId: 'uuid',
|
|
819
|
+
* // eventName: 'OrderPlaced',
|
|
820
|
+
* // aggregateId: '123',
|
|
821
|
+
* // occurredOn: '2024-01-15T10:30:00.000Z',
|
|
822
|
+
* // payload: { orderId: '123', ... }
|
|
823
|
+
* // }
|
|
824
|
+
* ```
|
|
825
|
+
*/
|
|
826
|
+
toJSON() {
|
|
827
|
+
return {
|
|
828
|
+
eventId: this._eventId,
|
|
829
|
+
eventName: this._eventName,
|
|
830
|
+
aggregateId: this._aggregateId,
|
|
831
|
+
occurredOn: this._occurredOn.toISOString(),
|
|
832
|
+
payload: this._payload
|
|
833
|
+
};
|
|
834
|
+
}
|
|
835
|
+
};
|
|
836
|
+
|
|
837
|
+
// src/backend/core/onion-layers/domain/classes/base-value-object.class.ts
|
|
838
|
+
var SKIP_VALUE_OBJECT_VALIDATION = "skip value object validation";
|
|
839
|
+
function deepEquals(a, b) {
|
|
840
|
+
if (a === b) return true;
|
|
841
|
+
if (a === null || a === void 0 || b === null || b === void 0) {
|
|
842
|
+
return a === b;
|
|
843
|
+
}
|
|
844
|
+
if (a instanceof Date && b instanceof Date) {
|
|
845
|
+
return a.getTime() === b.getTime();
|
|
846
|
+
}
|
|
847
|
+
if (Array.isArray(a) && Array.isArray(b)) {
|
|
848
|
+
if (a.length !== b.length) return false;
|
|
849
|
+
return a.every((item, index) => deepEquals(item, b[index]));
|
|
850
|
+
}
|
|
851
|
+
if (typeof a === "object" && typeof b === "object") {
|
|
852
|
+
const aObj = a;
|
|
853
|
+
const bObj = b;
|
|
854
|
+
const aKeys = Object.keys(aObj);
|
|
855
|
+
const bKeys = Object.keys(bObj);
|
|
856
|
+
if (aKeys.length !== bKeys.length) return false;
|
|
857
|
+
return aKeys.every((key) => deepEquals(aObj[key], bObj[key]));
|
|
858
|
+
}
|
|
859
|
+
return false;
|
|
860
|
+
}
|
|
861
|
+
var BaseValueObject = class {
|
|
862
|
+
_value;
|
|
863
|
+
/**
|
|
864
|
+
* Creates a new Value Object instance.
|
|
865
|
+
*
|
|
866
|
+
* @param value - The raw value to wrap
|
|
867
|
+
* @param validator - A bound validator or SKIP_VALUE_OBJECT_VALIDATION to bypass
|
|
868
|
+
* @throws {ObjectValidationError} When validation fails
|
|
869
|
+
*/
|
|
870
|
+
constructor(value, validator) {
|
|
871
|
+
this._value = validator === SKIP_VALUE_OBJECT_VALIDATION ? value : validator.validate(value);
|
|
872
|
+
}
|
|
873
|
+
/**
|
|
874
|
+
* Compares this Value Object with another for equality.
|
|
875
|
+
*
|
|
876
|
+
* Uses deep equality comparison to handle nested objects, arrays, and dates.
|
|
877
|
+
* Two Value Objects are equal if their underlying values are deeply equal.
|
|
878
|
+
*
|
|
879
|
+
* @param other - The Value Object to compare with
|
|
880
|
+
* @returns `true` if the values are deeply equal, `false` otherwise
|
|
881
|
+
*/
|
|
882
|
+
equals(other) {
|
|
883
|
+
if (this === other) return true;
|
|
884
|
+
return deepEquals(this.value, other.value);
|
|
885
|
+
}
|
|
886
|
+
/**
|
|
887
|
+
* The underlying immutable value.
|
|
888
|
+
*
|
|
889
|
+
* @returns The wrapped value of type T
|
|
890
|
+
*/
|
|
891
|
+
get value() {
|
|
892
|
+
return this._value;
|
|
893
|
+
}
|
|
894
|
+
};
|
|
895
|
+
|
|
896
|
+
// src/backend/core/onion-layers/domain/exceptions/invariant-violation.error.ts
|
|
897
|
+
var InvariantViolationError = class _InvariantViolationError extends DomainError {
|
|
898
|
+
/**
|
|
899
|
+
* Creates a new InvariantViolationError instance.
|
|
900
|
+
*
|
|
901
|
+
* @param options - Error configuration
|
|
902
|
+
* @param options.message - Description of the violated invariant
|
|
903
|
+
* @param options.code - Machine-readable error code (default: 'INVARIANT_VIOLATION')
|
|
904
|
+
* @param options.cause - Optional underlying error
|
|
905
|
+
*/
|
|
906
|
+
constructor({
|
|
907
|
+
message,
|
|
908
|
+
code = ErrorCodes.Domain.INVARIANT_VIOLATION,
|
|
909
|
+
cause
|
|
910
|
+
}) {
|
|
911
|
+
super({ message, code, cause });
|
|
912
|
+
}
|
|
913
|
+
/**
|
|
914
|
+
* Creates an InvariantViolationError from a caught error.
|
|
915
|
+
*
|
|
916
|
+
* @param cause - The original caught error
|
|
917
|
+
* @returns A new InvariantViolationError instance with the cause attached
|
|
918
|
+
*/
|
|
919
|
+
static fromError(cause) {
|
|
920
|
+
return new _InvariantViolationError({
|
|
921
|
+
message: cause instanceof Error ? cause.message : "Invariant violation",
|
|
922
|
+
cause
|
|
923
|
+
});
|
|
924
|
+
}
|
|
925
|
+
};
|
|
926
|
+
|
|
927
|
+
// src/backend/core/onion-layers/domain/exceptions/partial-load.error.ts
|
|
928
|
+
var PartialLoadError = class _PartialLoadError extends DomainError {
|
|
929
|
+
/**
|
|
930
|
+
* Creates a new PartialLoadError instance.
|
|
931
|
+
*
|
|
932
|
+
* @param options - Error configuration
|
|
933
|
+
* @param options.message - Description of what was not loaded
|
|
934
|
+
* @param options.code - Machine-readable error code (default: 'PARTIAL_LOAD')
|
|
935
|
+
* @param options.cause - Optional underlying error
|
|
936
|
+
*/
|
|
937
|
+
constructor({
|
|
938
|
+
message,
|
|
939
|
+
code = ErrorCodes.Domain.PARTIAL_LOAD,
|
|
940
|
+
cause
|
|
941
|
+
}) {
|
|
942
|
+
super({ message, code, cause });
|
|
943
|
+
}
|
|
944
|
+
/**
|
|
945
|
+
* Creates a PartialLoadError from a caught error.
|
|
946
|
+
*
|
|
947
|
+
* @param cause - The original caught error
|
|
948
|
+
* @returns A new PartialLoadError instance with the cause attached
|
|
949
|
+
*/
|
|
950
|
+
static fromError(cause) {
|
|
951
|
+
return new _PartialLoadError({
|
|
952
|
+
message: cause instanceof Error ? cause.message : "Partial load error",
|
|
953
|
+
cause
|
|
954
|
+
});
|
|
955
|
+
}
|
|
956
|
+
};
|
|
957
|
+
|
|
958
|
+
// src/backend/core/onion-layers/domain/value-objects/base-audit-by.vo.ts
|
|
959
|
+
var BaseAuditByVo = class extends BaseValueObject {
|
|
960
|
+
/**
|
|
961
|
+
* Creates a new BaseAuditByVo instance.
|
|
962
|
+
*
|
|
963
|
+
* @param value - The user tracking values
|
|
964
|
+
* @param value.createdBy - User who created the entity (optional for system ops)
|
|
965
|
+
* @param value.updatedBy - User who last updated the entity (optional)
|
|
966
|
+
* @param validator - Bound validator or skip validation symbol
|
|
967
|
+
*/
|
|
968
|
+
constructor(value, validator) {
|
|
969
|
+
super(value, validator);
|
|
970
|
+
}
|
|
971
|
+
/**
|
|
972
|
+
* The user ID who created the entity.
|
|
973
|
+
* Returns `undefined` for system-created entities.
|
|
974
|
+
*/
|
|
975
|
+
get createdBy() {
|
|
976
|
+
return this.value.createdBy;
|
|
977
|
+
}
|
|
978
|
+
/**
|
|
979
|
+
* The user ID who last updated the entity.
|
|
980
|
+
* Returns `undefined` for system-updated entities.
|
|
981
|
+
*/
|
|
982
|
+
get updatedBy() {
|
|
983
|
+
return this.value.updatedBy;
|
|
984
|
+
}
|
|
985
|
+
};
|
|
986
|
+
|
|
987
|
+
// src/backend/core/onion-layers/domain/value-objects/base-audit-info.vo.ts
|
|
988
|
+
var BaseAuditInfoVo = class extends BaseValueObject {
|
|
989
|
+
/**
|
|
990
|
+
* Creates a new BaseAuditInfoVo instance.
|
|
991
|
+
*
|
|
992
|
+
* @param value - Composite value containing audit by and on VOs
|
|
993
|
+
* @param value.by - User tracking value object
|
|
994
|
+
* @param value.on - Timestamp tracking value object
|
|
995
|
+
* @param validator - Bound validator or skip validation symbol
|
|
996
|
+
*/
|
|
997
|
+
constructor(value, validator) {
|
|
998
|
+
super(value, validator);
|
|
999
|
+
}
|
|
1000
|
+
/**
|
|
1001
|
+
* The user ID who created the entity.
|
|
1002
|
+
* Returns `undefined` for system-created entities.
|
|
1003
|
+
*/
|
|
1004
|
+
get createdBy() {
|
|
1005
|
+
return this.value.by.createdBy;
|
|
1006
|
+
}
|
|
1007
|
+
/**
|
|
1008
|
+
* The timestamp when the entity was created.
|
|
1009
|
+
* Returns a cloned Date to prevent mutation.
|
|
1010
|
+
*/
|
|
1011
|
+
get createdAt() {
|
|
1012
|
+
return new Date(this.value.on.createdAt.getTime());
|
|
1013
|
+
}
|
|
1014
|
+
/**
|
|
1015
|
+
* The user ID who last updated the entity.
|
|
1016
|
+
* Returns `undefined` for system-updated entities.
|
|
1017
|
+
*/
|
|
1018
|
+
get updatedBy() {
|
|
1019
|
+
return this.value.by.updatedBy;
|
|
1020
|
+
}
|
|
1021
|
+
/**
|
|
1022
|
+
* The timestamp when the entity was last updated.
|
|
1023
|
+
* Returns a cloned Date to prevent mutation.
|
|
1024
|
+
*/
|
|
1025
|
+
get updatedAt() {
|
|
1026
|
+
return new Date(this.value.on.updatedAt.getTime());
|
|
1027
|
+
}
|
|
1028
|
+
/**
|
|
1029
|
+
* Whether the entity has been modified since creation.
|
|
1030
|
+
*
|
|
1031
|
+
* Compares both timestamps and user IDs. Returns `true` if either:
|
|
1032
|
+
* - The updatedAt timestamp differs from createdAt
|
|
1033
|
+
* - The updatedBy user differs from createdBy
|
|
1034
|
+
*
|
|
1035
|
+
* Note: When both createdBy and updatedBy are undefined (system-created
|
|
1036
|
+
* entities), this correctly returns false for the user comparison.
|
|
1037
|
+
*/
|
|
1038
|
+
get isModified() {
|
|
1039
|
+
const timestampChanged = this.updatedAt.getTime() !== this.createdAt.getTime();
|
|
1040
|
+
const userChanged = this.updatedBy?.value !== this.createdBy?.value;
|
|
1041
|
+
return timestampChanged || userChanged;
|
|
1042
|
+
}
|
|
1043
|
+
/**
|
|
1044
|
+
* Alias for `updatedBy` for semantic clarity.
|
|
1045
|
+
*/
|
|
1046
|
+
get lastModifiedBy() {
|
|
1047
|
+
return this.updatedBy;
|
|
1048
|
+
}
|
|
1049
|
+
/**
|
|
1050
|
+
* Alias for `updatedAt` for semantic clarity.
|
|
1051
|
+
*/
|
|
1052
|
+
get lastModifiedAt() {
|
|
1053
|
+
return this.updatedAt;
|
|
1054
|
+
}
|
|
1055
|
+
};
|
|
1056
|
+
|
|
1057
|
+
// src/backend/core/onion-layers/domain/value-objects/base-audit-on.vo.ts
|
|
1058
|
+
var BaseAuditOnVo = class extends BaseValueObject {
|
|
1059
|
+
/**
|
|
1060
|
+
* Creates a new BaseAuditOnVo instance.
|
|
1061
|
+
*
|
|
1062
|
+
* @param value - The timestamp values
|
|
1063
|
+
* @param value.createdAt - When the entity was created
|
|
1064
|
+
* @param value.updatedAt - When the entity was last updated
|
|
1065
|
+
* @param validator - Bound validator or skip validation symbol
|
|
1066
|
+
* @throws {InvariantViolationError} When `updatedAt < createdAt`
|
|
1067
|
+
*/
|
|
1068
|
+
constructor(value, validator) {
|
|
1069
|
+
if (value.updatedAt < value.createdAt) {
|
|
1070
|
+
throw new InvariantViolationError({
|
|
1071
|
+
message: "UpdatedAt cannot be earlier than createdAt",
|
|
1072
|
+
code: "INVALID_AUDIT_TIMESTAMPS"
|
|
1073
|
+
});
|
|
1074
|
+
}
|
|
1075
|
+
super(value, validator);
|
|
1076
|
+
}
|
|
1077
|
+
/**
|
|
1078
|
+
* When the entity was created.
|
|
1079
|
+
* Returns a cloned Date to prevent mutation.
|
|
1080
|
+
*/
|
|
1081
|
+
get createdAt() {
|
|
1082
|
+
return new Date(this.value.createdAt);
|
|
1083
|
+
}
|
|
1084
|
+
/**
|
|
1085
|
+
* When the entity was last updated.
|
|
1086
|
+
* Returns a cloned Date to prevent mutation.
|
|
1087
|
+
*/
|
|
1088
|
+
get updatedAt() {
|
|
1089
|
+
return new Date(this.value.updatedAt);
|
|
1090
|
+
}
|
|
1091
|
+
};
|
|
1092
|
+
|
|
1093
|
+
// src/backend/core/onion-layers/domain/value-objects/base-email.vo.ts
|
|
1094
|
+
var BaseEmailVo = class extends BaseValueObject {
|
|
1095
|
+
/**
|
|
1096
|
+
* Creates a new BaseEmailVo instance.
|
|
1097
|
+
*
|
|
1098
|
+
* @param value - The email address string
|
|
1099
|
+
* @param validator - Bound validator or skip validation symbol
|
|
1100
|
+
*/
|
|
1101
|
+
constructor(value, validator) {
|
|
1102
|
+
super(value, validator);
|
|
1103
|
+
}
|
|
1104
|
+
};
|
|
1105
|
+
|
|
1106
|
+
// src/backend/core/onion-layers/domain/value-objects/base-long-text.vo.ts
|
|
1107
|
+
var BaseLongTextVo = class extends BaseValueObject {
|
|
1108
|
+
/**
|
|
1109
|
+
* Creates a new BaseLongTextVo instance.
|
|
1110
|
+
*
|
|
1111
|
+
* @param value - The long text string
|
|
1112
|
+
* @param validator - Bound validator or skip validation symbol
|
|
1113
|
+
*/
|
|
1114
|
+
constructor(value, validator) {
|
|
1115
|
+
super(value, validator);
|
|
1116
|
+
}
|
|
1117
|
+
};
|
|
1118
|
+
|
|
1119
|
+
// src/backend/core/onion-layers/domain/value-objects/base-medium-text.vo.ts
|
|
1120
|
+
var BaseMediumTextVo = class extends BaseValueObject {
|
|
1121
|
+
/**
|
|
1122
|
+
* Creates a new BaseMediumTextVo instance.
|
|
1123
|
+
*
|
|
1124
|
+
* @param value - The medium text string
|
|
1125
|
+
* @param validator - Bound validator or skip validation symbol
|
|
1126
|
+
*/
|
|
1127
|
+
constructor(value, validator) {
|
|
1128
|
+
super(value, validator);
|
|
1129
|
+
}
|
|
1130
|
+
};
|
|
1131
|
+
|
|
1132
|
+
// src/backend/core/onion-layers/domain/value-objects/base-pagination.vo.ts
|
|
1133
|
+
var BasePaginationVo = class extends BaseValueObject {
|
|
1134
|
+
/**
|
|
1135
|
+
* Creates a new BasePaginationVo instance.
|
|
1136
|
+
*
|
|
1137
|
+
* @param value - The pagination parameters
|
|
1138
|
+
* @param value.page - The page number (typically 1-indexed)
|
|
1139
|
+
* @param value.pageSize - The number of items per page
|
|
1140
|
+
* @param validator - Bound validator or skip validation symbol
|
|
1141
|
+
*/
|
|
1142
|
+
constructor(value, validator) {
|
|
1143
|
+
super(value, validator);
|
|
1144
|
+
}
|
|
1145
|
+
/**
|
|
1146
|
+
* The current page number.
|
|
1147
|
+
*/
|
|
1148
|
+
get page() {
|
|
1149
|
+
return this.value.page;
|
|
1150
|
+
}
|
|
1151
|
+
/**
|
|
1152
|
+
* The number of items per page.
|
|
1153
|
+
*/
|
|
1154
|
+
get pageSize() {
|
|
1155
|
+
return this.value.pageSize;
|
|
1156
|
+
}
|
|
1157
|
+
};
|
|
1158
|
+
|
|
1159
|
+
// src/backend/core/onion-layers/domain/value-objects/base-short-text.vo.ts
|
|
1160
|
+
var BaseShortTextVo = class extends BaseValueObject {
|
|
1161
|
+
/**
|
|
1162
|
+
* Creates a new BaseShortTextVo instance.
|
|
1163
|
+
*
|
|
1164
|
+
* @param value - The short text string
|
|
1165
|
+
* @param validator - Bound validator or skip validation symbol
|
|
1166
|
+
*/
|
|
1167
|
+
constructor(value, validator) {
|
|
1168
|
+
super(value, validator);
|
|
1169
|
+
}
|
|
1170
|
+
};
|
|
1171
|
+
|
|
1172
|
+
// src/backend/core/onion-layers/domain/value-objects/base-uuid-v4.vo.ts
|
|
1173
|
+
var import_uuid = require("uuid");
|
|
1174
|
+
var BaseUuidV4Vo = class extends BaseValueObject {
|
|
1175
|
+
/**
|
|
1176
|
+
* Creates a new BaseUuidV4Vo instance.
|
|
1177
|
+
*
|
|
1178
|
+
* @param value - The UUID v4 string value
|
|
1179
|
+
* @param validator - Bound validator or skip validation symbol
|
|
1180
|
+
*/
|
|
1181
|
+
constructor(value, validator) {
|
|
1182
|
+
super(value, validator);
|
|
1183
|
+
}
|
|
1184
|
+
/**
|
|
1185
|
+
* Generates a new UUID v4 value object.
|
|
1186
|
+
*
|
|
1187
|
+
* Creates a random UUID, skipping validation since the
|
|
1188
|
+
* `uuid` library guarantees format.
|
|
1189
|
+
*
|
|
1190
|
+
* @returns A new BaseUuidV4Vo with a freshly generated UUID
|
|
1191
|
+
*/
|
|
1192
|
+
static generate() {
|
|
1193
|
+
return new this((0, import_uuid.v4)(), SKIP_VALUE_OBJECT_VALIDATION);
|
|
1194
|
+
}
|
|
1195
|
+
/**
|
|
1196
|
+
* Creates a UUID v4 value object from an existing string.
|
|
1197
|
+
*
|
|
1198
|
+
* **Important:** This base implementation skips validation and accepts
|
|
1199
|
+
* any string value. Subclasses should override this method with a
|
|
1200
|
+
* validator to ensure UUID format correctness.
|
|
1201
|
+
*
|
|
1202
|
+
* @param value - The UUID v4 string value (not validated at base level)
|
|
1203
|
+
* @returns A new BaseUuidV4Vo with the provided value
|
|
1204
|
+
*
|
|
1205
|
+
* @example Subclass with validation (recommended)
|
|
1206
|
+
* ```typescript
|
|
1207
|
+
* class UserId extends BaseUuidV4Vo {
|
|
1208
|
+
* static override create(value: string): UserId {
|
|
1209
|
+
* return new UserId(value, uuidV4Validator);
|
|
1210
|
+
* }
|
|
1211
|
+
* }
|
|
1212
|
+
* ```
|
|
1213
|
+
*
|
|
1214
|
+
* @see generate - For creating new UUIDs (always valid)
|
|
1215
|
+
*/
|
|
1216
|
+
static create(value) {
|
|
1217
|
+
return new this(value, SKIP_VALUE_OBJECT_VALIDATION);
|
|
1218
|
+
}
|
|
1219
|
+
};
|
|
1220
|
+
|
|
1221
|
+
// src/backend/core/onion-layers/domain/value-objects/base-uuid-v7.vo.ts
|
|
1222
|
+
var import_uuid2 = require("uuid");
|
|
1223
|
+
var BaseUuidV7Vo = class extends BaseValueObject {
|
|
1224
|
+
/**
|
|
1225
|
+
* Creates a new BaseUuidV7Vo instance.
|
|
1226
|
+
*
|
|
1227
|
+
* @param value - The UUID v7 string value
|
|
1228
|
+
* @param validator - Bound validator or skip validation symbol
|
|
1229
|
+
*/
|
|
1230
|
+
constructor(value, validator) {
|
|
1231
|
+
super(value, validator);
|
|
1232
|
+
}
|
|
1233
|
+
/**
|
|
1234
|
+
* Generates a new UUID v7 value object.
|
|
1235
|
+
*
|
|
1236
|
+
* Creates a time-ordered UUID using the current timestamp,
|
|
1237
|
+
* skipping validation since the `uuid` library guarantees format.
|
|
1238
|
+
*
|
|
1239
|
+
* @returns A new BaseUuidV7Vo with a freshly generated UUID
|
|
1240
|
+
*/
|
|
1241
|
+
static generate() {
|
|
1242
|
+
return new this((0, import_uuid2.v7)(), SKIP_VALUE_OBJECT_VALIDATION);
|
|
1243
|
+
}
|
|
1244
|
+
/**
|
|
1245
|
+
* Creates a UUID v7 value object from an existing string.
|
|
1246
|
+
*
|
|
1247
|
+
* **Important:** This base implementation skips validation and accepts
|
|
1248
|
+
* any string value. Subclasses should override this method with a
|
|
1249
|
+
* validator to ensure UUID format correctness.
|
|
1250
|
+
*
|
|
1251
|
+
* @param value - The UUID v7 string value (not validated at base level)
|
|
1252
|
+
* @returns A new BaseUuidV7Vo with the provided value
|
|
1253
|
+
*
|
|
1254
|
+
* @example Subclass with validation (recommended)
|
|
1255
|
+
* ```typescript
|
|
1256
|
+
* class OrderId extends BaseUuidV7Vo {
|
|
1257
|
+
* static override create(value: string): OrderId {
|
|
1258
|
+
* return new OrderId(value, uuidV7Validator);
|
|
1259
|
+
* }
|
|
1260
|
+
* }
|
|
1261
|
+
* ```
|
|
1262
|
+
*
|
|
1263
|
+
* @see generate - For creating new UUIDs (always valid)
|
|
1264
|
+
*/
|
|
1265
|
+
static create(value) {
|
|
1266
|
+
return new this(value, SKIP_VALUE_OBJECT_VALIDATION);
|
|
1267
|
+
}
|
|
1268
|
+
};
|
|
1269
|
+
|
|
1270
|
+
// src/backend/core/onion-layers/domain/example-domain/value-objects/money.vo.ts
|
|
1271
|
+
var Money = class _Money extends BaseValueObject {
|
|
1272
|
+
/**
|
|
1273
|
+
* Creates a Money instance with USD currency.
|
|
1274
|
+
*
|
|
1275
|
+
* @param amount - The monetary amount
|
|
1276
|
+
*/
|
|
1277
|
+
static usd(amount) {
|
|
1278
|
+
return new _Money({ amount, currency: "USD" }, SKIP_VALUE_OBJECT_VALIDATION);
|
|
1279
|
+
}
|
|
1280
|
+
/**
|
|
1281
|
+
* Creates a Money instance with EUR currency.
|
|
1282
|
+
*
|
|
1283
|
+
* @param amount - The monetary amount
|
|
1284
|
+
*/
|
|
1285
|
+
static eur(amount) {
|
|
1286
|
+
return new _Money({ amount, currency: "EUR" }, SKIP_VALUE_OBJECT_VALIDATION);
|
|
1287
|
+
}
|
|
1288
|
+
/**
|
|
1289
|
+
* Creates a zero amount in the specified currency.
|
|
1290
|
+
*
|
|
1291
|
+
* @param currency - The currency code (default: 'USD')
|
|
1292
|
+
*/
|
|
1293
|
+
static zero(currency = "USD") {
|
|
1294
|
+
return new _Money({ amount: 0, currency }, SKIP_VALUE_OBJECT_VALIDATION);
|
|
1295
|
+
}
|
|
1296
|
+
/**
|
|
1297
|
+
* Reconstitutes a Money from a persisted value.
|
|
1298
|
+
*
|
|
1299
|
+
* @param value - The money value from persistence
|
|
1300
|
+
*/
|
|
1301
|
+
static fromPersistence(value) {
|
|
1302
|
+
return new _Money(value, SKIP_VALUE_OBJECT_VALIDATION);
|
|
1303
|
+
}
|
|
1304
|
+
/**
|
|
1305
|
+
* The monetary amount.
|
|
1306
|
+
*/
|
|
1307
|
+
get amount() {
|
|
1308
|
+
return this.value.amount;
|
|
1309
|
+
}
|
|
1310
|
+
/**
|
|
1311
|
+
* The currency code.
|
|
1312
|
+
*/
|
|
1313
|
+
get currency() {
|
|
1314
|
+
return this.value.currency;
|
|
1315
|
+
}
|
|
1316
|
+
/**
|
|
1317
|
+
* Adds another Money value to this one.
|
|
1318
|
+
*
|
|
1319
|
+
* @param other - The Money to add
|
|
1320
|
+
* @throws {InvariantViolationError} If currencies don't match
|
|
1321
|
+
*/
|
|
1322
|
+
add(other) {
|
|
1323
|
+
this.assertSameCurrency(other);
|
|
1324
|
+
return new _Money(
|
|
1325
|
+
{ amount: this.amount + other.amount, currency: this.currency },
|
|
1326
|
+
SKIP_VALUE_OBJECT_VALIDATION
|
|
1327
|
+
);
|
|
1328
|
+
}
|
|
1329
|
+
/**
|
|
1330
|
+
* Subtracts another Money value from this one.
|
|
1331
|
+
*
|
|
1332
|
+
* @param other - The Money to subtract
|
|
1333
|
+
* @throws {InvariantViolationError} If currencies don't match
|
|
1334
|
+
*/
|
|
1335
|
+
subtract(other) {
|
|
1336
|
+
this.assertSameCurrency(other);
|
|
1337
|
+
return new _Money(
|
|
1338
|
+
{ amount: this.amount - other.amount, currency: this.currency },
|
|
1339
|
+
SKIP_VALUE_OBJECT_VALIDATION
|
|
1340
|
+
);
|
|
1341
|
+
}
|
|
1342
|
+
/**
|
|
1343
|
+
* Multiplies this Money by a factor.
|
|
1344
|
+
*
|
|
1345
|
+
* @param factor - The multiplication factor
|
|
1346
|
+
*/
|
|
1347
|
+
multiply(factor) {
|
|
1348
|
+
return new _Money(
|
|
1349
|
+
{ amount: this.amount * factor, currency: this.currency },
|
|
1350
|
+
SKIP_VALUE_OBJECT_VALIDATION
|
|
1351
|
+
);
|
|
1352
|
+
}
|
|
1353
|
+
/**
|
|
1354
|
+
* Checks if this Money is greater than another.
|
|
1355
|
+
*
|
|
1356
|
+
* @param other - The Money to compare with
|
|
1357
|
+
* @throws {InvariantViolationError} If currencies don't match
|
|
1358
|
+
*/
|
|
1359
|
+
isGreaterThan(other) {
|
|
1360
|
+
this.assertSameCurrency(other);
|
|
1361
|
+
return this.amount > other.amount;
|
|
1362
|
+
}
|
|
1363
|
+
/**
|
|
1364
|
+
* Checks if this Money is less than another.
|
|
1365
|
+
*
|
|
1366
|
+
* @param other - The Money to compare with
|
|
1367
|
+
* @throws {InvariantViolationError} If currencies don't match
|
|
1368
|
+
*/
|
|
1369
|
+
isLessThan(other) {
|
|
1370
|
+
this.assertSameCurrency(other);
|
|
1371
|
+
return this.amount < other.amount;
|
|
1372
|
+
}
|
|
1373
|
+
/**
|
|
1374
|
+
* Checks if this Money represents zero.
|
|
1375
|
+
*/
|
|
1376
|
+
isZero() {
|
|
1377
|
+
return this.amount === 0;
|
|
1378
|
+
}
|
|
1379
|
+
/**
|
|
1380
|
+
* Asserts that two Money values have the same currency.
|
|
1381
|
+
* @internal
|
|
1382
|
+
*/
|
|
1383
|
+
assertSameCurrency(other) {
|
|
1384
|
+
if (this.currency !== other.currency) {
|
|
1385
|
+
throw new InvariantViolationError({
|
|
1386
|
+
message: `Cannot operate on different currencies: ${this.currency} vs ${other.currency}`,
|
|
1387
|
+
code: "CURRENCY_MISMATCH"
|
|
1388
|
+
});
|
|
1389
|
+
}
|
|
1390
|
+
}
|
|
1391
|
+
};
|
|
1392
|
+
|
|
1393
|
+
// src/backend/core/onion-layers/domain/example-domain/value-objects/order-id.vo.ts
|
|
1394
|
+
var OrderId = class extends BaseUuidV7Vo {
|
|
1395
|
+
};
|
|
1396
|
+
|
|
1397
|
+
// src/backend/core/onion-layers/domain/example-domain/value-objects/order-status.vo.ts
|
|
1398
|
+
var OrderStatus = class _OrderStatus extends BaseValueObject {
|
|
1399
|
+
/**
|
|
1400
|
+
* Creates a new OrderStatus with 'pending' value.
|
|
1401
|
+
* Use when creating new orders.
|
|
1402
|
+
*/
|
|
1403
|
+
static pending() {
|
|
1404
|
+
return new _OrderStatus("pending", SKIP_VALUE_OBJECT_VALIDATION);
|
|
1405
|
+
}
|
|
1406
|
+
/**
|
|
1407
|
+
* Creates a new OrderStatus with 'confirmed' value.
|
|
1408
|
+
* Use when payment is received.
|
|
1409
|
+
*/
|
|
1410
|
+
static confirmed() {
|
|
1411
|
+
return new _OrderStatus("confirmed", SKIP_VALUE_OBJECT_VALIDATION);
|
|
1412
|
+
}
|
|
1413
|
+
/**
|
|
1414
|
+
* Creates a new OrderStatus with 'shipped' value.
|
|
1415
|
+
* Use when order is dispatched.
|
|
1416
|
+
*/
|
|
1417
|
+
static shipped() {
|
|
1418
|
+
return new _OrderStatus("shipped", SKIP_VALUE_OBJECT_VALIDATION);
|
|
1419
|
+
}
|
|
1420
|
+
/**
|
|
1421
|
+
* Creates a new OrderStatus with 'cancelled' value.
|
|
1422
|
+
* Use when order is cancelled by customer or system.
|
|
1423
|
+
*/
|
|
1424
|
+
static cancelled() {
|
|
1425
|
+
return new _OrderStatus("cancelled", SKIP_VALUE_OBJECT_VALIDATION);
|
|
1426
|
+
}
|
|
1427
|
+
/**
|
|
1428
|
+
* Reconstitutes an OrderStatus from a persisted value.
|
|
1429
|
+
*
|
|
1430
|
+
* @param value - The status value from persistence
|
|
1431
|
+
*/
|
|
1432
|
+
static fromPersistence(value) {
|
|
1433
|
+
return new _OrderStatus(value, SKIP_VALUE_OBJECT_VALIDATION);
|
|
1434
|
+
}
|
|
1435
|
+
/**
|
|
1436
|
+
* Checks if the order is in pending status.
|
|
1437
|
+
*/
|
|
1438
|
+
isPending() {
|
|
1439
|
+
return this.value === "pending";
|
|
1440
|
+
}
|
|
1441
|
+
/**
|
|
1442
|
+
* Checks if the order is confirmed.
|
|
1443
|
+
*/
|
|
1444
|
+
isConfirmed() {
|
|
1445
|
+
return this.value === "confirmed";
|
|
1446
|
+
}
|
|
1447
|
+
/**
|
|
1448
|
+
* Checks if the order has been shipped.
|
|
1449
|
+
*/
|
|
1450
|
+
isShipped() {
|
|
1451
|
+
return this.value === "shipped";
|
|
1452
|
+
}
|
|
1453
|
+
/**
|
|
1454
|
+
* Checks if the order has been cancelled.
|
|
1455
|
+
*/
|
|
1456
|
+
isCancelled() {
|
|
1457
|
+
return this.value === "cancelled";
|
|
1458
|
+
}
|
|
1459
|
+
/**
|
|
1460
|
+
* Checks if the order can still be modified (pending or confirmed).
|
|
1461
|
+
*/
|
|
1462
|
+
isModifiable() {
|
|
1463
|
+
return this.isPending() || this.isConfirmed();
|
|
1464
|
+
}
|
|
1465
|
+
};
|
|
1466
|
+
|
|
1467
|
+
// src/backend/core/onion-layers/domain/example-domain/events/order-cancelled.event.ts
|
|
1468
|
+
var OrderCancelledEvent = class extends BaseDomainEvent {
|
|
1469
|
+
constructor(payload) {
|
|
1470
|
+
super("OrderCancelled", payload.orderId, payload);
|
|
1471
|
+
}
|
|
1472
|
+
};
|
|
1473
|
+
|
|
1474
|
+
// src/backend/core/onion-layers/domain/example-domain/events/order-placed.event.ts
|
|
1475
|
+
var OrderPlacedEvent = class extends BaseDomainEvent {
|
|
1476
|
+
constructor(payload) {
|
|
1477
|
+
super("OrderPlaced", payload.orderId, payload);
|
|
1478
|
+
}
|
|
1479
|
+
};
|
|
1480
|
+
|
|
1481
|
+
// src/backend/core/onion-layers/domain/example-domain/aggregates/order/policies/value/default-order-status.policy.ts
|
|
1482
|
+
var defaultOrderStatus = () => {
|
|
1483
|
+
return OrderStatus.pending();
|
|
1484
|
+
};
|
|
1485
|
+
|
|
1486
|
+
// src/backend/core/onion-layers/domain/example-domain/aggregates/order/policies/business/can-add-order-item.policy.ts
|
|
1487
|
+
var canAddOrderItem = (order) => {
|
|
1488
|
+
return order.status.isPending();
|
|
1489
|
+
};
|
|
1490
|
+
|
|
1491
|
+
// src/backend/core/onion-layers/domain/example-domain/aggregates/order/policies/business/can-cancel-order.policy.ts
|
|
1492
|
+
var canCancelOrder = (order) => {
|
|
1493
|
+
return order.status.isPending() || order.status.isConfirmed();
|
|
1494
|
+
};
|
|
1495
|
+
|
|
1496
|
+
// src/backend/core/onion-layers/domain/example-domain/aggregates/order/order.aggregate.ts
|
|
1497
|
+
var Order = class _Order extends BaseAggregateRoot {
|
|
1498
|
+
constructor(id, props, version) {
|
|
1499
|
+
super(id, props, version);
|
|
1500
|
+
}
|
|
1501
|
+
/**
|
|
1502
|
+
* Creates a new Order.
|
|
1503
|
+
*
|
|
1504
|
+
* @param customerId - The customer placing the order
|
|
1505
|
+
* @param items - Initial order items
|
|
1506
|
+
* @returns A new Order instance with OrderPlacedEvent raised
|
|
1507
|
+
*/
|
|
1508
|
+
static create(customerId, items) {
|
|
1509
|
+
const id = OrderId.generate();
|
|
1510
|
+
const totalAmount = items.reduce((sum, item) => sum.add(item.totalPrice), Money.zero());
|
|
1511
|
+
const order = new _Order(id, {
|
|
1512
|
+
customerId,
|
|
1513
|
+
items,
|
|
1514
|
+
status: defaultOrderStatus(),
|
|
1515
|
+
totalAmount,
|
|
1516
|
+
placedAt: /* @__PURE__ */ new Date()
|
|
1517
|
+
});
|
|
1518
|
+
order.addDomainEvent(
|
|
1519
|
+
new OrderPlacedEvent({
|
|
1520
|
+
orderId: id.value,
|
|
1521
|
+
customerId,
|
|
1522
|
+
itemCount: items.length,
|
|
1523
|
+
totalAmount: totalAmount.amount,
|
|
1524
|
+
currency: totalAmount.currency,
|
|
1525
|
+
placedAt: order.placedAt.toISOString()
|
|
1526
|
+
})
|
|
1527
|
+
);
|
|
1528
|
+
return order;
|
|
1529
|
+
}
|
|
1530
|
+
/**
|
|
1531
|
+
* Reconstitutes an Order from persistence.
|
|
1532
|
+
*
|
|
1533
|
+
* @param id - The order ID
|
|
1534
|
+
* @param props - The order properties
|
|
1535
|
+
* @param version - The version for optimistic locking
|
|
1536
|
+
*/
|
|
1537
|
+
static fromPersistence(id, props, version) {
|
|
1538
|
+
return new _Order(id, props, version);
|
|
1539
|
+
}
|
|
1540
|
+
get customerId() {
|
|
1541
|
+
return this.props.customerId;
|
|
1542
|
+
}
|
|
1543
|
+
get items() {
|
|
1544
|
+
return this.props.items;
|
|
1545
|
+
}
|
|
1546
|
+
get status() {
|
|
1547
|
+
return this.props.status;
|
|
1548
|
+
}
|
|
1549
|
+
get totalAmount() {
|
|
1550
|
+
return this.props.totalAmount;
|
|
1551
|
+
}
|
|
1552
|
+
get placedAt() {
|
|
1553
|
+
return this.props.placedAt;
|
|
1554
|
+
}
|
|
1555
|
+
/**
|
|
1556
|
+
* Adds an item to the order.
|
|
1557
|
+
*
|
|
1558
|
+
* Uses the `canAddOrderItem` business policy to check if the operation is allowed.
|
|
1559
|
+
*
|
|
1560
|
+
* @param item - The item to add
|
|
1561
|
+
* @throws {InvariantViolationError} If the order is not in pending status
|
|
1562
|
+
*/
|
|
1563
|
+
addItem(item) {
|
|
1564
|
+
if (!canAddOrderItem(this)) {
|
|
1565
|
+
throw new InvariantViolationError({
|
|
1566
|
+
message: "Cannot add items to non-pending order",
|
|
1567
|
+
code: "ORDER_NOT_PENDING"
|
|
1568
|
+
});
|
|
1569
|
+
}
|
|
1570
|
+
this._props.items.push(item);
|
|
1571
|
+
this._props.totalAmount = this._props.totalAmount.add(item.totalPrice);
|
|
1572
|
+
}
|
|
1573
|
+
/**
|
|
1574
|
+
* Confirms the order (e.g., after payment received).
|
|
1575
|
+
*
|
|
1576
|
+
* @throws {InvariantViolationError} If the order is not in pending status
|
|
1577
|
+
*/
|
|
1578
|
+
confirm() {
|
|
1579
|
+
if (!this.status.isPending()) {
|
|
1580
|
+
throw new InvariantViolationError({
|
|
1581
|
+
message: "Only pending orders can be confirmed",
|
|
1582
|
+
code: "ORDER_NOT_PENDING"
|
|
1583
|
+
});
|
|
1584
|
+
}
|
|
1585
|
+
this._props.status = OrderStatus.confirmed();
|
|
1586
|
+
}
|
|
1587
|
+
/**
|
|
1588
|
+
* Marks the order as shipped.
|
|
1589
|
+
*
|
|
1590
|
+
* @throws {InvariantViolationError} If the order is not confirmed
|
|
1591
|
+
*/
|
|
1592
|
+
ship() {
|
|
1593
|
+
if (!this.status.isConfirmed()) {
|
|
1594
|
+
throw new InvariantViolationError({
|
|
1595
|
+
message: "Only confirmed orders can be shipped",
|
|
1596
|
+
code: "ORDER_NOT_CONFIRMED"
|
|
1597
|
+
});
|
|
1598
|
+
}
|
|
1599
|
+
this._props.status = OrderStatus.shipped();
|
|
1600
|
+
}
|
|
1601
|
+
/**
|
|
1602
|
+
* Cancels the order.
|
|
1603
|
+
*
|
|
1604
|
+
* Uses the `canCancelOrder` business policy to check if the operation is allowed.
|
|
1605
|
+
*
|
|
1606
|
+
* @param reason - The reason for cancellation
|
|
1607
|
+
* @throws {InvariantViolationError} If the order cannot be cancelled
|
|
1608
|
+
*/
|
|
1609
|
+
cancel(reason) {
|
|
1610
|
+
if (!canCancelOrder(this)) {
|
|
1611
|
+
throw new InvariantViolationError({
|
|
1612
|
+
message: "Order cannot be cancelled - already shipped or cancelled",
|
|
1613
|
+
code: "ORDER_CANNOT_CANCEL"
|
|
1614
|
+
});
|
|
1615
|
+
}
|
|
1616
|
+
this._props.status = OrderStatus.cancelled();
|
|
1617
|
+
this.addDomainEvent(
|
|
1618
|
+
new OrderCancelledEvent({
|
|
1619
|
+
orderId: this.id.value,
|
|
1620
|
+
reason,
|
|
1621
|
+
cancelledAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1622
|
+
})
|
|
1623
|
+
);
|
|
1624
|
+
}
|
|
1625
|
+
};
|
|
1626
|
+
|
|
1627
|
+
// src/backend/core/onion-layers/domain/example-domain/entities/order-item-id.vo.ts
|
|
1628
|
+
var OrderItemId = class extends BaseUuidV7Vo {
|
|
1629
|
+
};
|
|
1630
|
+
|
|
1631
|
+
// src/backend/core/onion-layers/domain/example-domain/entities/order-item.entity.ts
|
|
1632
|
+
var OrderItem = class _OrderItem extends BaseEntity {
|
|
1633
|
+
constructor(id, props) {
|
|
1634
|
+
super(id, props);
|
|
1635
|
+
}
|
|
1636
|
+
/**
|
|
1637
|
+
* Creates a new OrderItem.
|
|
1638
|
+
*/
|
|
1639
|
+
static create(props) {
|
|
1640
|
+
return new _OrderItem(OrderItemId.generate(), props);
|
|
1641
|
+
}
|
|
1642
|
+
/**
|
|
1643
|
+
* Reconstitutes an OrderItem from persistence.
|
|
1644
|
+
*/
|
|
1645
|
+
static fromPersistence(id, props) {
|
|
1646
|
+
return new _OrderItem(id, props);
|
|
1647
|
+
}
|
|
1648
|
+
get productId() {
|
|
1649
|
+
return this.props.productId;
|
|
1650
|
+
}
|
|
1651
|
+
get productName() {
|
|
1652
|
+
return this.props.productName;
|
|
1653
|
+
}
|
|
1654
|
+
get quantity() {
|
|
1655
|
+
return this.props.quantity;
|
|
1656
|
+
}
|
|
1657
|
+
get unitPrice() {
|
|
1658
|
+
return this.props.unitPrice;
|
|
1659
|
+
}
|
|
1660
|
+
/**
|
|
1661
|
+
* Calculates the total price for this line item.
|
|
1662
|
+
*/
|
|
1663
|
+
get totalPrice() {
|
|
1664
|
+
return this.props.unitPrice.multiply(this.props.quantity);
|
|
1665
|
+
}
|
|
1666
|
+
/**
|
|
1667
|
+
* Updates the quantity of this item.
|
|
1668
|
+
*/
|
|
1669
|
+
updateQuantity(newQuantity) {
|
|
1670
|
+
this._props.quantity = newQuantity;
|
|
1671
|
+
}
|
|
1672
|
+
/**
|
|
1673
|
+
* Converts to a plain object for events or persistence.
|
|
1674
|
+
*/
|
|
1675
|
+
toPlain() {
|
|
1676
|
+
return {
|
|
1677
|
+
id: this.id.value,
|
|
1678
|
+
productId: this.props.productId,
|
|
1679
|
+
productName: this.props.productName,
|
|
1680
|
+
quantity: this.props.quantity,
|
|
1681
|
+
unitPrice: {
|
|
1682
|
+
amount: this.props.unitPrice.amount,
|
|
1683
|
+
currency: this.props.unitPrice.currency
|
|
1684
|
+
}
|
|
1685
|
+
};
|
|
1686
|
+
}
|
|
1687
|
+
};
|
|
1688
|
+
|
|
1689
|
+
// src/backend/core/onion-layers/domain/example-domain/exceptions/order-already-shipped.error.ts
|
|
1690
|
+
var OrderAlreadyShippedError = class extends InvariantViolationError {
|
|
1691
|
+
constructor(orderId) {
|
|
1692
|
+
super({
|
|
1693
|
+
message: `Order ${orderId} has already been shipped and cannot be modified`,
|
|
1694
|
+
code: "ORDER_ALREADY_SHIPPED"
|
|
1695
|
+
});
|
|
1696
|
+
}
|
|
1697
|
+
};
|
|
1698
|
+
|
|
1699
|
+
// src/backend/core/onion-layers/infra/classes/base-outbound-adapter.class.ts
|
|
1700
|
+
var WRAPPED_METHODS_SYMBOL = /* @__PURE__ */ Symbol.for("onion-lasagna:wrapped-methods");
|
|
1701
|
+
function getWrappedMethods(proto) {
|
|
1702
|
+
const existing = proto[WRAPPED_METHODS_SYMBOL];
|
|
1703
|
+
if (existing) return existing;
|
|
1704
|
+
const newSet = /* @__PURE__ */ new Set();
|
|
1705
|
+
Object.defineProperty(proto, WRAPPED_METHODS_SYMBOL, {
|
|
1706
|
+
value: newSet,
|
|
1707
|
+
writable: false,
|
|
1708
|
+
enumerable: false,
|
|
1709
|
+
configurable: false
|
|
1710
|
+
});
|
|
1711
|
+
return newSet;
|
|
1712
|
+
}
|
|
1713
|
+
var BaseOutboundAdapter = class _BaseOutboundAdapter {
|
|
1714
|
+
/**
|
|
1715
|
+
* Initializes the adapter and wraps all subclass methods with error handling.
|
|
1716
|
+
* Must be called via `super()` in subclass constructors.
|
|
1717
|
+
*/
|
|
1718
|
+
constructor() {
|
|
1719
|
+
this.wrapAllSubclassMethods();
|
|
1720
|
+
}
|
|
1721
|
+
/**
|
|
1722
|
+
* Factory method for creating infrastructure errors.
|
|
1723
|
+
*
|
|
1724
|
+
* Override this in subclasses to return specific error types
|
|
1725
|
+
* (e.g., `DbError`, `NetworkError`, `ExternalServiceError`).
|
|
1726
|
+
*
|
|
1727
|
+
* @param error - The original error that was caught
|
|
1728
|
+
* @param methodName - Name of the method where the error occurred (for debugging)
|
|
1729
|
+
* @returns An InfraError instance wrapping the original error
|
|
1730
|
+
*/
|
|
1731
|
+
createInfraError(error, methodName) {
|
|
1732
|
+
return new InfraError({
|
|
1733
|
+
message: `Outbound adapter error in ${methodName}`,
|
|
1734
|
+
cause: error
|
|
1735
|
+
});
|
|
1736
|
+
}
|
|
1737
|
+
/**
|
|
1738
|
+
* Walks the prototype chain and wraps all methods with error handling.
|
|
1739
|
+
* Uses prototype-level Symbol markers to prevent re-wrapping across instances.
|
|
1740
|
+
* @internal
|
|
1741
|
+
*/
|
|
1742
|
+
wrapAllSubclassMethods() {
|
|
1743
|
+
const wrapMethod = (methodName, original) => {
|
|
1744
|
+
const wrapped = (...args) => {
|
|
1745
|
+
try {
|
|
1746
|
+
const result = Reflect.apply(original, this, args);
|
|
1747
|
+
if (result instanceof Promise) {
|
|
1748
|
+
return result.catch((error) => {
|
|
1749
|
+
throw this.createInfraError(error, methodName);
|
|
1750
|
+
});
|
|
1751
|
+
}
|
|
1752
|
+
return result;
|
|
1753
|
+
} catch (error) {
|
|
1754
|
+
throw this.createInfraError(error, methodName);
|
|
1755
|
+
}
|
|
1756
|
+
};
|
|
1757
|
+
Object.defineProperty(this, methodName, {
|
|
1758
|
+
value: wrapped,
|
|
1759
|
+
writable: false,
|
|
1760
|
+
enumerable: false,
|
|
1761
|
+
configurable: false
|
|
1762
|
+
});
|
|
1763
|
+
};
|
|
1764
|
+
const methodsToWrap = [];
|
|
1765
|
+
let proto = Object.getPrototypeOf(this);
|
|
1766
|
+
while (proto && proto !== _BaseOutboundAdapter.prototype && proto !== Object.prototype) {
|
|
1767
|
+
const wrappedOnProto = getWrappedMethods(proto);
|
|
1768
|
+
for (const key of Object.getOwnPropertyNames(proto)) {
|
|
1769
|
+
if (key === "constructor") continue;
|
|
1770
|
+
if (wrappedOnProto.has(key)) continue;
|
|
1771
|
+
const descriptor = Object.getOwnPropertyDescriptor(proto, key);
|
|
1772
|
+
if (!descriptor) continue;
|
|
1773
|
+
if (descriptor.get || descriptor.set) continue;
|
|
1774
|
+
if (typeof descriptor.value !== "function") continue;
|
|
1775
|
+
methodsToWrap.push({ name: key, fn: descriptor.value });
|
|
1776
|
+
wrappedOnProto.add(key);
|
|
1777
|
+
}
|
|
1778
|
+
proto = Object.getPrototypeOf(proto);
|
|
1779
|
+
}
|
|
1780
|
+
for (const { name, fn } of methodsToWrap) {
|
|
1781
|
+
wrapMethod(name, fn);
|
|
1782
|
+
}
|
|
1783
|
+
}
|
|
1784
|
+
};
|
|
1785
|
+
|
|
1786
|
+
// src/backend/core/onion-layers/infra/exceptions/db.error.ts
|
|
1787
|
+
var DbError = class _DbError extends InfraError {
|
|
1788
|
+
/**
|
|
1789
|
+
* Creates a new DbError instance.
|
|
1790
|
+
*
|
|
1791
|
+
* @param options - Error configuration
|
|
1792
|
+
* @param options.message - Description of the database failure
|
|
1793
|
+
* @param options.code - Machine-readable error code (default: 'DB_ERROR')
|
|
1794
|
+
* @param options.cause - Optional underlying database error
|
|
1795
|
+
*/
|
|
1796
|
+
constructor({
|
|
1797
|
+
message,
|
|
1798
|
+
code = ErrorCodes.Infra.DB_ERROR,
|
|
1799
|
+
cause
|
|
1800
|
+
}) {
|
|
1801
|
+
super({ message, code, cause });
|
|
1802
|
+
}
|
|
1803
|
+
/**
|
|
1804
|
+
* Creates a DbError from a caught error.
|
|
1805
|
+
*
|
|
1806
|
+
* @param cause - The original caught error
|
|
1807
|
+
* @returns A new DbError instance with the cause attached
|
|
1808
|
+
*/
|
|
1809
|
+
static fromError(cause) {
|
|
1810
|
+
return new _DbError({
|
|
1811
|
+
message: cause instanceof Error ? cause.message : "Database error",
|
|
1812
|
+
cause
|
|
1813
|
+
});
|
|
1814
|
+
}
|
|
1815
|
+
};
|
|
1816
|
+
|
|
1817
|
+
// src/backend/core/onion-layers/infra/exceptions/network.error.ts
|
|
1818
|
+
var NetworkError = class _NetworkError extends InfraError {
|
|
1819
|
+
/**
|
|
1820
|
+
* Creates a new NetworkError instance.
|
|
1821
|
+
*
|
|
1822
|
+
* @param options - Error configuration
|
|
1823
|
+
* @param options.message - Description of the network failure
|
|
1824
|
+
* @param options.code - Machine-readable error code (default: 'NETWORK_ERROR')
|
|
1825
|
+
* @param options.cause - Optional underlying network error
|
|
1826
|
+
*/
|
|
1827
|
+
constructor({
|
|
1828
|
+
message,
|
|
1829
|
+
code = ErrorCodes.Infra.NETWORK_ERROR,
|
|
1830
|
+
cause
|
|
1831
|
+
}) {
|
|
1832
|
+
super({ message, code, cause });
|
|
1833
|
+
}
|
|
1834
|
+
/**
|
|
1835
|
+
* Creates a NetworkError from a caught error.
|
|
1836
|
+
*
|
|
1837
|
+
* @param cause - The original caught error
|
|
1838
|
+
* @returns A new NetworkError instance with the cause attached
|
|
1839
|
+
*/
|
|
1840
|
+
static fromError(cause) {
|
|
1841
|
+
return new _NetworkError({
|
|
1842
|
+
message: cause instanceof Error ? cause.message : "Network error",
|
|
1843
|
+
cause
|
|
1844
|
+
});
|
|
1845
|
+
}
|
|
1846
|
+
};
|
|
1847
|
+
|
|
1848
|
+
// src/backend/core/onion-layers/infra/exceptions/timeout.error.ts
|
|
1849
|
+
var TimeoutError = class _TimeoutError extends InfraError {
|
|
1850
|
+
/**
|
|
1851
|
+
* Creates a new TimeoutError instance.
|
|
1852
|
+
*
|
|
1853
|
+
* @param options - Error configuration
|
|
1854
|
+
* @param options.message - Description of what timed out
|
|
1855
|
+
* @param options.code - Machine-readable error code (default: 'TIMEOUT_ERROR')
|
|
1856
|
+
* @param options.cause - Optional underlying timeout error
|
|
1857
|
+
*/
|
|
1858
|
+
constructor({
|
|
1859
|
+
message,
|
|
1860
|
+
code = ErrorCodes.Infra.TIMEOUT_ERROR,
|
|
1861
|
+
cause
|
|
1862
|
+
}) {
|
|
1863
|
+
super({ message, code, cause });
|
|
1864
|
+
}
|
|
1865
|
+
/**
|
|
1866
|
+
* Creates a TimeoutError from a caught error.
|
|
1867
|
+
*
|
|
1868
|
+
* @param cause - The original caught error
|
|
1869
|
+
* @returns A new TimeoutError instance with the cause attached
|
|
1870
|
+
*/
|
|
1871
|
+
static fromError(cause) {
|
|
1872
|
+
return new _TimeoutError({
|
|
1873
|
+
message: cause instanceof Error ? cause.message : "Operation timed out",
|
|
1874
|
+
cause
|
|
1875
|
+
});
|
|
1876
|
+
}
|
|
1877
|
+
};
|
|
1878
|
+
|
|
1879
|
+
// src/backend/core/onion-layers/infra/exceptions/external-service.error.ts
|
|
1880
|
+
var ExternalServiceError = class _ExternalServiceError extends InfraError {
|
|
1881
|
+
/**
|
|
1882
|
+
* Creates a new ExternalServiceError instance.
|
|
1883
|
+
*
|
|
1884
|
+
* @param options - Error configuration
|
|
1885
|
+
* @param options.message - Description of the external service failure
|
|
1886
|
+
* @param options.code - Machine-readable error code (default: 'EXTERNAL_SERVICE_ERROR')
|
|
1887
|
+
* @param options.cause - Optional underlying service error
|
|
1888
|
+
*/
|
|
1889
|
+
constructor({
|
|
1890
|
+
message,
|
|
1891
|
+
code = ErrorCodes.Infra.EXTERNAL_SERVICE_ERROR,
|
|
1892
|
+
cause
|
|
1893
|
+
}) {
|
|
1894
|
+
super({ message, code, cause });
|
|
1895
|
+
}
|
|
1896
|
+
/**
|
|
1897
|
+
* Creates an ExternalServiceError from a caught error.
|
|
1898
|
+
*
|
|
1899
|
+
* @param cause - The original caught error
|
|
1900
|
+
* @returns A new ExternalServiceError instance with the cause attached
|
|
1901
|
+
*/
|
|
1902
|
+
static fromError(cause) {
|
|
1903
|
+
return new _ExternalServiceError({
|
|
1904
|
+
message: cause instanceof Error ? cause.message : "External service error",
|
|
1905
|
+
cause
|
|
1906
|
+
});
|
|
1907
|
+
}
|
|
1908
|
+
};
|
|
1909
|
+
|
|
1910
|
+
// src/backend/core/onion-layers/presentation/exceptions/controller.error.ts
|
|
1911
|
+
var ControllerError = class _ControllerError extends CodedError {
|
|
1912
|
+
/**
|
|
1913
|
+
* Creates a new ControllerError instance.
|
|
1914
|
+
*
|
|
1915
|
+
* @param options - Error configuration
|
|
1916
|
+
* @param options.message - Human-readable error description
|
|
1917
|
+
* @param options.code - Machine-readable error code (default: 'CONTROLLER_ERROR')
|
|
1918
|
+
* @param options.cause - Optional underlying error
|
|
1919
|
+
*/
|
|
1920
|
+
constructor({
|
|
1921
|
+
message,
|
|
1922
|
+
code = ErrorCodes.Presentation.CONTROLLER_ERROR,
|
|
1923
|
+
cause
|
|
1924
|
+
}) {
|
|
1925
|
+
super({ message, code, cause });
|
|
1926
|
+
}
|
|
1927
|
+
/**
|
|
1928
|
+
* Creates a ControllerError from a caught error.
|
|
1929
|
+
*
|
|
1930
|
+
* @param cause - The original caught error
|
|
1931
|
+
* @returns A new ControllerError instance with the cause attached
|
|
1932
|
+
*/
|
|
1933
|
+
static fromError(cause) {
|
|
1934
|
+
return new _ControllerError({
|
|
1935
|
+
message: cause instanceof Error ? cause.message : "Controller error",
|
|
1936
|
+
cause
|
|
1937
|
+
});
|
|
1938
|
+
}
|
|
1939
|
+
};
|
|
1940
|
+
|
|
1941
|
+
// src/backend/core/onion-layers/presentation/exceptions/invalid-request.error.ts
|
|
1942
|
+
var InvalidRequestError = class _InvalidRequestError extends CodedError {
|
|
1943
|
+
/**
|
|
1944
|
+
* Array of field-level validation errors.
|
|
1945
|
+
*
|
|
1946
|
+
* Each entry contains:
|
|
1947
|
+
* - `field`: Dot-notation path to the invalid field
|
|
1948
|
+
* - `message`: Human-readable validation failure message
|
|
1949
|
+
*/
|
|
1950
|
+
validationErrors;
|
|
1951
|
+
/**
|
|
1952
|
+
* Creates a new InvalidRequestError instance.
|
|
1953
|
+
*
|
|
1954
|
+
* @param options - Error configuration
|
|
1955
|
+
* @param options.message - Summary of the validation failure
|
|
1956
|
+
* @param options.code - Machine-readable error code (default: 'INVALID_REQUEST')
|
|
1957
|
+
* @param options.cause - Optional underlying error
|
|
1958
|
+
* @param options.validationErrors - Array of field-level validation errors
|
|
1959
|
+
*/
|
|
1960
|
+
constructor({
|
|
1961
|
+
message,
|
|
1962
|
+
code = ErrorCodes.Presentation.INVALID_REQUEST,
|
|
1963
|
+
cause,
|
|
1964
|
+
validationErrors
|
|
1965
|
+
}) {
|
|
1966
|
+
super({ message, code, cause });
|
|
1967
|
+
this.validationErrors = validationErrors;
|
|
1968
|
+
}
|
|
1969
|
+
/**
|
|
1970
|
+
* Creates an InvalidRequestError from a caught error.
|
|
1971
|
+
*
|
|
1972
|
+
* @param cause - The original caught error
|
|
1973
|
+
* @returns A new InvalidRequestError instance with the cause attached
|
|
1974
|
+
*/
|
|
1975
|
+
static fromError(cause) {
|
|
1976
|
+
return new _InvalidRequestError({
|
|
1977
|
+
message: cause instanceof Error ? cause.message : "Invalid request",
|
|
1978
|
+
cause,
|
|
1979
|
+
validationErrors: []
|
|
1980
|
+
});
|
|
1981
|
+
}
|
|
1982
|
+
};
|
|
1983
|
+
|
|
1984
|
+
// src/backend/core/onion-layers/presentation/classes/base-controller.class.ts
|
|
1985
|
+
var BaseController = class _BaseController {
|
|
1986
|
+
/**
|
|
1987
|
+
* Creates a new BaseController instance.
|
|
1988
|
+
*
|
|
1989
|
+
* @param requestMapper - Function to map request DTO to use case input DTO
|
|
1990
|
+
* @param useCase - The use case port to execute
|
|
1991
|
+
* @param responseMapper - Function to map use case output DTO to response DTO
|
|
1992
|
+
*/
|
|
1993
|
+
constructor(requestMapper, useCase, responseMapper) {
|
|
1994
|
+
this.requestMapper = requestMapper;
|
|
1995
|
+
this.useCase = useCase;
|
|
1996
|
+
this.responseMapper = responseMapper;
|
|
1997
|
+
}
|
|
1998
|
+
/**
|
|
1999
|
+
* Factory method to create a controller from a configuration object.
|
|
2000
|
+
*
|
|
2001
|
+
* @param config - Controller configuration
|
|
2002
|
+
* @returns A new BaseController instance
|
|
2003
|
+
*/
|
|
2004
|
+
static create(config) {
|
|
2005
|
+
return new _BaseController(config.requestMapper, config.useCase, config.responseMapper);
|
|
2006
|
+
}
|
|
2007
|
+
/**
|
|
2008
|
+
* Executes the controller pipeline with error wrapping.
|
|
2009
|
+
*
|
|
2010
|
+
* This is the public entry point that ensures consistent error handling.
|
|
2011
|
+
* All errors are wrapped in {@link ControllerError} unless they extend {@link CodedError}.
|
|
2012
|
+
*
|
|
2013
|
+
* **Do not override this method.** Override {@link pipeline} instead for custom pipeline logic.
|
|
2014
|
+
*
|
|
2015
|
+
* @param input - The validated request DTO
|
|
2016
|
+
* @returns Promise resolving to the validated response DTO
|
|
2017
|
+
* @throws {InvalidRequestError} When request mapping/validation fails
|
|
2018
|
+
* @throws {ControllerError} When an unexpected error occurs
|
|
2019
|
+
* @throws {CodedError} When use case throws a known error type
|
|
2020
|
+
*/
|
|
2021
|
+
async execute(input) {
|
|
2022
|
+
return wrapErrorUnlessAsync(
|
|
2023
|
+
() => this.pipeline(input),
|
|
2024
|
+
(cause) => new ControllerError({
|
|
2025
|
+
message: cause instanceof Error ? cause.message : "Controller execution failed",
|
|
2026
|
+
cause
|
|
2027
|
+
}),
|
|
2028
|
+
[CodedError]
|
|
2029
|
+
);
|
|
2030
|
+
}
|
|
2031
|
+
/**
|
|
2032
|
+
* Runs the controller pipeline.
|
|
2033
|
+
*
|
|
2034
|
+
* Orchestrates: `mapRequest → executeUseCase → mapResponse`
|
|
2035
|
+
*
|
|
2036
|
+
* Override this method to customize the entire pipeline flow, or override
|
|
2037
|
+
* individual protected methods ({@link mapRequest}, {@link executeUseCase},
|
|
2038
|
+
* {@link mapResponse}) for more granular control.
|
|
2039
|
+
*
|
|
2040
|
+
* @param input - The validated request DTO
|
|
2041
|
+
* @returns Promise resolving to the validated response DTO
|
|
2042
|
+
*/
|
|
2043
|
+
async pipeline(input) {
|
|
2044
|
+
const mappedInput = this.mapRequest(input);
|
|
2045
|
+
const result = await this.executeUseCase(mappedInput);
|
|
2046
|
+
return this.mapResponse(result);
|
|
2047
|
+
}
|
|
2048
|
+
/**
|
|
2049
|
+
* Maps the request DTO to a use case input DTO.
|
|
2050
|
+
*
|
|
2051
|
+
* Override to add custom pre-processing, logging, or transformation logic.
|
|
2052
|
+
* The default implementation uses the configured `requestMapper` and converts
|
|
2053
|
+
* {@link ObjectValidationError} to {@link InvalidRequestError}.
|
|
2054
|
+
*
|
|
2055
|
+
* @param input - The validated request DTO
|
|
2056
|
+
* @returns The use case input DTO
|
|
2057
|
+
* @throws {InvalidRequestError} When validation fails
|
|
2058
|
+
* @throws {ControllerError} When mapping fails unexpectedly
|
|
2059
|
+
*/
|
|
2060
|
+
mapRequest(input) {
|
|
2061
|
+
return wrapErrorUnless(
|
|
2062
|
+
() => this.requestMapper(input),
|
|
2063
|
+
(cause) => {
|
|
2064
|
+
if (cause instanceof ObjectValidationError) {
|
|
2065
|
+
return new InvalidRequestError({
|
|
2066
|
+
message: cause.message,
|
|
2067
|
+
cause,
|
|
2068
|
+
validationErrors: cause.validationErrors
|
|
2069
|
+
});
|
|
2070
|
+
}
|
|
2071
|
+
return new ControllerError({
|
|
2072
|
+
message: cause instanceof Error ? cause.message : "Request mapping failed",
|
|
2073
|
+
cause
|
|
2074
|
+
});
|
|
2075
|
+
},
|
|
2076
|
+
[CodedError]
|
|
2077
|
+
);
|
|
2078
|
+
}
|
|
2079
|
+
/**
|
|
2080
|
+
* Executes the use case with the mapped input.
|
|
2081
|
+
*
|
|
2082
|
+
* Override to add custom logic around use case execution, such as:
|
|
2083
|
+
* - Logging/tracing
|
|
2084
|
+
* - Caching
|
|
2085
|
+
* - Retry logic
|
|
2086
|
+
* - Multi-use-case orchestration
|
|
2087
|
+
*
|
|
2088
|
+
* @param input - The use case input DTO
|
|
2089
|
+
* @returns Promise resolving to the use case output DTO
|
|
2090
|
+
*/
|
|
2091
|
+
async executeUseCase(input) {
|
|
2092
|
+
return this.useCase.execute(input);
|
|
2093
|
+
}
|
|
2094
|
+
/**
|
|
2095
|
+
* Maps the use case output DTO to a response DTO.
|
|
2096
|
+
*
|
|
2097
|
+
* Override to add custom post-processing, logging, or transformation logic.
|
|
2098
|
+
* The default implementation uses the configured `responseMapper`.
|
|
2099
|
+
*
|
|
2100
|
+
* @param output - The use case output DTO
|
|
2101
|
+
* @returns The response DTO
|
|
2102
|
+
* @throws {ControllerError} When mapping or validation fails
|
|
2103
|
+
*/
|
|
2104
|
+
mapResponse(output) {
|
|
2105
|
+
return wrapErrorUnless(
|
|
2106
|
+
() => this.responseMapper(output),
|
|
2107
|
+
(cause) => new ControllerError({
|
|
2108
|
+
message: cause instanceof ObjectValidationError ? "Response validation failed" : cause instanceof Error ? cause.message : "Response mapping failed",
|
|
2109
|
+
cause
|
|
2110
|
+
}),
|
|
2111
|
+
[CodedError]
|
|
2112
|
+
);
|
|
2113
|
+
}
|
|
2114
|
+
};
|
|
2115
|
+
|
|
2116
|
+
// src/backend/core/onion-layers/presentation/exceptions/access-denied.error.ts
|
|
2117
|
+
var AccessDeniedError = class _AccessDeniedError extends CodedError {
|
|
2118
|
+
/**
|
|
2119
|
+
* Creates a new AccessDeniedError instance.
|
|
2120
|
+
*
|
|
2121
|
+
* @param options - Error configuration
|
|
2122
|
+
* @param options.message - Description of why access was denied
|
|
2123
|
+
* @param options.code - Machine-readable error code (default: 'ACCESS_DENIED')
|
|
2124
|
+
* @param options.cause - Optional underlying error
|
|
2125
|
+
*/
|
|
2126
|
+
constructor({
|
|
2127
|
+
message,
|
|
2128
|
+
code = ErrorCodes.Presentation.ACCESS_DENIED,
|
|
2129
|
+
cause
|
|
2130
|
+
}) {
|
|
2131
|
+
super({ message, code, cause });
|
|
2132
|
+
}
|
|
2133
|
+
/**
|
|
2134
|
+
* Creates an AccessDeniedError from a caught error.
|
|
2135
|
+
*
|
|
2136
|
+
* @param cause - The original caught error
|
|
2137
|
+
* @returns A new AccessDeniedError instance with the cause attached
|
|
2138
|
+
*/
|
|
2139
|
+
static fromError(cause) {
|
|
2140
|
+
return new _AccessDeniedError({
|
|
2141
|
+
message: cause instanceof Error ? cause.message : "Access denied",
|
|
2142
|
+
cause
|
|
2143
|
+
});
|
|
2144
|
+
}
|
|
2145
|
+
};
|
|
2146
|
+
|
|
2147
|
+
// src/backend/core/onion-layers/presentation/classes/guarded-controller.class.ts
|
|
2148
|
+
function createAllowAllGuard() {
|
|
2149
|
+
return async () => ({
|
|
2150
|
+
isAllowed: true
|
|
2151
|
+
});
|
|
2152
|
+
}
|
|
2153
|
+
var GuardedController = class _GuardedController extends BaseController {
|
|
2154
|
+
/** The access guard function for this controller. */
|
|
2155
|
+
accessGuard;
|
|
2156
|
+
/**
|
|
2157
|
+
* Creates a new GuardedController instance.
|
|
2158
|
+
*
|
|
2159
|
+
* @param requestMapper - Function to map request DTO to use case input DTO
|
|
2160
|
+
* @param useCase - The use case port to execute
|
|
2161
|
+
* @param responseMapper - Function to map use case output DTO to response DTO
|
|
2162
|
+
* @param accessGuard - Optional access guard; defaults to allowing all
|
|
2163
|
+
*/
|
|
2164
|
+
constructor(requestMapper, useCase, responseMapper, accessGuard) {
|
|
2165
|
+
super(requestMapper, useCase, responseMapper);
|
|
2166
|
+
this.accessGuard = accessGuard ?? createAllowAllGuard();
|
|
2167
|
+
}
|
|
2168
|
+
/**
|
|
2169
|
+
* Factory method to create a guarded controller from a configuration object.
|
|
2170
|
+
*
|
|
2171
|
+
* @param config - Controller configuration including optional access guard
|
|
2172
|
+
* @returns A new GuardedController instance
|
|
2173
|
+
*/
|
|
2174
|
+
static create(config) {
|
|
2175
|
+
return new _GuardedController(
|
|
2176
|
+
config.requestMapper,
|
|
2177
|
+
config.useCase,
|
|
2178
|
+
config.responseMapper,
|
|
2179
|
+
config.accessGuard
|
|
2180
|
+
);
|
|
2181
|
+
}
|
|
2182
|
+
/**
|
|
2183
|
+
* Runs the controller pipeline with access control.
|
|
2184
|
+
*
|
|
2185
|
+
* Checks the access guard before executing the pipeline.
|
|
2186
|
+
* If denied, throws {@link AccessDeniedError}.
|
|
2187
|
+
*
|
|
2188
|
+
* @param input - The validated request DTO
|
|
2189
|
+
* @returns Promise resolving to the validated response DTO
|
|
2190
|
+
* @throws {AccessDeniedError} When access guard denies the request
|
|
2191
|
+
*/
|
|
2192
|
+
async pipeline(input) {
|
|
2193
|
+
await this.checkAccess(input);
|
|
2194
|
+
return super.pipeline(input);
|
|
2195
|
+
}
|
|
2196
|
+
/**
|
|
2197
|
+
* Checks access using the configured guard.
|
|
2198
|
+
*
|
|
2199
|
+
* Override to customize access control logic.
|
|
2200
|
+
*
|
|
2201
|
+
* @param input - The validated request DTO
|
|
2202
|
+
* @throws {AccessDeniedError} When access is denied
|
|
2203
|
+
*/
|
|
2204
|
+
async checkAccess(input) {
|
|
2205
|
+
const result = await this.accessGuard(input);
|
|
2206
|
+
if (!result.isAllowed) {
|
|
2207
|
+
throw new AccessDeniedError({
|
|
2208
|
+
message: result.reason ?? "Access denied"
|
|
2209
|
+
});
|
|
2210
|
+
}
|
|
2211
|
+
}
|
|
2212
|
+
};
|
|
2213
|
+
|
|
2214
|
+
// src/backend/core/onion-layers/presentation/interfaces/types/metadata/system-metadata.type.ts
|
|
2215
|
+
function defineSystemMetadata(metadata) {
|
|
2216
|
+
return metadata;
|
|
2217
|
+
}
|
|
2218
|
+
|
|
2219
|
+
// src/backend/core/onion-layers/presentation/routing/compute-route-path.util.ts
|
|
2220
|
+
function trimSlashes(segment) {
|
|
2221
|
+
return segment.replace(/^\/+|\/+$/g, "");
|
|
2222
|
+
}
|
|
2223
|
+
function computeRoutePath(service, resource, endpoint) {
|
|
2224
|
+
const segments = [service.basePath, resource.path, endpoint.path].map(trimSlashes).filter((s) => s.length > 0);
|
|
2225
|
+
if (segments.length === 0) {
|
|
2226
|
+
return "/";
|
|
2227
|
+
}
|
|
2228
|
+
return "/" + segments.join("/");
|
|
2229
|
+
}
|
|
2230
|
+
|
|
2231
|
+
// src/backend/core/onion-layers/presentation/utils/http-response.util.ts
|
|
2232
|
+
function isHttpResponse(value) {
|
|
2233
|
+
return typeof value === "object" && value !== null && "statusCode" in value && typeof value.statusCode === "number";
|
|
2234
|
+
}
|
|
2235
|
+
function assertHttpResponse(value, context = "value") {
|
|
2236
|
+
if (!isHttpResponse(value)) {
|
|
2237
|
+
const actualType = value === null ? "null" : value === void 0 ? "undefined" : typeof value;
|
|
2238
|
+
const hasStatusCode = typeof value === "object" && value !== null && "statusCode" in value;
|
|
2239
|
+
let message = `Expected ${context} to be an HttpResponse with a numeric statusCode, `;
|
|
2240
|
+
if (hasStatusCode) {
|
|
2241
|
+
const statusCodeType = typeof value["statusCode"];
|
|
2242
|
+
message += `but statusCode was ${statusCodeType}`;
|
|
2243
|
+
} else {
|
|
2244
|
+
message += `but got ${actualType}`;
|
|
2245
|
+
}
|
|
2246
|
+
throw new Error(message);
|
|
2247
|
+
}
|
|
2248
|
+
}
|
|
2249
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
2250
|
+
0 && (module.exports = {
|
|
2251
|
+
AccessDeniedError,
|
|
2252
|
+
BaseAggregateRoot,
|
|
2253
|
+
BaseAuditByVo,
|
|
2254
|
+
BaseAuditInfoVo,
|
|
2255
|
+
BaseAuditOnVo,
|
|
2256
|
+
BaseController,
|
|
2257
|
+
BaseDomainEvent,
|
|
2258
|
+
BaseEmailVo,
|
|
2259
|
+
BaseEntity,
|
|
2260
|
+
BaseInboundAdapter,
|
|
2261
|
+
BaseLongTextVo,
|
|
2262
|
+
BaseMediumTextVo,
|
|
2263
|
+
BaseOutboundAdapter,
|
|
2264
|
+
BasePaginationVo,
|
|
2265
|
+
BaseShortTextVo,
|
|
2266
|
+
BaseUuidV4Vo,
|
|
2267
|
+
BaseUuidV7Vo,
|
|
2268
|
+
BaseValueObject,
|
|
2269
|
+
ConflictError,
|
|
2270
|
+
ControllerError,
|
|
2271
|
+
DbError,
|
|
2272
|
+
DomainError,
|
|
2273
|
+
ExternalServiceError,
|
|
2274
|
+
GuardedController,
|
|
2275
|
+
InfraError,
|
|
2276
|
+
InvalidRequestError,
|
|
2277
|
+
InvariantViolationError,
|
|
2278
|
+
Money,
|
|
2279
|
+
NetworkError,
|
|
2280
|
+
NotFoundError,
|
|
2281
|
+
Order,
|
|
2282
|
+
OrderAlreadyShippedError,
|
|
2283
|
+
OrderCancelledEvent,
|
|
2284
|
+
OrderId,
|
|
2285
|
+
OrderItem,
|
|
2286
|
+
OrderItemId,
|
|
2287
|
+
OrderPlacedEvent,
|
|
2288
|
+
OrderStatus,
|
|
2289
|
+
PartialLoadError,
|
|
2290
|
+
SKIP_VALUE_OBJECT_VALIDATION,
|
|
2291
|
+
TimeoutError,
|
|
2292
|
+
UnprocessableError,
|
|
2293
|
+
UseCaseError,
|
|
2294
|
+
assertHttpResponse,
|
|
2295
|
+
canAddOrderItem,
|
|
2296
|
+
canCancelOrder,
|
|
2297
|
+
computeRoutePath,
|
|
2298
|
+
defaultOrderStatus,
|
|
2299
|
+
defineSystemMetadata,
|
|
2300
|
+
isHttpResponse
|
|
2301
|
+
});
|
|
2302
|
+
//# sourceMappingURL=onion-layers.cjs.map
|