@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,573 @@
|
|
|
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/presentation/index.ts
|
|
21
|
+
var presentation_exports = {};
|
|
22
|
+
__export(presentation_exports, {
|
|
23
|
+
AccessDeniedError: () => AccessDeniedError,
|
|
24
|
+
BaseController: () => BaseController,
|
|
25
|
+
ControllerError: () => ControllerError,
|
|
26
|
+
GuardedController: () => GuardedController,
|
|
27
|
+
InvalidRequestError: () => InvalidRequestError,
|
|
28
|
+
assertHttpResponse: () => assertHttpResponse,
|
|
29
|
+
computeRoutePath: () => computeRoutePath,
|
|
30
|
+
defineSystemMetadata: () => defineSystemMetadata,
|
|
31
|
+
isHttpResponse: () => isHttpResponse
|
|
32
|
+
});
|
|
33
|
+
module.exports = __toCommonJS(presentation_exports);
|
|
34
|
+
|
|
35
|
+
// src/backend/core/global/exceptions/coded-error.error.ts
|
|
36
|
+
var CodedError = class extends Error {
|
|
37
|
+
/** Machine-readable error code for programmatic handling. */
|
|
38
|
+
code;
|
|
39
|
+
/**
|
|
40
|
+
* Creates a new CodedError instance.
|
|
41
|
+
*
|
|
42
|
+
* @param options - Error configuration
|
|
43
|
+
* @param options.message - Human-readable error message
|
|
44
|
+
* @param options.code - Machine-readable error code from ErrorCodes registry or custom string
|
|
45
|
+
* @param options.cause - Optional underlying error that caused this error
|
|
46
|
+
*/
|
|
47
|
+
constructor({
|
|
48
|
+
message,
|
|
49
|
+
code,
|
|
50
|
+
cause
|
|
51
|
+
}) {
|
|
52
|
+
super(message);
|
|
53
|
+
this.name = this.constructor.name;
|
|
54
|
+
this.code = code;
|
|
55
|
+
if (cause !== void 0) {
|
|
56
|
+
Object.defineProperty(this, "cause", {
|
|
57
|
+
value: cause,
|
|
58
|
+
writable: false,
|
|
59
|
+
enumerable: false,
|
|
60
|
+
configurable: true
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Factory method to create a typed error from a caught error.
|
|
66
|
+
*
|
|
67
|
+
* Subclasses should override this to provide proper error transformation.
|
|
68
|
+
* Designed for use with {@link wrapErrorAsync} and {@link wrapError}.
|
|
69
|
+
*
|
|
70
|
+
* @param _cause - The original caught error
|
|
71
|
+
* @returns A new CodedError instance
|
|
72
|
+
* @throws {Error} If not overridden by subclass
|
|
73
|
+
*
|
|
74
|
+
* @example
|
|
75
|
+
* ```typescript
|
|
76
|
+
* class NotFoundError extends UseCaseError {
|
|
77
|
+
* static override fromError(cause: unknown): NotFoundError {
|
|
78
|
+
* return new NotFoundError({
|
|
79
|
+
* message: 'Resource not found',
|
|
80
|
+
* cause,
|
|
81
|
+
* });
|
|
82
|
+
* }
|
|
83
|
+
* }
|
|
84
|
+
* ```
|
|
85
|
+
*/
|
|
86
|
+
static fromError(_cause) {
|
|
87
|
+
throw new Error(`${this.name}.fromError() must be implemented by subclass`);
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
// src/backend/core/global/exceptions/error-codes.const.ts
|
|
92
|
+
var ErrorCodes = {
|
|
93
|
+
/**
|
|
94
|
+
* Domain layer error codes.
|
|
95
|
+
* Used for business rule violations and invariant failures.
|
|
96
|
+
*/
|
|
97
|
+
Domain: {
|
|
98
|
+
/** Generic domain error */
|
|
99
|
+
DOMAIN_ERROR: "DOMAIN_ERROR",
|
|
100
|
+
/** Business invariant was violated */
|
|
101
|
+
INVARIANT_VIOLATION: "INVARIANT_VIOLATION",
|
|
102
|
+
/** Aggregate was partially loaded (missing required relations) */
|
|
103
|
+
PARTIAL_LOAD: "PARTIAL_LOAD"
|
|
104
|
+
},
|
|
105
|
+
/**
|
|
106
|
+
* Application layer (use case) error codes.
|
|
107
|
+
* Used for orchestration failures and business operation errors.
|
|
108
|
+
*/
|
|
109
|
+
App: {
|
|
110
|
+
/** Generic use case error */
|
|
111
|
+
USE_CASE_ERROR: "USE_CASE_ERROR",
|
|
112
|
+
/** Requested resource was not found */
|
|
113
|
+
NOT_FOUND: "NOT_FOUND",
|
|
114
|
+
/** Resource state conflict (e.g., duplicate, already exists) */
|
|
115
|
+
CONFLICT: "CONFLICT",
|
|
116
|
+
/** Request is valid but cannot be processed due to business rules */
|
|
117
|
+
UNPROCESSABLE: "UNPROCESSABLE"
|
|
118
|
+
},
|
|
119
|
+
/**
|
|
120
|
+
* Infrastructure layer error codes.
|
|
121
|
+
* Used for data access, external services, and I/O failures.
|
|
122
|
+
*/
|
|
123
|
+
Infra: {
|
|
124
|
+
/** Generic infrastructure error */
|
|
125
|
+
INFRA_ERROR: "INFRA_ERROR",
|
|
126
|
+
/** Database operation failed */
|
|
127
|
+
DB_ERROR: "DB_ERROR",
|
|
128
|
+
/** Network connectivity or communication error */
|
|
129
|
+
NETWORK_ERROR: "NETWORK_ERROR",
|
|
130
|
+
/** Operation timed out */
|
|
131
|
+
TIMEOUT_ERROR: "TIMEOUT_ERROR",
|
|
132
|
+
/** External/third-party service error */
|
|
133
|
+
EXTERNAL_SERVICE_ERROR: "EXTERNAL_SERVICE_ERROR"
|
|
134
|
+
},
|
|
135
|
+
/**
|
|
136
|
+
* Presentation layer error codes.
|
|
137
|
+
* Used for controller, request handling, and authorization errors.
|
|
138
|
+
*/
|
|
139
|
+
Presentation: {
|
|
140
|
+
/** Generic controller error */
|
|
141
|
+
CONTROLLER_ERROR: "CONTROLLER_ERROR",
|
|
142
|
+
/** Request denied due to authorization failure */
|
|
143
|
+
ACCESS_DENIED: "ACCESS_DENIED",
|
|
144
|
+
/** Request validation failed (malformed input) */
|
|
145
|
+
INVALID_REQUEST: "INVALID_REQUEST"
|
|
146
|
+
},
|
|
147
|
+
/**
|
|
148
|
+
* Global/cross-cutting error codes.
|
|
149
|
+
* Used for validation and other cross-layer concerns.
|
|
150
|
+
*/
|
|
151
|
+
Global: {
|
|
152
|
+
/** Object/schema validation failed */
|
|
153
|
+
OBJECT_VALIDATION_ERROR: "OBJECT_VALIDATION_ERROR"
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
// src/backend/core/global/exceptions/object-validation.error.ts
|
|
158
|
+
var ObjectValidationError = class _ObjectValidationError extends CodedError {
|
|
159
|
+
/**
|
|
160
|
+
* Array of field-level validation errors.
|
|
161
|
+
*
|
|
162
|
+
* Each entry contains:
|
|
163
|
+
* - `field`: Dot-notation path to the invalid field (e.g., 'user.email')
|
|
164
|
+
* - `message`: Human-readable validation failure message
|
|
165
|
+
*/
|
|
166
|
+
validationErrors;
|
|
167
|
+
/**
|
|
168
|
+
* Creates a new ObjectValidationError instance.
|
|
169
|
+
*
|
|
170
|
+
* @param options - Error configuration
|
|
171
|
+
* @param options.message - Human-readable summary message
|
|
172
|
+
* @param options.code - Machine-readable error code (default: 'OBJECT_VALIDATION_ERROR')
|
|
173
|
+
* @param options.cause - Optional underlying error from validation library
|
|
174
|
+
* @param options.validationErrors - Array of field-level validation errors
|
|
175
|
+
*/
|
|
176
|
+
constructor({
|
|
177
|
+
message,
|
|
178
|
+
code = ErrorCodes.Global.OBJECT_VALIDATION_ERROR,
|
|
179
|
+
cause,
|
|
180
|
+
validationErrors
|
|
181
|
+
}) {
|
|
182
|
+
super({ message, code, cause });
|
|
183
|
+
this.validationErrors = validationErrors;
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Creates an ObjectValidationError from a caught error.
|
|
187
|
+
*
|
|
188
|
+
* @param cause - The original caught error
|
|
189
|
+
* @returns A new ObjectValidationError instance with the cause attached
|
|
190
|
+
*/
|
|
191
|
+
static fromError(cause) {
|
|
192
|
+
return new _ObjectValidationError({
|
|
193
|
+
message: cause instanceof Error ? cause.message : "Validation failed",
|
|
194
|
+
cause,
|
|
195
|
+
validationErrors: []
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
// src/backend/core/global/utils/wrap-error.util.ts
|
|
201
|
+
function wrapErrorUnless(fn, errorFactory, passthroughTypes) {
|
|
202
|
+
try {
|
|
203
|
+
return fn();
|
|
204
|
+
} catch (error) {
|
|
205
|
+
if (passthroughTypes.some((Type) => error instanceof Type)) {
|
|
206
|
+
throw error;
|
|
207
|
+
}
|
|
208
|
+
throw errorFactory(error);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
async function wrapErrorUnlessAsync(fn, errorFactory, passthroughTypes) {
|
|
212
|
+
try {
|
|
213
|
+
return await fn();
|
|
214
|
+
} catch (error) {
|
|
215
|
+
if (passthroughTypes.some((Type) => error instanceof Type)) {
|
|
216
|
+
throw error;
|
|
217
|
+
}
|
|
218
|
+
throw errorFactory(error);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// src/backend/core/onion-layers/presentation/exceptions/controller.error.ts
|
|
223
|
+
var ControllerError = class _ControllerError extends CodedError {
|
|
224
|
+
/**
|
|
225
|
+
* Creates a new ControllerError instance.
|
|
226
|
+
*
|
|
227
|
+
* @param options - Error configuration
|
|
228
|
+
* @param options.message - Human-readable error description
|
|
229
|
+
* @param options.code - Machine-readable error code (default: 'CONTROLLER_ERROR')
|
|
230
|
+
* @param options.cause - Optional underlying error
|
|
231
|
+
*/
|
|
232
|
+
constructor({
|
|
233
|
+
message,
|
|
234
|
+
code = ErrorCodes.Presentation.CONTROLLER_ERROR,
|
|
235
|
+
cause
|
|
236
|
+
}) {
|
|
237
|
+
super({ message, code, cause });
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Creates a ControllerError from a caught error.
|
|
241
|
+
*
|
|
242
|
+
* @param cause - The original caught error
|
|
243
|
+
* @returns A new ControllerError instance with the cause attached
|
|
244
|
+
*/
|
|
245
|
+
static fromError(cause) {
|
|
246
|
+
return new _ControllerError({
|
|
247
|
+
message: cause instanceof Error ? cause.message : "Controller error",
|
|
248
|
+
cause
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
};
|
|
252
|
+
|
|
253
|
+
// src/backend/core/onion-layers/presentation/exceptions/invalid-request.error.ts
|
|
254
|
+
var InvalidRequestError = class _InvalidRequestError extends CodedError {
|
|
255
|
+
/**
|
|
256
|
+
* Array of field-level validation errors.
|
|
257
|
+
*
|
|
258
|
+
* Each entry contains:
|
|
259
|
+
* - `field`: Dot-notation path to the invalid field
|
|
260
|
+
* - `message`: Human-readable validation failure message
|
|
261
|
+
*/
|
|
262
|
+
validationErrors;
|
|
263
|
+
/**
|
|
264
|
+
* Creates a new InvalidRequestError instance.
|
|
265
|
+
*
|
|
266
|
+
* @param options - Error configuration
|
|
267
|
+
* @param options.message - Summary of the validation failure
|
|
268
|
+
* @param options.code - Machine-readable error code (default: 'INVALID_REQUEST')
|
|
269
|
+
* @param options.cause - Optional underlying error
|
|
270
|
+
* @param options.validationErrors - Array of field-level validation errors
|
|
271
|
+
*/
|
|
272
|
+
constructor({
|
|
273
|
+
message,
|
|
274
|
+
code = ErrorCodes.Presentation.INVALID_REQUEST,
|
|
275
|
+
cause,
|
|
276
|
+
validationErrors
|
|
277
|
+
}) {
|
|
278
|
+
super({ message, code, cause });
|
|
279
|
+
this.validationErrors = validationErrors;
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* Creates an InvalidRequestError from a caught error.
|
|
283
|
+
*
|
|
284
|
+
* @param cause - The original caught error
|
|
285
|
+
* @returns A new InvalidRequestError instance with the cause attached
|
|
286
|
+
*/
|
|
287
|
+
static fromError(cause) {
|
|
288
|
+
return new _InvalidRequestError({
|
|
289
|
+
message: cause instanceof Error ? cause.message : "Invalid request",
|
|
290
|
+
cause,
|
|
291
|
+
validationErrors: []
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
};
|
|
295
|
+
|
|
296
|
+
// src/backend/core/onion-layers/presentation/classes/base-controller.class.ts
|
|
297
|
+
var BaseController = class _BaseController {
|
|
298
|
+
/**
|
|
299
|
+
* Creates a new BaseController instance.
|
|
300
|
+
*
|
|
301
|
+
* @param requestMapper - Function to map request DTO to use case input DTO
|
|
302
|
+
* @param useCase - The use case port to execute
|
|
303
|
+
* @param responseMapper - Function to map use case output DTO to response DTO
|
|
304
|
+
*/
|
|
305
|
+
constructor(requestMapper, useCase, responseMapper) {
|
|
306
|
+
this.requestMapper = requestMapper;
|
|
307
|
+
this.useCase = useCase;
|
|
308
|
+
this.responseMapper = responseMapper;
|
|
309
|
+
}
|
|
310
|
+
/**
|
|
311
|
+
* Factory method to create a controller from a configuration object.
|
|
312
|
+
*
|
|
313
|
+
* @param config - Controller configuration
|
|
314
|
+
* @returns A new BaseController instance
|
|
315
|
+
*/
|
|
316
|
+
static create(config) {
|
|
317
|
+
return new _BaseController(config.requestMapper, config.useCase, config.responseMapper);
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
320
|
+
* Executes the controller pipeline with error wrapping.
|
|
321
|
+
*
|
|
322
|
+
* This is the public entry point that ensures consistent error handling.
|
|
323
|
+
* All errors are wrapped in {@link ControllerError} unless they extend {@link CodedError}.
|
|
324
|
+
*
|
|
325
|
+
* **Do not override this method.** Override {@link pipeline} instead for custom pipeline logic.
|
|
326
|
+
*
|
|
327
|
+
* @param input - The validated request DTO
|
|
328
|
+
* @returns Promise resolving to the validated response DTO
|
|
329
|
+
* @throws {InvalidRequestError} When request mapping/validation fails
|
|
330
|
+
* @throws {ControllerError} When an unexpected error occurs
|
|
331
|
+
* @throws {CodedError} When use case throws a known error type
|
|
332
|
+
*/
|
|
333
|
+
async execute(input) {
|
|
334
|
+
return wrapErrorUnlessAsync(
|
|
335
|
+
() => this.pipeline(input),
|
|
336
|
+
(cause) => new ControllerError({
|
|
337
|
+
message: cause instanceof Error ? cause.message : "Controller execution failed",
|
|
338
|
+
cause
|
|
339
|
+
}),
|
|
340
|
+
[CodedError]
|
|
341
|
+
);
|
|
342
|
+
}
|
|
343
|
+
/**
|
|
344
|
+
* Runs the controller pipeline.
|
|
345
|
+
*
|
|
346
|
+
* Orchestrates: `mapRequest → executeUseCase → mapResponse`
|
|
347
|
+
*
|
|
348
|
+
* Override this method to customize the entire pipeline flow, or override
|
|
349
|
+
* individual protected methods ({@link mapRequest}, {@link executeUseCase},
|
|
350
|
+
* {@link mapResponse}) for more granular control.
|
|
351
|
+
*
|
|
352
|
+
* @param input - The validated request DTO
|
|
353
|
+
* @returns Promise resolving to the validated response DTO
|
|
354
|
+
*/
|
|
355
|
+
async pipeline(input) {
|
|
356
|
+
const mappedInput = this.mapRequest(input);
|
|
357
|
+
const result = await this.executeUseCase(mappedInput);
|
|
358
|
+
return this.mapResponse(result);
|
|
359
|
+
}
|
|
360
|
+
/**
|
|
361
|
+
* Maps the request DTO to a use case input DTO.
|
|
362
|
+
*
|
|
363
|
+
* Override to add custom pre-processing, logging, or transformation logic.
|
|
364
|
+
* The default implementation uses the configured `requestMapper` and converts
|
|
365
|
+
* {@link ObjectValidationError} to {@link InvalidRequestError}.
|
|
366
|
+
*
|
|
367
|
+
* @param input - The validated request DTO
|
|
368
|
+
* @returns The use case input DTO
|
|
369
|
+
* @throws {InvalidRequestError} When validation fails
|
|
370
|
+
* @throws {ControllerError} When mapping fails unexpectedly
|
|
371
|
+
*/
|
|
372
|
+
mapRequest(input) {
|
|
373
|
+
return wrapErrorUnless(
|
|
374
|
+
() => this.requestMapper(input),
|
|
375
|
+
(cause) => {
|
|
376
|
+
if (cause instanceof ObjectValidationError) {
|
|
377
|
+
return new InvalidRequestError({
|
|
378
|
+
message: cause.message,
|
|
379
|
+
cause,
|
|
380
|
+
validationErrors: cause.validationErrors
|
|
381
|
+
});
|
|
382
|
+
}
|
|
383
|
+
return new ControllerError({
|
|
384
|
+
message: cause instanceof Error ? cause.message : "Request mapping failed",
|
|
385
|
+
cause
|
|
386
|
+
});
|
|
387
|
+
},
|
|
388
|
+
[CodedError]
|
|
389
|
+
);
|
|
390
|
+
}
|
|
391
|
+
/**
|
|
392
|
+
* Executes the use case with the mapped input.
|
|
393
|
+
*
|
|
394
|
+
* Override to add custom logic around use case execution, such as:
|
|
395
|
+
* - Logging/tracing
|
|
396
|
+
* - Caching
|
|
397
|
+
* - Retry logic
|
|
398
|
+
* - Multi-use-case orchestration
|
|
399
|
+
*
|
|
400
|
+
* @param input - The use case input DTO
|
|
401
|
+
* @returns Promise resolving to the use case output DTO
|
|
402
|
+
*/
|
|
403
|
+
async executeUseCase(input) {
|
|
404
|
+
return this.useCase.execute(input);
|
|
405
|
+
}
|
|
406
|
+
/**
|
|
407
|
+
* Maps the use case output DTO to a response DTO.
|
|
408
|
+
*
|
|
409
|
+
* Override to add custom post-processing, logging, or transformation logic.
|
|
410
|
+
* The default implementation uses the configured `responseMapper`.
|
|
411
|
+
*
|
|
412
|
+
* @param output - The use case output DTO
|
|
413
|
+
* @returns The response DTO
|
|
414
|
+
* @throws {ControllerError} When mapping or validation fails
|
|
415
|
+
*/
|
|
416
|
+
mapResponse(output) {
|
|
417
|
+
return wrapErrorUnless(
|
|
418
|
+
() => this.responseMapper(output),
|
|
419
|
+
(cause) => new ControllerError({
|
|
420
|
+
message: cause instanceof ObjectValidationError ? "Response validation failed" : cause instanceof Error ? cause.message : "Response mapping failed",
|
|
421
|
+
cause
|
|
422
|
+
}),
|
|
423
|
+
[CodedError]
|
|
424
|
+
);
|
|
425
|
+
}
|
|
426
|
+
};
|
|
427
|
+
|
|
428
|
+
// src/backend/core/onion-layers/presentation/exceptions/access-denied.error.ts
|
|
429
|
+
var AccessDeniedError = class _AccessDeniedError extends CodedError {
|
|
430
|
+
/**
|
|
431
|
+
* Creates a new AccessDeniedError instance.
|
|
432
|
+
*
|
|
433
|
+
* @param options - Error configuration
|
|
434
|
+
* @param options.message - Description of why access was denied
|
|
435
|
+
* @param options.code - Machine-readable error code (default: 'ACCESS_DENIED')
|
|
436
|
+
* @param options.cause - Optional underlying error
|
|
437
|
+
*/
|
|
438
|
+
constructor({
|
|
439
|
+
message,
|
|
440
|
+
code = ErrorCodes.Presentation.ACCESS_DENIED,
|
|
441
|
+
cause
|
|
442
|
+
}) {
|
|
443
|
+
super({ message, code, cause });
|
|
444
|
+
}
|
|
445
|
+
/**
|
|
446
|
+
* Creates an AccessDeniedError from a caught error.
|
|
447
|
+
*
|
|
448
|
+
* @param cause - The original caught error
|
|
449
|
+
* @returns A new AccessDeniedError instance with the cause attached
|
|
450
|
+
*/
|
|
451
|
+
static fromError(cause) {
|
|
452
|
+
return new _AccessDeniedError({
|
|
453
|
+
message: cause instanceof Error ? cause.message : "Access denied",
|
|
454
|
+
cause
|
|
455
|
+
});
|
|
456
|
+
}
|
|
457
|
+
};
|
|
458
|
+
|
|
459
|
+
// src/backend/core/onion-layers/presentation/classes/guarded-controller.class.ts
|
|
460
|
+
function createAllowAllGuard() {
|
|
461
|
+
return async () => ({
|
|
462
|
+
isAllowed: true
|
|
463
|
+
});
|
|
464
|
+
}
|
|
465
|
+
var GuardedController = class _GuardedController extends BaseController {
|
|
466
|
+
/** The access guard function for this controller. */
|
|
467
|
+
accessGuard;
|
|
468
|
+
/**
|
|
469
|
+
* Creates a new GuardedController instance.
|
|
470
|
+
*
|
|
471
|
+
* @param requestMapper - Function to map request DTO to use case input DTO
|
|
472
|
+
* @param useCase - The use case port to execute
|
|
473
|
+
* @param responseMapper - Function to map use case output DTO to response DTO
|
|
474
|
+
* @param accessGuard - Optional access guard; defaults to allowing all
|
|
475
|
+
*/
|
|
476
|
+
constructor(requestMapper, useCase, responseMapper, accessGuard) {
|
|
477
|
+
super(requestMapper, useCase, responseMapper);
|
|
478
|
+
this.accessGuard = accessGuard ?? createAllowAllGuard();
|
|
479
|
+
}
|
|
480
|
+
/**
|
|
481
|
+
* Factory method to create a guarded controller from a configuration object.
|
|
482
|
+
*
|
|
483
|
+
* @param config - Controller configuration including optional access guard
|
|
484
|
+
* @returns A new GuardedController instance
|
|
485
|
+
*/
|
|
486
|
+
static create(config) {
|
|
487
|
+
return new _GuardedController(
|
|
488
|
+
config.requestMapper,
|
|
489
|
+
config.useCase,
|
|
490
|
+
config.responseMapper,
|
|
491
|
+
config.accessGuard
|
|
492
|
+
);
|
|
493
|
+
}
|
|
494
|
+
/**
|
|
495
|
+
* Runs the controller pipeline with access control.
|
|
496
|
+
*
|
|
497
|
+
* Checks the access guard before executing the pipeline.
|
|
498
|
+
* If denied, throws {@link AccessDeniedError}.
|
|
499
|
+
*
|
|
500
|
+
* @param input - The validated request DTO
|
|
501
|
+
* @returns Promise resolving to the validated response DTO
|
|
502
|
+
* @throws {AccessDeniedError} When access guard denies the request
|
|
503
|
+
*/
|
|
504
|
+
async pipeline(input) {
|
|
505
|
+
await this.checkAccess(input);
|
|
506
|
+
return super.pipeline(input);
|
|
507
|
+
}
|
|
508
|
+
/**
|
|
509
|
+
* Checks access using the configured guard.
|
|
510
|
+
*
|
|
511
|
+
* Override to customize access control logic.
|
|
512
|
+
*
|
|
513
|
+
* @param input - The validated request DTO
|
|
514
|
+
* @throws {AccessDeniedError} When access is denied
|
|
515
|
+
*/
|
|
516
|
+
async checkAccess(input) {
|
|
517
|
+
const result = await this.accessGuard(input);
|
|
518
|
+
if (!result.isAllowed) {
|
|
519
|
+
throw new AccessDeniedError({
|
|
520
|
+
message: result.reason ?? "Access denied"
|
|
521
|
+
});
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
};
|
|
525
|
+
|
|
526
|
+
// src/backend/core/onion-layers/presentation/interfaces/types/metadata/system-metadata.type.ts
|
|
527
|
+
function defineSystemMetadata(metadata) {
|
|
528
|
+
return metadata;
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
// src/backend/core/onion-layers/presentation/routing/compute-route-path.util.ts
|
|
532
|
+
function trimSlashes(segment) {
|
|
533
|
+
return segment.replace(/^\/+|\/+$/g, "");
|
|
534
|
+
}
|
|
535
|
+
function computeRoutePath(service, resource, endpoint) {
|
|
536
|
+
const segments = [service.basePath, resource.path, endpoint.path].map(trimSlashes).filter((s) => s.length > 0);
|
|
537
|
+
if (segments.length === 0) {
|
|
538
|
+
return "/";
|
|
539
|
+
}
|
|
540
|
+
return "/" + segments.join("/");
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
// src/backend/core/onion-layers/presentation/utils/http-response.util.ts
|
|
544
|
+
function isHttpResponse(value) {
|
|
545
|
+
return typeof value === "object" && value !== null && "statusCode" in value && typeof value.statusCode === "number";
|
|
546
|
+
}
|
|
547
|
+
function assertHttpResponse(value, context = "value") {
|
|
548
|
+
if (!isHttpResponse(value)) {
|
|
549
|
+
const actualType = value === null ? "null" : value === void 0 ? "undefined" : typeof value;
|
|
550
|
+
const hasStatusCode = typeof value === "object" && value !== null && "statusCode" in value;
|
|
551
|
+
let message = `Expected ${context} to be an HttpResponse with a numeric statusCode, `;
|
|
552
|
+
if (hasStatusCode) {
|
|
553
|
+
const statusCodeType = typeof value["statusCode"];
|
|
554
|
+
message += `but statusCode was ${statusCodeType}`;
|
|
555
|
+
} else {
|
|
556
|
+
message += `but got ${actualType}`;
|
|
557
|
+
}
|
|
558
|
+
throw new Error(message);
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
562
|
+
0 && (module.exports = {
|
|
563
|
+
AccessDeniedError,
|
|
564
|
+
BaseController,
|
|
565
|
+
ControllerError,
|
|
566
|
+
GuardedController,
|
|
567
|
+
InvalidRequestError,
|
|
568
|
+
assertHttpResponse,
|
|
569
|
+
computeRoutePath,
|
|
570
|
+
defineSystemMetadata,
|
|
571
|
+
isHttpResponse
|
|
572
|
+
});
|
|
573
|
+
//# sourceMappingURL=presentation.cjs.map
|