@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,213 @@
|
|
|
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/fastify/routing.ts
|
|
23
|
+
function toFastifyPath(path) {
|
|
24
|
+
return path.replace(/\{([^}]+)\}/g, ":$1");
|
|
25
|
+
}
|
|
26
|
+
function extractRequest(request) {
|
|
27
|
+
const headers = {};
|
|
28
|
+
for (const [key, value] of Object.entries(request.headers)) {
|
|
29
|
+
if (typeof value === "string") {
|
|
30
|
+
headers[key.toLowerCase()] = value;
|
|
31
|
+
} else if (Array.isArray(value)) {
|
|
32
|
+
headers[key.toLowerCase()] = value.join(", ");
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
const queryParams = {};
|
|
36
|
+
const query = request.query;
|
|
37
|
+
for (const [key, value] of Object.entries(query)) {
|
|
38
|
+
if (value != null) {
|
|
39
|
+
queryParams[key] = value;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return {
|
|
43
|
+
body: request.body,
|
|
44
|
+
headers,
|
|
45
|
+
queryParams,
|
|
46
|
+
pathParams: request.params
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
function sendResponse(reply, response) {
|
|
50
|
+
if (response.headers) {
|
|
51
|
+
for (const [key, value] of Object.entries(response.headers)) {
|
|
52
|
+
if (value != null) {
|
|
53
|
+
reply.header(key, String(value));
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
reply.status(response.statusCode);
|
|
58
|
+
if (response.body === void 0 || response.body === null) {
|
|
59
|
+
return reply.send();
|
|
60
|
+
}
|
|
61
|
+
return reply.send(response.body);
|
|
62
|
+
}
|
|
63
|
+
function registerFastifyRoutes(app, routes, options) {
|
|
64
|
+
const routeArray = Array.isArray(routes) ? routes : [routes];
|
|
65
|
+
const prefix = options?.prefix ?? "";
|
|
66
|
+
const middlewares = options?.middlewares ?? [];
|
|
67
|
+
for (const { metadata, controller, requestDtoFactory } of routeArray) {
|
|
68
|
+
const path = prefix + toFastifyPath(metadata.path);
|
|
69
|
+
const method = metadata.method.toUpperCase();
|
|
70
|
+
const handler = async (request, reply) => {
|
|
71
|
+
const rawRequest = extractRequest(request);
|
|
72
|
+
const requestDto = requestDtoFactory(rawRequest);
|
|
73
|
+
const responseDto = await controller.execute(requestDto);
|
|
74
|
+
return sendResponse(reply, responseDto.data);
|
|
75
|
+
};
|
|
76
|
+
app.route({
|
|
77
|
+
method,
|
|
78
|
+
url: path,
|
|
79
|
+
preHandler: middlewares,
|
|
80
|
+
handler
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// src/backend/frameworks/fastify/map-error-to-response.ts
|
|
86
|
+
function mapErrorToResponse(error) {
|
|
87
|
+
if (error instanceof ObjectValidationError) {
|
|
88
|
+
return {
|
|
89
|
+
statusCode: 400,
|
|
90
|
+
body: {
|
|
91
|
+
message: error.message,
|
|
92
|
+
errorCode: error.code,
|
|
93
|
+
errorItems: error.validationErrors.map((e) => ({
|
|
94
|
+
item: e.field,
|
|
95
|
+
message: e.message
|
|
96
|
+
}))
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
if (error instanceof InvalidRequestError) {
|
|
101
|
+
return {
|
|
102
|
+
statusCode: 400,
|
|
103
|
+
body: {
|
|
104
|
+
message: error.message,
|
|
105
|
+
errorCode: error.code,
|
|
106
|
+
errorItems: error.validationErrors.map((e) => ({
|
|
107
|
+
item: e.field,
|
|
108
|
+
message: e.message
|
|
109
|
+
}))
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
if (error instanceof AccessDeniedError) {
|
|
114
|
+
return {
|
|
115
|
+
statusCode: 403,
|
|
116
|
+
body: {
|
|
117
|
+
message: error.message,
|
|
118
|
+
errorCode: error.code
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
if (error instanceof NotFoundError) {
|
|
123
|
+
return {
|
|
124
|
+
statusCode: 404,
|
|
125
|
+
body: {
|
|
126
|
+
message: error.message,
|
|
127
|
+
errorCode: error.code
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
if (error instanceof ConflictError) {
|
|
132
|
+
return {
|
|
133
|
+
statusCode: 409,
|
|
134
|
+
body: {
|
|
135
|
+
message: error.message,
|
|
136
|
+
errorCode: error.code
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
if (error instanceof UnprocessableError) {
|
|
141
|
+
return {
|
|
142
|
+
statusCode: 422,
|
|
143
|
+
body: {
|
|
144
|
+
message: error.message,
|
|
145
|
+
errorCode: error.code
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
if (error instanceof UseCaseError) {
|
|
150
|
+
return {
|
|
151
|
+
statusCode: 400,
|
|
152
|
+
body: {
|
|
153
|
+
message: error.message,
|
|
154
|
+
errorCode: error.code
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
if (error instanceof DomainError) {
|
|
159
|
+
return {
|
|
160
|
+
statusCode: 500,
|
|
161
|
+
body: {
|
|
162
|
+
message: "An unexpected error occurred",
|
|
163
|
+
errorCode: "INTERNAL_ERROR"
|
|
164
|
+
}
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
if (error instanceof InfraError) {
|
|
168
|
+
return {
|
|
169
|
+
statusCode: 500,
|
|
170
|
+
body: {
|
|
171
|
+
message: "An unexpected error occurred",
|
|
172
|
+
errorCode: "INTERNAL_ERROR"
|
|
173
|
+
}
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
if (error instanceof ControllerError) {
|
|
177
|
+
return {
|
|
178
|
+
statusCode: 500,
|
|
179
|
+
body: {
|
|
180
|
+
message: "An unexpected error occurred",
|
|
181
|
+
errorCode: "INTERNAL_ERROR"
|
|
182
|
+
}
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
if (error instanceof CodedError) {
|
|
186
|
+
return {
|
|
187
|
+
statusCode: 500,
|
|
188
|
+
body: {
|
|
189
|
+
message: "An unexpected error occurred",
|
|
190
|
+
errorCode: "INTERNAL_ERROR"
|
|
191
|
+
}
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
return {
|
|
195
|
+
statusCode: 500,
|
|
196
|
+
body: {
|
|
197
|
+
message: "An unexpected error occurred",
|
|
198
|
+
errorCode: "INTERNAL_ERROR"
|
|
199
|
+
}
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// src/backend/frameworks/fastify/error-handler.ts
|
|
204
|
+
function onionErrorHandler(error, _request, reply) {
|
|
205
|
+
const { statusCode, body } = mapErrorToResponse(error);
|
|
206
|
+
return reply.status(statusCode).send(body);
|
|
207
|
+
}
|
|
208
|
+
export {
|
|
209
|
+
mapErrorToResponse,
|
|
210
|
+
onionErrorHandler,
|
|
211
|
+
registerFastifyRoutes
|
|
212
|
+
};
|
|
213
|
+
//# sourceMappingURL=fastify.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/backend/frameworks/fastify/routing.ts","../../../src/backend/frameworks/fastify/map-error-to-response.ts","../../../src/backend/frameworks/fastify/error-handler.ts"],"sourcesContent":["import type {\n FastifyInstance,\n FastifyRequest,\n FastifyReply,\n RouteHandlerMethod,\n HTTPMethods,\n} from 'fastify';\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 * Controller that works with HttpRequest/HttpResponse.\n */\nexport type HttpController = Controller<HttpRequest, HttpResponse>;\n\n/**\n * Fastify preHandler middleware type.\n */\nexport type FastifyMiddleware = (\n request: FastifyRequest,\n reply: FastifyReply,\n) => Promise<void> | void;\n\n/**\n * Converts `{param}` to Fastify's `:param` format.\n */\nfunction toFastifyPath(path: string): string {\n return path.replace(/\\{([^}]+)\\}/g, ':$1');\n}\n\n/**\n * Extracts HttpRequest from Fastify request.\n */\nfunction extractRequest(request: FastifyRequest): HttpRequest {\n const headers: Record<string, string> = {};\n for (const [key, value] of Object.entries(request.headers)) {\n if (typeof value === 'string') {\n headers[key.toLowerCase()] = value;\n } else if (Array.isArray(value)) {\n headers[key.toLowerCase()] = value.join(', ');\n }\n }\n\n const queryParams: Record<string, string | string[]> = {};\n const query = request.query as Record<string, string | string[] | undefined>;\n for (const [key, value] of Object.entries(query)) {\n if (value != null) {\n queryParams[key] = value;\n }\n }\n\n return {\n body: request.body,\n headers,\n queryParams,\n pathParams: request.params as Record<string, string>,\n };\n}\n\n/**\n * Sends HttpResponse via Fastify reply.\n */\nfunction sendResponse(reply: FastifyReply, response: HttpResponse): FastifyReply {\n if (response.headers) {\n for (const [key, value] of Object.entries(response.headers)) {\n if (value != null) {\n reply.header(key, String(value));\n }\n }\n }\n\n reply.status(response.statusCode);\n\n if (response.body === undefined || response.body === null) {\n return reply.send();\n }\n\n return reply.send(response.body);\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 * registerFastifyRoutes(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 (preHandler hooks) to apply to all routes in this registration.\n * These run before the controller handler.\n *\n * @example\n * ```typescript\n * registerFastifyRoutes(app, protectedRoutes, {\n * middlewares: [\n * async (request, reply) => {\n * if (!request.headers.authorization) {\n * reply.status(401).send({ message: 'Unauthorized' });\n * }\n * },\n * ],\n * });\n * ```\n */\n middlewares?: FastifyMiddleware[];\n}\n\n/**\n * Registers routes onto a Fastify instance.\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 Fastify 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 = Fastify();\n *\n * registerFastifyRoutes(app, {\n * metadata: { path: '/health', method: 'GET' },\n * controller: healthController,\n * });\n * ```\n *\n * @example Multiple routes\n * ```typescript\n * const app = Fastify();\n *\n * registerFastifyRoutes(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 * registerFastifyRoutes(app, userRoutes, {\n * prefix: '/api/v1',\n * });\n * ```\n *\n * @example With middlewares\n * ```typescript\n * registerFastifyRoutes(app, protectedRoutes, {\n * middlewares: [\n * async (request, reply) => {\n * if (!request.headers.authorization) {\n * reply.status(401).send({ message: 'Unauthorized' });\n * }\n * },\n * ],\n * });\n * ```\n *\n * @example Registering from multiple domains\n * ```typescript\n * const app = Fastify();\n *\n * // Public routes\n * registerFastifyRoutes(app, publicRoutes);\n *\n * // API routes with prefix\n * registerFastifyRoutes(app, userRoutes, { prefix: '/api' });\n * registerFastifyRoutes(app, orderRoutes, { prefix: '/api' });\n *\n * await app.listen({ port: 3000 });\n * ```\n */\nexport function registerFastifyRoutes(\n app: FastifyInstance,\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 + toFastifyPath(metadata.path);\n const method = metadata.method.toUpperCase() as HTTPMethods;\n\n const handler: RouteHandlerMethod = async (request, reply) => {\n const rawRequest = extractRequest(request);\n const requestDto = requestDtoFactory(rawRequest);\n const responseDto = await controller.execute(requestDto);\n return sendResponse(reply, responseDto.data);\n };\n\n app.route({\n method,\n url: path,\n preHandler: middlewares,\n handler,\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 type { FastifyError, FastifyReply, FastifyRequest } from 'fastify';\nimport { mapErrorToResponse } from './map-error-to-response';\n\n/**\n * Fastify error handler that maps domain errors to HTTP responses.\n *\n * Apply this to your Fastify app using `setErrorHandler()` to automatically\n * convert domain/use-case errors to appropriate HTTP responses.\n *\n * @example\n * ```typescript\n * import Fastify from 'fastify';\n * import { registerFastifyRoutes, onionErrorHandler } from '@cosmneo/onion-lasagna/backend/frameworks/fastify';\n *\n * const app = Fastify();\n *\n * // Apply error handler\n * app.setErrorHandler(onionErrorHandler);\n *\n * // Register routes\n * registerFastifyRoutes(app, routes);\n *\n * await app.listen({ port: 3000 });\n * ```\n *\n * @example With custom error logging\n * ```typescript\n * app.setErrorHandler((error, request, reply) => {\n * // Log the error\n * request.log.error(error);\n *\n * // Use the onion error handler\n * return onionErrorHandler(error, request, reply);\n * });\n * ```\n */\nexport function onionErrorHandler(\n error: FastifyError | Error,\n _request: FastifyRequest,\n reply: FastifyReply,\n): FastifyReply {\n const { statusCode, body } = mapErrorToResponse(error);\n\n return reply.status(statusCode).send(body);\n}\n"],"mappings":"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","names":[]}
|