@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,251 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ConflictError,
|
|
3
|
+
InfraError,
|
|
4
|
+
NotFoundError,
|
|
5
|
+
UnprocessableError,
|
|
6
|
+
UseCaseError
|
|
7
|
+
} from "../../chunk-RLLWYFPI.js";
|
|
8
|
+
import {
|
|
9
|
+
AccessDeniedError,
|
|
10
|
+
ControllerError,
|
|
11
|
+
InvalidRequestError
|
|
12
|
+
} from "../../chunk-74IKUOSE.js";
|
|
13
|
+
import {
|
|
14
|
+
DomainError
|
|
15
|
+
} from "../../chunk-ZWLYNGO3.js";
|
|
16
|
+
import {
|
|
17
|
+
CodedError,
|
|
18
|
+
ObjectValidationError
|
|
19
|
+
} from "../../chunk-MQD5GXMT.js";
|
|
20
|
+
import "../../chunk-CGZBV6BD.js";
|
|
21
|
+
|
|
22
|
+
// src/backend/frameworks/elysia/routing.ts
|
|
23
|
+
function toElysiaPath(path) {
|
|
24
|
+
return path.replace(/\{([^}]+)\}/g, ":$1");
|
|
25
|
+
}
|
|
26
|
+
function extractRequest(context) {
|
|
27
|
+
const headers = {};
|
|
28
|
+
for (const [key, value] of Object.entries(context.headers)) {
|
|
29
|
+
if (value != null) {
|
|
30
|
+
headers[key.toLowerCase()] = value;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
const queryParams = {};
|
|
34
|
+
for (const [key, value] of Object.entries(context.query)) {
|
|
35
|
+
if (value != null) {
|
|
36
|
+
queryParams[key] = value;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return {
|
|
40
|
+
body: context.body,
|
|
41
|
+
headers,
|
|
42
|
+
queryParams,
|
|
43
|
+
pathParams: context.params
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
function createResponse(response) {
|
|
47
|
+
const headers = {
|
|
48
|
+
"Content-Type": "application/json"
|
|
49
|
+
};
|
|
50
|
+
if (response.headers) {
|
|
51
|
+
for (const [key, value] of Object.entries(response.headers)) {
|
|
52
|
+
if (value != null) {
|
|
53
|
+
headers[key] = String(value);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
if (response.body === void 0 || response.body === null) {
|
|
58
|
+
return new Response(null, {
|
|
59
|
+
status: response.statusCode,
|
|
60
|
+
headers
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
if (typeof response.body === "string") {
|
|
64
|
+
headers["Content-Type"] = "text/plain";
|
|
65
|
+
return new Response(response.body, {
|
|
66
|
+
status: response.statusCode,
|
|
67
|
+
headers
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
return new Response(JSON.stringify(response.body), {
|
|
71
|
+
status: response.statusCode,
|
|
72
|
+
headers
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
function registerElysiaRoutes(app, routes, options) {
|
|
76
|
+
const routeArray = Array.isArray(routes) ? routes : [routes];
|
|
77
|
+
const prefix = options?.prefix ?? "";
|
|
78
|
+
const middlewares = options?.middlewares ?? [];
|
|
79
|
+
for (const { metadata, controller, requestDtoFactory } of routeArray) {
|
|
80
|
+
const path = prefix + toElysiaPath(metadata.path);
|
|
81
|
+
const method = metadata.method.toLowerCase();
|
|
82
|
+
const handler = async (context) => {
|
|
83
|
+
for (const middleware of middlewares) {
|
|
84
|
+
const result = await middleware(context);
|
|
85
|
+
if (result !== void 0) return result;
|
|
86
|
+
}
|
|
87
|
+
const rawRequest = extractRequest(context);
|
|
88
|
+
const requestDto = requestDtoFactory(rawRequest);
|
|
89
|
+
const responseDto = await controller.execute(requestDto);
|
|
90
|
+
return createResponse(responseDto.data);
|
|
91
|
+
};
|
|
92
|
+
switch (method) {
|
|
93
|
+
case "get":
|
|
94
|
+
app.get(path, handler);
|
|
95
|
+
break;
|
|
96
|
+
case "post":
|
|
97
|
+
app.post(path, handler);
|
|
98
|
+
break;
|
|
99
|
+
case "put":
|
|
100
|
+
app.put(path, handler);
|
|
101
|
+
break;
|
|
102
|
+
case "patch":
|
|
103
|
+
app.patch(path, handler);
|
|
104
|
+
break;
|
|
105
|
+
case "delete":
|
|
106
|
+
app.delete(path, handler);
|
|
107
|
+
break;
|
|
108
|
+
case "options":
|
|
109
|
+
app.options(path, handler);
|
|
110
|
+
break;
|
|
111
|
+
case "head":
|
|
112
|
+
app.head(path, handler);
|
|
113
|
+
break;
|
|
114
|
+
default:
|
|
115
|
+
throw new Error(`Unsupported HTTP method: ${method}`);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// src/backend/frameworks/elysia/map-error-to-response.ts
|
|
121
|
+
function mapErrorToResponse(error) {
|
|
122
|
+
if (error instanceof ObjectValidationError) {
|
|
123
|
+
return {
|
|
124
|
+
statusCode: 400,
|
|
125
|
+
body: {
|
|
126
|
+
message: error.message,
|
|
127
|
+
errorCode: error.code,
|
|
128
|
+
errorItems: error.validationErrors.map((e) => ({
|
|
129
|
+
item: e.field,
|
|
130
|
+
message: e.message
|
|
131
|
+
}))
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
if (error instanceof InvalidRequestError) {
|
|
136
|
+
return {
|
|
137
|
+
statusCode: 400,
|
|
138
|
+
body: {
|
|
139
|
+
message: error.message,
|
|
140
|
+
errorCode: error.code,
|
|
141
|
+
errorItems: error.validationErrors.map((e) => ({
|
|
142
|
+
item: e.field,
|
|
143
|
+
message: e.message
|
|
144
|
+
}))
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
if (error instanceof AccessDeniedError) {
|
|
149
|
+
return {
|
|
150
|
+
statusCode: 403,
|
|
151
|
+
body: {
|
|
152
|
+
message: error.message,
|
|
153
|
+
errorCode: error.code
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
if (error instanceof NotFoundError) {
|
|
158
|
+
return {
|
|
159
|
+
statusCode: 404,
|
|
160
|
+
body: {
|
|
161
|
+
message: error.message,
|
|
162
|
+
errorCode: error.code
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
if (error instanceof ConflictError) {
|
|
167
|
+
return {
|
|
168
|
+
statusCode: 409,
|
|
169
|
+
body: {
|
|
170
|
+
message: error.message,
|
|
171
|
+
errorCode: error.code
|
|
172
|
+
}
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
if (error instanceof UnprocessableError) {
|
|
176
|
+
return {
|
|
177
|
+
statusCode: 422,
|
|
178
|
+
body: {
|
|
179
|
+
message: error.message,
|
|
180
|
+
errorCode: error.code
|
|
181
|
+
}
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
if (error instanceof UseCaseError) {
|
|
185
|
+
return {
|
|
186
|
+
statusCode: 400,
|
|
187
|
+
body: {
|
|
188
|
+
message: error.message,
|
|
189
|
+
errorCode: error.code
|
|
190
|
+
}
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
if (error instanceof DomainError) {
|
|
194
|
+
return {
|
|
195
|
+
statusCode: 500,
|
|
196
|
+
body: {
|
|
197
|
+
message: "An unexpected error occurred",
|
|
198
|
+
errorCode: "INTERNAL_ERROR"
|
|
199
|
+
}
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
if (error instanceof InfraError) {
|
|
203
|
+
return {
|
|
204
|
+
statusCode: 500,
|
|
205
|
+
body: {
|
|
206
|
+
message: "An unexpected error occurred",
|
|
207
|
+
errorCode: "INTERNAL_ERROR"
|
|
208
|
+
}
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
if (error instanceof ControllerError) {
|
|
212
|
+
return {
|
|
213
|
+
statusCode: 500,
|
|
214
|
+
body: {
|
|
215
|
+
message: "An unexpected error occurred",
|
|
216
|
+
errorCode: "INTERNAL_ERROR"
|
|
217
|
+
}
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
if (error instanceof CodedError) {
|
|
221
|
+
return {
|
|
222
|
+
statusCode: 500,
|
|
223
|
+
body: {
|
|
224
|
+
message: "An unexpected error occurred",
|
|
225
|
+
errorCode: "INTERNAL_ERROR"
|
|
226
|
+
}
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
return {
|
|
230
|
+
statusCode: 500,
|
|
231
|
+
body: {
|
|
232
|
+
message: "An unexpected error occurred",
|
|
233
|
+
errorCode: "INTERNAL_ERROR"
|
|
234
|
+
}
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// src/backend/frameworks/elysia/error-handler.ts
|
|
239
|
+
function onionErrorHandler({ error }) {
|
|
240
|
+
const { statusCode, body } = mapErrorToResponse(error);
|
|
241
|
+
return new Response(JSON.stringify(body), {
|
|
242
|
+
status: statusCode,
|
|
243
|
+
headers: { "Content-Type": "application/json" }
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
export {
|
|
247
|
+
mapErrorToResponse,
|
|
248
|
+
onionErrorHandler,
|
|
249
|
+
registerElysiaRoutes
|
|
250
|
+
};
|
|
251
|
+
//# sourceMappingURL=elysia.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/backend/frameworks/elysia/routing.ts","../../../src/backend/frameworks/elysia/map-error-to-response.ts","../../../src/backend/frameworks/elysia/error-handler.ts"],"sourcesContent":["import type { Elysia, Handler } from 'elysia';\nimport type { BaseDto } from '../../core/global/classes/base-dto.class';\nimport type { Controller } from '../../core/onion-layers/presentation/interfaces/types/controller.type';\nimport type { HttpRequest } from '../../core/onion-layers/presentation/interfaces/types/http/http-request';\nimport type { HttpResponse } from '../../core/onion-layers/presentation/interfaces/types/http/http-response';\nimport type { RouteInput } from '../../core/onion-layers/presentation/routing';\n\n/**\n * Supported HTTP methods in Elysia.\n */\ntype HttpMethod = 'get' | 'post' | 'put' | 'patch' | 'delete' | 'options' | 'head';\n\n/**\n * Controller that works with a validated request DTO and returns HttpResponse.\n */\nexport type HttpController<TRequestDto extends BaseDto<unknown> = BaseDto<unknown>> = Controller<\n TRequestDto,\n HttpResponse\n>;\n\n/**\n * Elysia beforeHandle middleware type.\n * Returns undefined to continue, or a Response to short-circuit.\n */\nexport type ElysiaMiddleware = (context: {\n body: unknown;\n headers: Record<string, string | undefined>;\n query: Record<string, string | undefined>;\n params: Record<string, string>;\n}) => Response | undefined | Promise<Response | undefined>;\n\n/**\n * Converts `{param}` to Elysia's `:param` format.\n */\nfunction toElysiaPath(path: string): string {\n return path.replace(/\\{([^}]+)\\}/g, ':$1');\n}\n\n/**\n * Extracts HttpRequest from Elysia context.\n */\nfunction extractRequest(context: {\n body: unknown;\n headers: Record<string, string | undefined>;\n query: Record<string, string | undefined>;\n params: Record<string, string>;\n}): HttpRequest {\n const headers: Record<string, string> = {};\n for (const [key, value] of Object.entries(context.headers)) {\n if (value != null) {\n headers[key.toLowerCase()] = value;\n }\n }\n\n const queryParams: Record<string, string | string[]> = {};\n for (const [key, value] of Object.entries(context.query)) {\n if (value != null) {\n queryParams[key] = value;\n }\n }\n\n return {\n body: context.body,\n headers,\n queryParams,\n pathParams: context.params,\n };\n}\n\n/**\n * Creates Elysia response from HttpResponse.\n */\nfunction createResponse(response: HttpResponse): Response {\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n };\n\n if (response.headers) {\n for (const [key, value] of Object.entries(response.headers)) {\n if (value != null) {\n headers[key] = String(value);\n }\n }\n }\n\n if (response.body === undefined || response.body === null) {\n return new Response(null, {\n status: response.statusCode,\n headers,\n });\n }\n\n if (typeof response.body === 'string') {\n headers['Content-Type'] = 'text/plain';\n return new Response(response.body, {\n status: response.statusCode,\n headers,\n });\n }\n\n return new Response(JSON.stringify(response.body), {\n status: response.statusCode,\n headers,\n });\n}\n\n/**\n * Route input type that accepts either a single route or an array of routes.\n */\nexport type RouteInputOrArray = RouteInput | RouteInput[];\n\n/**\n * Options for registering routes.\n */\nexport interface RegisterRoutesOptions {\n /**\n * Prefix to apply to all routes in this registration.\n *\n * @example\n * ```typescript\n * registerElysiaRoutes(app, userRoutes, {\n * prefix: '/api/v1',\n * });\n * // Routes will be: /api/v1/users, /api/v1/users/:id, etc.\n * ```\n */\n prefix?: string;\n\n /**\n * Middlewares (beforeHandle hooks) to apply to all routes in this registration.\n * These run before the controller handler.\n *\n * @example\n * ```typescript\n * registerElysiaRoutes(app, userRoutes, {\n * middlewares: [\n * ({ headers }) => {\n * if (!headers.authorization) {\n * return new Response('Unauthorized', { status: 401 });\n * }\n * },\n * ],\n * });\n * ```\n */\n middlewares?: ElysiaMiddleware[];\n}\n\n/**\n * Registers routes onto an Elysia app.\n *\n * Accepts either a single route or an array of routes. Can be called multiple\n * times to register routes from different domains/modules.\n *\n * @param app - The Elysia app instance (passed by reference)\n * @param routes - A single route or an array of routes to register\n * @param options - Optional configuration including prefix\n *\n * @example Single route\n * ```typescript\n * const app = new Elysia();\n *\n * registerElysiaRoutes(app, {\n * metadata: { path: '/health', method: 'GET' },\n * controller: healthController,\n * });\n * ```\n *\n * @example Multiple routes\n * ```typescript\n * const app = new Elysia();\n *\n * registerElysiaRoutes(app, [\n * { metadata: { path: '/users', method: 'POST' }, controller: createUserController },\n * { metadata: { path: '/users/{id}', method: 'GET' }, controller: getUserController },\n * { metadata: { path: '/users/{id}', method: 'DELETE' }, controller: deleteUserController },\n * ]);\n * ```\n *\n * @example With prefix\n * ```typescript\n * registerElysiaRoutes(app, userRoutes, {\n * prefix: '/api/v1',\n * });\n * ```\n *\n * @example With middlewares\n * ```typescript\n * registerElysiaRoutes(app, protectedRoutes, {\n * middlewares: [\n * ({ headers }) => {\n * if (!headers.authorization) {\n * return new Response('Unauthorized', { status: 401 });\n * }\n * },\n * ],\n * });\n * ```\n *\n * @example Registering from multiple domains\n * ```typescript\n * const app = new Elysia();\n *\n * // Public routes\n * registerElysiaRoutes(app, publicRoutes);\n *\n * // API routes with prefix\n * registerElysiaRoutes(app, userRoutes, { prefix: '/api' });\n * registerElysiaRoutes(app, orderRoutes, { prefix: '/api' });\n *\n * export default app;\n * ```\n */\nexport function registerElysiaRoutes(\n app: Elysia,\n routes: RouteInputOrArray,\n options?: RegisterRoutesOptions,\n): void {\n const routeArray = Array.isArray(routes) ? routes : [routes];\n const prefix = options?.prefix ?? '';\n const middlewares = options?.middlewares ?? [];\n\n for (const { metadata, controller, requestDtoFactory } of routeArray) {\n const path = prefix + toElysiaPath(metadata.path);\n const method = metadata.method.toLowerCase() as HttpMethod;\n\n const handler: Handler = async (context) => {\n // Run middlewares first (beforeHandle pattern)\n for (const middleware of middlewares) {\n const result = await middleware(context);\n if (result !== undefined) return result;\n }\n\n const rawRequest = extractRequest(context as Parameters<typeof extractRequest>[0]);\n const requestDto = requestDtoFactory(rawRequest);\n const responseDto = await controller.execute(requestDto);\n return createResponse(responseDto.data);\n };\n\n switch (method) {\n case 'get':\n app.get(path, handler);\n break;\n case 'post':\n app.post(path, handler);\n break;\n case 'put':\n app.put(path, handler);\n break;\n case 'patch':\n app.patch(path, handler);\n break;\n case 'delete':\n app.delete(path, handler);\n break;\n case 'options':\n app.options(path, handler);\n break;\n case 'head':\n app.head(path, handler);\n break;\n default:\n throw new Error(`Unsupported HTTP method: ${method}`);\n }\n }\n}\n","import { CodedError } from '../../core/global/exceptions/coded-error.error';\nimport { ObjectValidationError } from '../../core/global/exceptions/object-validation.error';\nimport { DomainError } from '../../core/onion-layers/domain/exceptions/domain.error';\nimport { UseCaseError } from '../../core/onion-layers/app/exceptions/use-case.error';\nimport { NotFoundError } from '../../core/onion-layers/app/exceptions/not-found.error';\nimport { ConflictError } from '../../core/onion-layers/app/exceptions/conflict.error';\nimport { UnprocessableError } from '../../core/onion-layers/app/exceptions/unprocessable.error';\nimport { InfraError } from '../../core/onion-layers/infra/exceptions/infra.error';\nimport { ControllerError } from '../../core/onion-layers/presentation/exceptions/controller.error';\nimport { AccessDeniedError } from '../../core/onion-layers/presentation/exceptions/access-denied.error';\nimport { InvalidRequestError } from '../../core/onion-layers/presentation/exceptions/invalid-request.error';\n\n/**\n * Error item for field-level validation errors.\n */\ninterface ErrorItem {\n item: string;\n message: string;\n}\n\n/**\n * Standard error response body.\n */\nexport interface ErrorResponseBody {\n message: string;\n errorCode: string;\n errorItems?: ErrorItem[];\n}\n\n/**\n * Mapped error response with status code and body.\n */\nexport interface MappedErrorResponse {\n statusCode: number;\n body: ErrorResponseBody;\n}\n\n/**\n * Maps our error hierarchy to HTTP status codes and response bodies.\n *\n * Mapping strategy:\n * - `ObjectValidationError` → 400 Bad Request\n * - `InvalidRequestError` → 400 Bad Request\n * - `AccessDeniedError` → 403 Forbidden\n * - `NotFoundError` → 404 Not Found\n * - `ConflictError` → 409 Conflict\n * - `UnprocessableError` → 422 Unprocessable Entity\n * - `UseCaseError` (other) → 400 Bad Request\n * - `DomainError` → 500 Internal Server Error (masked)\n * - `InfraError` → 500 Internal Server Error (masked)\n * - `ControllerError` → 500 Internal Server Error (masked)\n * - Unknown → 500 Internal Server Error (masked)\n *\n * **Security Note:** Domain and infrastructure errors are masked to avoid\n * leaking internal implementation details.\n *\n * @param error - The error to map\n * @returns Mapped error response with status code and body\n */\nexport function mapErrorToResponse(error: unknown): MappedErrorResponse {\n // Validation errors → 400 Bad Request\n if (error instanceof ObjectValidationError) {\n return {\n statusCode: 400,\n body: {\n message: error.message,\n errorCode: error.code,\n errorItems: error.validationErrors.map((e) => ({\n item: e.field,\n message: e.message,\n })),\n },\n };\n }\n\n if (error instanceof InvalidRequestError) {\n return {\n statusCode: 400,\n body: {\n message: error.message,\n errorCode: error.code,\n errorItems: error.validationErrors.map((e) => ({\n item: e.field,\n message: e.message,\n })),\n },\n };\n }\n\n // Access control → 403 Forbidden\n if (error instanceof AccessDeniedError) {\n return {\n statusCode: 403,\n body: {\n message: error.message,\n errorCode: error.code,\n },\n };\n }\n\n // Use case errors → specific HTTP status codes\n if (error instanceof NotFoundError) {\n return {\n statusCode: 404,\n body: {\n message: error.message,\n errorCode: error.code,\n },\n };\n }\n\n if (error instanceof ConflictError) {\n return {\n statusCode: 409,\n body: {\n message: error.message,\n errorCode: error.code,\n },\n };\n }\n\n if (error instanceof UnprocessableError) {\n return {\n statusCode: 422,\n body: {\n message: error.message,\n errorCode: error.code,\n },\n };\n }\n\n // Other use case errors → 400 Bad Request\n if (error instanceof UseCaseError) {\n return {\n statusCode: 400,\n body: {\n message: error.message,\n errorCode: error.code,\n },\n };\n }\n\n // Domain errors → 500 Internal Server Error (masked)\n if (error instanceof DomainError) {\n return {\n statusCode: 500,\n body: {\n message: 'An unexpected error occurred',\n errorCode: 'INTERNAL_ERROR',\n },\n };\n }\n\n // Infrastructure errors → 500 Internal Server Error (masked)\n if (error instanceof InfraError) {\n return {\n statusCode: 500,\n body: {\n message: 'An unexpected error occurred',\n errorCode: 'INTERNAL_ERROR',\n },\n };\n }\n\n // Controller errors → 500 Internal Server Error (masked)\n if (error instanceof ControllerError) {\n return {\n statusCode: 500,\n body: {\n message: 'An unexpected error occurred',\n errorCode: 'INTERNAL_ERROR',\n },\n };\n }\n\n // CodedError (catch-all for known errors) → 500 (masked)\n if (error instanceof CodedError) {\n return {\n statusCode: 500,\n body: {\n message: 'An unexpected error occurred',\n errorCode: 'INTERNAL_ERROR',\n },\n };\n }\n\n // Unknown errors → 500 Internal Server Error (masked)\n return {\n statusCode: 500,\n body: {\n message: 'An unexpected error occurred',\n errorCode: 'INTERNAL_ERROR',\n },\n };\n}\n","import { mapErrorToResponse } from './map-error-to-response';\n\n/**\n * Elysia error handler that maps domain errors to HTTP responses.\n *\n * Apply this to your Elysia app using `.onError()` to automatically\n * convert domain/use-case errors to appropriate HTTP responses.\n *\n * @example\n * ```typescript\n * import { Elysia } from 'elysia';\n * import { registerElysiaRoutes, onionErrorHandler } from '@cosmneo/onion-lasagna/backend/frameworks/elysia';\n *\n * const app = new Elysia()\n * .onError(onionErrorHandler)\n * .get('/health', () => ({ status: 'ok' }));\n *\n * registerElysiaRoutes(app, routes);\n *\n * export default app;\n * ```\n *\n * @example With custom error logging\n * ```typescript\n * const app = new Elysia()\n * .onError(({ error, code, ...context }) => {\n * // Log the error\n * console.error('Error occurred:', error);\n *\n * // Use the onion error handler\n * return onionErrorHandler({ error, code, ...context });\n * });\n * ```\n */\nexport function onionErrorHandler({ error }: { error: unknown }): Response {\n const { statusCode, body } = mapErrorToResponse(error);\n\n return new Response(JSON.stringify(body), {\n status: statusCode,\n headers: { 'Content-Type': 'application/json' },\n });\n}\n"],"mappings":"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","names":[]}
|