@cosmneo/onion-lasagna 0.1.12 → 0.2.1
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/{chunk-TVTA63VN.js → chunk-2BVCU32G.js} +22 -51
- package/dist/chunk-2BVCU32G.js.map +1 -0
- package/dist/{chunk-B5SIIVRK.js → chunk-3BY5RBF2.js} +3 -3
- package/dist/chunk-3BY5RBF2.js.map +1 -0
- package/dist/chunk-3QKQCJSP.js +14 -0
- package/dist/chunk-3QKQCJSP.js.map +1 -0
- package/dist/{chunk-SI7FI7MT.js → chunk-42JMR62O.js} +3 -3
- package/dist/chunk-42JMR62O.js.map +1 -0
- package/dist/{chunk-273YQRYN.js → chunk-A4JUAZK4.js} +3 -3
- package/dist/chunk-A4JUAZK4.js.map +1 -0
- package/dist/{chunk-PWTJLVHY.js → chunk-AUMHMWDD.js} +87 -47
- package/dist/chunk-AUMHMWDD.js.map +1 -0
- package/dist/{chunk-ZEVR3B76.js → chunk-H5TNDC5U.js} +17 -89
- package/dist/chunk-H5TNDC5U.js.map +1 -0
- package/dist/chunk-MF2JDREK.js +168 -0
- package/dist/chunk-MF2JDREK.js.map +1 -0
- package/dist/{chunk-RRXLBGQB.js → chunk-T7S574XQ.js} +68 -4
- package/dist/chunk-T7S574XQ.js.map +1 -0
- package/dist/{chunk-Q5QCTEOD.js → chunk-XIRJ73IO.js} +39 -37
- package/dist/chunk-XIRJ73IO.js.map +1 -0
- package/dist/{chunk-5TNCT634.js → chunk-XP6PLTV2.js} +13 -9
- package/dist/chunk-XP6PLTV2.js.map +1 -0
- package/dist/{chunk-OKFXZHBC.js → chunk-ZG26OQFN.js} +2 -2
- package/dist/chunk-ZG26OQFN.js.map +1 -0
- package/dist/{backend/core/global.cjs → global.cjs} +6 -6
- package/dist/global.cjs.map +1 -0
- package/dist/{backend/core/global.d.cts → global.d.cts} +201 -20
- package/dist/{backend/core/global.d.ts → global.d.ts} +201 -20
- package/dist/global.js +27 -0
- package/dist/http/index.cjs +704 -333
- package/dist/http/index.cjs.map +1 -1
- package/dist/http/index.d.cts +4 -6
- package/dist/http/index.d.ts +4 -6
- package/dist/http/index.js +32 -20
- package/dist/http/openapi/index.cjs +47 -39
- package/dist/http/openapi/index.cjs.map +1 -1
- package/dist/http/openapi/index.d.cts +8 -34
- package/dist/http/openapi/index.d.ts +8 -34
- package/dist/http/openapi/index.js +2 -3
- package/dist/http/route/index.cjs +111 -19
- package/dist/http/route/index.cjs.map +1 -1
- package/dist/http/route/index.d.cts +133 -227
- package/dist/http/route/index.d.ts +133 -227
- package/dist/http/route/index.js +5 -5
- package/dist/http/schema/index.cjs +5 -98
- package/dist/http/schema/index.cjs.map +1 -1
- package/dist/http/schema/index.d.cts +0 -4
- package/dist/http/schema/index.d.ts +0 -4
- package/dist/http/schema/index.js +2 -15
- package/dist/http/schema/types.cjs +3 -3
- package/dist/http/schema/types.cjs.map +1 -1
- package/dist/http/schema/types.js +1 -2
- package/dist/http/server/index.cjs +120 -63
- package/dist/http/server/index.cjs.map +1 -1
- package/dist/http/server/index.d.cts +261 -93
- package/dist/http/server/index.d.ts +261 -93
- package/dist/http/server/index.js +6 -61
- package/dist/http/server/index.js.map +1 -1
- package/dist/http/{frameworks/fastify.cjs → shared/index.cjs} +32 -88
- package/dist/http/shared/index.cjs.map +1 -0
- package/dist/http/shared/index.d.cts +144 -0
- package/dist/http/shared/index.d.ts +144 -0
- package/dist/http/shared/index.js +21 -0
- package/dist/{backend/core/onion-layers.cjs → index.cjs} +93 -42
- package/dist/index.cjs.map +1 -0
- package/dist/{backend/core/onion-layers.d.ts → index.d.cts} +182 -6
- package/dist/{backend/core/onion-layers.d.cts → index.d.ts} +182 -6
- package/dist/{backend/core/onion-layers.js → index.js} +48 -36
- package/dist/index.js.map +1 -0
- package/dist/ports.cjs +19 -0
- package/dist/ports.cjs.map +1 -0
- package/dist/ports.d.cts +250 -0
- package/dist/ports.d.ts +250 -0
- package/dist/ports.js +1 -0
- package/dist/{router-definition.type-B69DjYzf.d.cts → router-definition.type-BElX-Pl4.d.cts} +169 -260
- package/dist/{router-definition.type-29Mmkxs9.d.ts → router-definition.type-DxG8ncJZ.d.ts} +169 -260
- package/dist/types.cjs +19 -0
- package/dist/types.cjs.map +1 -0
- package/dist/types.d.cts +23 -0
- package/dist/types.d.ts +23 -0
- package/dist/types.js +1 -0
- package/package.json +34 -139
- package/dist/backend/core/global.cjs.map +0 -1
- package/dist/backend/core/global.js +0 -35
- package/dist/backend/core/global.js.map +0 -1
- package/dist/backend/core/onion-layers.cjs.map +0 -1
- package/dist/backend/core/onion-layers.js.map +0 -1
- package/dist/backend/core/presentation.cjs +0 -265
- package/dist/backend/core/presentation.cjs.map +0 -1
- package/dist/backend/core/presentation.d.cts +0 -176
- package/dist/backend/core/presentation.d.ts +0 -176
- package/dist/backend/core/presentation.js +0 -16
- package/dist/chunk-273YQRYN.js.map +0 -1
- package/dist/chunk-3WMF4XXN.js +0 -44
- package/dist/chunk-3WMF4XXN.js.map +0 -1
- package/dist/chunk-55ROG54O.js +0 -1
- package/dist/chunk-5TNCT634.js.map +0 -1
- package/dist/chunk-B5SIIVRK.js.map +0 -1
- package/dist/chunk-CGZBV6BD.js +0 -54
- package/dist/chunk-HRS3NSHF.js +0 -51
- package/dist/chunk-HRS3NSHF.js.map +0 -1
- package/dist/chunk-L2SRWSPH.js +0 -216
- package/dist/chunk-L2SRWSPH.js.map +0 -1
- package/dist/chunk-OKFXZHBC.js.map +0 -1
- package/dist/chunk-PWTJLVHY.js.map +0 -1
- package/dist/chunk-Q5QCTEOD.js.map +0 -1
- package/dist/chunk-QN7JZMFW.js +0 -40
- package/dist/chunk-QN7JZMFW.js.map +0 -1
- package/dist/chunk-RRXLBGQB.js.map +0 -1
- package/dist/chunk-SI7FI7MT.js.map +0 -1
- package/dist/chunk-TVTA63VN.js.map +0 -1
- package/dist/chunk-ZEVR3B76.js.map +0 -1
- package/dist/chunk-ZSCB3LKI.js +0 -82
- package/dist/chunk-ZSCB3LKI.js.map +0 -1
- package/dist/create-server-routes-COxEzdnw.d.ts +0 -84
- package/dist/create-server-routes-XBGmav3T.d.cts +0 -84
- package/dist/http/client/index.cjs +0 -257
- package/dist/http/client/index.cjs.map +0 -1
- package/dist/http/client/index.d.cts +0 -89
- package/dist/http/client/index.d.ts +0 -89
- package/dist/http/client/index.js +0 -11
- package/dist/http/frameworks/elysia.cjs +0 -789
- package/dist/http/frameworks/elysia.cjs.map +0 -1
- package/dist/http/frameworks/elysia.d.cts +0 -182
- package/dist/http/frameworks/elysia.d.ts +0 -182
- package/dist/http/frameworks/elysia.js +0 -141
- package/dist/http/frameworks/elysia.js.map +0 -1
- package/dist/http/frameworks/fastify.cjs.map +0 -1
- package/dist/http/frameworks/fastify.d.cts +0 -159
- package/dist/http/frameworks/fastify.d.ts +0 -159
- package/dist/http/frameworks/fastify.js +0 -77
- package/dist/http/frameworks/fastify.js.map +0 -1
- package/dist/http/frameworks/hono.cjs +0 -801
- package/dist/http/frameworks/hono.cjs.map +0 -1
- package/dist/http/frameworks/hono.d.cts +0 -163
- package/dist/http/frameworks/hono.d.ts +0 -163
- package/dist/http/frameworks/hono.js +0 -153
- package/dist/http/frameworks/hono.js.map +0 -1
- package/dist/http/frameworks/nestjs.cjs +0 -267
- package/dist/http/frameworks/nestjs.cjs.map +0 -1
- package/dist/http/frameworks/nestjs.d.cts +0 -201
- package/dist/http/frameworks/nestjs.d.ts +0 -201
- package/dist/http/frameworks/nestjs.js +0 -89
- package/dist/http/frameworks/nestjs.js.map +0 -1
- package/dist/http/react-query/index.cjs +0 -365
- package/dist/http/react-query/index.cjs.map +0 -1
- package/dist/http/react-query/index.d.cts +0 -167
- package/dist/http/react-query/index.d.ts +0 -167
- package/dist/http/react-query/index.js +0 -122
- package/dist/http/react-query/index.js.map +0 -1
- package/dist/http/schema/typebox.cjs +0 -76
- package/dist/http/schema/typebox.cjs.map +0 -1
- package/dist/http/schema/typebox.d.cts +0 -73
- package/dist/http/schema/typebox.d.ts +0 -73
- package/dist/http/schema/typebox.js +0 -10
- package/dist/http/schema/typebox.js.map +0 -1
- package/dist/http/schema/zod.cjs +0 -69
- package/dist/http/schema/zod.cjs.map +0 -1
- package/dist/http/schema/zod.d.cts +0 -77
- package/dist/http/schema/zod.d.ts +0 -77
- package/dist/http/schema/zod.js +0 -10
- package/dist/http/schema/zod.js.map +0 -1
- package/dist/types-CirYpK38.d.ts +0 -262
- package/dist/types-Co3cPRWT.d.cts +0 -262
- package/dist/types-D1yDxONt.d.ts +0 -157
- package/dist/types-DF29z22c.d.cts +0 -157
- package/dist/types-Dw-b8WZ7.d.cts +0 -50
- package/dist/types-Dw-b8WZ7.d.ts +0 -50
- package/dist/validation-error.type-CJLDfv3Q.d.cts +0 -203
- package/dist/validation-error.type-CJLDfv3Q.d.ts +0 -203
- /package/dist/{backend/core/presentation.js.map → global.js.map} +0 -0
- /package/dist/http/{client → shared}/index.js.map +0 -0
- /package/dist/{chunk-55ROG54O.js.map → ports.js.map} +0 -0
- /package/dist/{chunk-CGZBV6BD.js.map → types.js.map} +0 -0
|
@@ -1,40 +1,12 @@
|
|
|
1
|
+
import {
|
|
2
|
+
UseCaseError
|
|
3
|
+
} from "./chunk-T7S574XQ.js";
|
|
1
4
|
import {
|
|
2
5
|
CodedError,
|
|
3
6
|
ErrorCodes
|
|
4
|
-
} from "./chunk-
|
|
5
|
-
|
|
6
|
-
// src/backend/core/onion-layers/app/exceptions/use-case.error.ts
|
|
7
|
-
var UseCaseError = class _UseCaseError extends CodedError {
|
|
8
|
-
/**
|
|
9
|
-
* Creates a new UseCaseError instance.
|
|
10
|
-
*
|
|
11
|
-
* @param options - Error configuration
|
|
12
|
-
* @param options.message - Human-readable error description
|
|
13
|
-
* @param options.code - Machine-readable error code (default: 'USE_CASE_ERROR')
|
|
14
|
-
* @param options.cause - Optional underlying error
|
|
15
|
-
*/
|
|
16
|
-
constructor({
|
|
17
|
-
message,
|
|
18
|
-
code = ErrorCodes.App.USE_CASE_ERROR,
|
|
19
|
-
cause
|
|
20
|
-
}) {
|
|
21
|
-
super({ message, code, cause });
|
|
22
|
-
}
|
|
23
|
-
/**
|
|
24
|
-
* Creates a UseCaseError from a caught error.
|
|
25
|
-
*
|
|
26
|
-
* @param cause - The original caught error
|
|
27
|
-
* @returns A new UseCaseError instance with the cause attached
|
|
28
|
-
*/
|
|
29
|
-
static fromError(cause) {
|
|
30
|
-
return new _UseCaseError({
|
|
31
|
-
message: cause instanceof Error ? cause.message : "Use case error",
|
|
32
|
-
cause
|
|
33
|
-
});
|
|
34
|
-
}
|
|
35
|
-
};
|
|
7
|
+
} from "./chunk-A4JUAZK4.js";
|
|
36
8
|
|
|
37
|
-
// src/
|
|
9
|
+
// src/domain/exceptions/domain.error.ts
|
|
38
10
|
var DomainError = class _DomainError extends CodedError {
|
|
39
11
|
/**
|
|
40
12
|
* Creates a new DomainError instance.
|
|
@@ -65,7 +37,7 @@ var DomainError = class _DomainError extends CodedError {
|
|
|
65
37
|
}
|
|
66
38
|
};
|
|
67
39
|
|
|
68
|
-
// src/
|
|
40
|
+
// src/infra/exceptions/infra.error.ts
|
|
69
41
|
var InfraError = class _InfraError extends CodedError {
|
|
70
42
|
/**
|
|
71
43
|
* Creates a new InfraError instance.
|
|
@@ -96,7 +68,7 @@ var InfraError = class _InfraError extends CodedError {
|
|
|
96
68
|
}
|
|
97
69
|
};
|
|
98
70
|
|
|
99
|
-
// src/
|
|
71
|
+
// src/app/exceptions/not-found.error.ts
|
|
100
72
|
var NotFoundError = class _NotFoundError extends UseCaseError {
|
|
101
73
|
/**
|
|
102
74
|
* Creates a new NotFoundError instance.
|
|
@@ -127,7 +99,7 @@ var NotFoundError = class _NotFoundError extends UseCaseError {
|
|
|
127
99
|
}
|
|
128
100
|
};
|
|
129
101
|
|
|
130
|
-
// src/
|
|
102
|
+
// src/app/exceptions/conflict.error.ts
|
|
131
103
|
var ConflictError = class _ConflictError extends UseCaseError {
|
|
132
104
|
/**
|
|
133
105
|
* Creates a new ConflictError instance.
|
|
@@ -158,7 +130,7 @@ var ConflictError = class _ConflictError extends UseCaseError {
|
|
|
158
130
|
}
|
|
159
131
|
};
|
|
160
132
|
|
|
161
|
-
// src/
|
|
133
|
+
// src/app/exceptions/unprocessable.error.ts
|
|
162
134
|
var UnprocessableError = class _UnprocessableError extends UseCaseError {
|
|
163
135
|
/**
|
|
164
136
|
* Creates a new UnprocessableError instance.
|
|
@@ -189,7 +161,7 @@ var UnprocessableError = class _UnprocessableError extends UseCaseError {
|
|
|
189
161
|
}
|
|
190
162
|
};
|
|
191
163
|
|
|
192
|
-
// src/
|
|
164
|
+
// src/app/exceptions/forbidden.error.ts
|
|
193
165
|
var ForbiddenError = class _ForbiddenError extends UseCaseError {
|
|
194
166
|
/**
|
|
195
167
|
* Creates a new ForbiddenError instance.
|
|
@@ -220,45 +192,44 @@ var ForbiddenError = class _ForbiddenError extends UseCaseError {
|
|
|
220
192
|
}
|
|
221
193
|
};
|
|
222
194
|
|
|
223
|
-
// src/
|
|
224
|
-
var
|
|
195
|
+
// src/presentation/exceptions/access-denied.error.ts
|
|
196
|
+
var AccessDeniedError = class _AccessDeniedError extends CodedError {
|
|
225
197
|
/**
|
|
226
|
-
* Creates a new
|
|
198
|
+
* Creates a new AccessDeniedError instance.
|
|
227
199
|
*
|
|
228
200
|
* @param options - Error configuration
|
|
229
|
-
* @param options.message - Description of why
|
|
230
|
-
* @param options.code - Machine-readable error code (default: '
|
|
201
|
+
* @param options.message - Description of why access was denied
|
|
202
|
+
* @param options.code - Machine-readable error code (default: 'ACCESS_DENIED')
|
|
231
203
|
* @param options.cause - Optional underlying error
|
|
232
204
|
*/
|
|
233
205
|
constructor({
|
|
234
206
|
message,
|
|
235
|
-
code = ErrorCodes.
|
|
207
|
+
code = ErrorCodes.Presentation.ACCESS_DENIED,
|
|
236
208
|
cause
|
|
237
209
|
}) {
|
|
238
210
|
super({ message, code, cause });
|
|
239
211
|
}
|
|
240
212
|
/**
|
|
241
|
-
* Creates an
|
|
213
|
+
* Creates an AccessDeniedError from a caught error.
|
|
242
214
|
*
|
|
243
215
|
* @param cause - The original caught error
|
|
244
|
-
* @returns A new
|
|
216
|
+
* @returns A new AccessDeniedError instance with the cause attached
|
|
245
217
|
*/
|
|
246
218
|
static fromError(cause) {
|
|
247
|
-
return new
|
|
248
|
-
message: cause instanceof Error ? cause.message : "
|
|
219
|
+
return new _AccessDeniedError({
|
|
220
|
+
message: cause instanceof Error ? cause.message : "Access denied",
|
|
249
221
|
cause
|
|
250
222
|
});
|
|
251
223
|
}
|
|
252
224
|
};
|
|
253
225
|
|
|
254
226
|
export {
|
|
255
|
-
UseCaseError,
|
|
256
227
|
DomainError,
|
|
257
228
|
InfraError,
|
|
258
229
|
NotFoundError,
|
|
259
230
|
ConflictError,
|
|
260
231
|
UnprocessableError,
|
|
261
232
|
ForbiddenError,
|
|
262
|
-
|
|
233
|
+
AccessDeniedError
|
|
263
234
|
};
|
|
264
|
-
//# sourceMappingURL=chunk-
|
|
235
|
+
//# sourceMappingURL=chunk-2BVCU32G.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/domain/exceptions/domain.error.ts","../src/infra/exceptions/infra.error.ts","../src/app/exceptions/not-found.error.ts","../src/app/exceptions/conflict.error.ts","../src/app/exceptions/unprocessable.error.ts","../src/app/exceptions/forbidden.error.ts","../src/presentation/exceptions/access-denied.error.ts"],"sourcesContent":["import { CodedError } from '../../global/exceptions/coded-error.error';\nimport { ErrorCodes, type DomainErrorCode } from '../../global/exceptions/error-codes.const';\n\n/**\n * Base error class for domain layer failures.\n *\n * Domain errors represent violations of business rules, invariants,\n * or aggregate consistency. They originate from the core domain logic\n * and should be caught and handled by the application layer.\n *\n * **When to throw:**\n * - Business rule violations (e.g., \"Cannot withdraw more than balance\")\n * - Invariant violations (e.g., \"Email format invalid\")\n * - Aggregate consistency failures\n *\n * **Child classes:**\n * - {@link InvariantViolationError} - Value object or entity invariant failures\n * - {@link PartialLoadError} - Incomplete aggregate reconstitution\n *\n * @example\n * ```typescript\n * if (account.balance < amount) {\n * throw new DomainError({\n * message: 'Insufficient funds for withdrawal',\n * code: 'INSUFFICIENT_FUNDS',\n * });\n * }\n * ```\n */\nexport class DomainError extends CodedError {\n /**\n * Creates a new DomainError instance.\n *\n * @param options - Error configuration\n * @param options.message - Human-readable error description\n * @param options.code - Machine-readable error code (default: 'DOMAIN_ERROR')\n * @param options.cause - Optional underlying error\n */\n constructor({\n message,\n code = ErrorCodes.Domain.DOMAIN_ERROR,\n cause,\n }: {\n message: string;\n code?: DomainErrorCode | string;\n cause?: unknown;\n }) {\n super({ message, code, cause });\n }\n\n /**\n * Creates a DomainError from a caught error.\n *\n * @param cause - The original caught error\n * @returns A new DomainError instance with the cause attached\n */\n static override fromError(cause: unknown): DomainError {\n return new DomainError({\n message: cause instanceof Error ? cause.message : 'Domain error',\n cause,\n });\n }\n}\n","import { CodedError } from '../../global/exceptions/coded-error.error';\nimport { ErrorCodes, type InfraErrorCode } from '../../global/exceptions/error-codes.const';\n\n/**\n * Base error class for infrastructure layer failures.\n *\n * Infrastructure errors represent failures in external dependencies\n * such as databases, network services, file systems, or third-party APIs.\n * They are automatically created by {@link BaseOutboundAdapter} when\n * repository or gateway methods fail.\n *\n * **When to throw:**\n * - Database connection or query failures\n * - Network timeouts or connection errors\n * - External API failures\n * - File system errors\n *\n * **Child classes:**\n * - {@link DbError} - Database operation failures\n * - {@link NetworkError} - Network connectivity issues\n * - {@link TimeoutError} - Operation timeout\n * - {@link ExternalServiceError} - Third-party service failures\n *\n * @example\n * ```typescript\n * // In a repository extending BaseOutboundAdapter\n * protected override createInfraError(error: unknown, methodName: string): InfraError {\n * return new DbError({\n * message: `Database error in ${methodName}`,\n * cause: error,\n * });\n * }\n * ```\n */\nexport class InfraError extends CodedError {\n /**\n * Creates a new InfraError instance.\n *\n * @param options - Error configuration\n * @param options.message - Human-readable error description\n * @param options.code - Machine-readable error code (default: 'INFRA_ERROR')\n * @param options.cause - Optional underlying error\n */\n constructor({\n message,\n code = ErrorCodes.Infra.INFRA_ERROR,\n cause,\n }: {\n message: string;\n code?: InfraErrorCode | string;\n cause?: unknown;\n }) {\n super({ message, code, cause });\n }\n\n /**\n * Creates an InfraError from a caught error.\n *\n * @param cause - The original caught error\n * @returns A new InfraError instance with the cause attached\n */\n static override fromError(cause: unknown): InfraError {\n return new InfraError({\n message: cause instanceof Error ? cause.message : 'Infrastructure error',\n cause,\n });\n }\n}\n","import { ErrorCodes, type AppErrorCode } from '../../global/exceptions/error-codes.const';\nimport { UseCaseError } from './use-case.error';\n\n/**\n * Error thrown when a requested resource does not exist.\n *\n * Indicates that the entity or resource referenced by the request\n * could not be found in the system.\n *\n * **When to throw:**\n * - Entity lookup by ID returns null\n * - Referenced resource doesn't exist\n * - Parent entity for a child operation not found\n *\n * @example\n * ```typescript\n * const user = await this.userRepo.findById(userId);\n * if (!user) {\n * throw new NotFoundError({\n * message: `User with ID ${userId} not found`,\n * code: 'USER_NOT_FOUND',\n * });\n * }\n * ```\n *\n * @extends UseCaseError\n */\nexport class NotFoundError extends UseCaseError {\n /**\n * Creates a new NotFoundError instance.\n *\n * @param options - Error configuration\n * @param options.message - Description of what was not found\n * @param options.code - Machine-readable error code (default: 'NOT_FOUND')\n * @param options.cause - Optional underlying error\n */\n constructor({\n message,\n code = ErrorCodes.App.NOT_FOUND,\n cause,\n }: {\n message: string;\n code?: AppErrorCode | string;\n cause?: unknown;\n }) {\n super({ message, code, cause });\n }\n\n /**\n * Creates a NotFoundError from a caught error.\n *\n * @param cause - The original caught error\n * @returns A new NotFoundError instance with the cause attached\n */\n static override fromError(cause: unknown): NotFoundError {\n return new NotFoundError({\n message: cause instanceof Error ? cause.message : 'Resource not found',\n cause,\n });\n }\n}\n","import { ErrorCodes, type AppErrorCode } from '../../global/exceptions/error-codes.const';\nimport { UseCaseError } from './use-case.error';\n\n/**\n * Error thrown when an operation conflicts with existing state.\n *\n * Indicates that the requested operation cannot be completed because\n * it would violate uniqueness constraints or cause state conflicts.\n *\n * **When to throw:**\n * - Duplicate unique field (e.g., email already registered)\n * - Optimistic locking conflict (stale version)\n * - Concurrent modification detected\n *\n * @example\n * ```typescript\n * const existing = await this.userRepo.findByEmail(email);\n * if (existing) {\n * throw new ConflictError({\n * message: 'Email already registered',\n * code: 'EMAIL_ALREADY_EXISTS',\n * });\n * }\n * ```\n *\n * @extends UseCaseError\n */\nexport class ConflictError extends UseCaseError {\n /**\n * Creates a new ConflictError instance.\n *\n * @param options - Error configuration\n * @param options.message - Description of the conflict\n * @param options.code - Machine-readable error code (default: 'CONFLICT')\n * @param options.cause - Optional underlying error\n */\n constructor({\n message,\n code = ErrorCodes.App.CONFLICT,\n cause,\n }: {\n message: string;\n code?: AppErrorCode | string;\n cause?: unknown;\n }) {\n super({ message, code, cause });\n }\n\n /**\n * Creates a ConflictError from a caught error.\n *\n * @param cause - The original caught error\n * @returns A new ConflictError instance with the cause attached\n */\n static override fromError(cause: unknown): ConflictError {\n return new ConflictError({\n message: cause instanceof Error ? cause.message : 'Conflict error',\n cause,\n });\n }\n}\n","import { ErrorCodes, type AppErrorCode } from '../../global/exceptions/error-codes.const';\nimport { UseCaseError } from './use-case.error';\n\n/**\n * Error thrown when a request is valid but cannot be processed.\n *\n * The request is syntactically correct and passes validation, but\n * business logic prevents the operation from being completed.\n *\n * **When to throw:**\n * - Business rule prevents operation (e.g., insufficient balance)\n * - Invalid state transition (e.g., canceling a completed order)\n * - Preconditions not met for the operation\n *\n * @example\n * ```typescript\n * if (account.balance < amount) {\n * throw new UnprocessableError({\n * message: 'Insufficient balance for withdrawal',\n * code: 'INSUFFICIENT_BALANCE',\n * });\n * }\n * ```\n *\n * @extends UseCaseError\n */\nexport class UnprocessableError extends UseCaseError {\n /**\n * Creates a new UnprocessableError instance.\n *\n * @param options - Error configuration\n * @param options.message - Description of why the request cannot be processed\n * @param options.code - Machine-readable error code (default: 'UNPROCESSABLE')\n * @param options.cause - Optional underlying error\n */\n constructor({\n message,\n code = ErrorCodes.App.UNPROCESSABLE,\n cause,\n }: {\n message: string;\n code?: AppErrorCode | string;\n cause?: unknown;\n }) {\n super({ message, code, cause });\n }\n\n /**\n * Creates an UnprocessableError from a caught error.\n *\n * @param cause - The original caught error\n * @returns A new UnprocessableError instance with the cause attached\n */\n static override fromError(cause: unknown): UnprocessableError {\n return new UnprocessableError({\n message: cause instanceof Error ? cause.message : 'Unprocessable request',\n cause,\n });\n }\n}\n","import { ErrorCodes, type AppErrorCode } from '../../global/exceptions/error-codes.const';\nimport { UseCaseError } from './use-case.error';\n\n/**\n * Error thrown when authorization for an operation is denied.\n *\n * Indicates that the user is authenticated but lacks permission to perform\n * the requested operation. Commonly thrown from the `authorize()` method\n * of use cases when access checks fail.\n *\n * **When to throw:**\n * - User doesn't own the resource they're trying to modify\n * - User lacks required role or permission\n * - Organization/tenant isolation violation\n * - Business rule restricts the operation for this user\n *\n * **Difference from AccessDeniedError:**\n * - `ForbiddenError` is an application layer error (use case authorization)\n * - `AccessDeniedError` is a presentation layer error (controller/guard level)\n *\n * @example Use case authorization\n * ```typescript\n * class UpdateActivityUseCase extends BaseInboundAdapter<Input, Output, AuthContext> {\n * protected async authorize(input: Input): Promise<AuthContext> {\n * const activity = await this.activityRepo.findById(input.activityId);\n * if (!activity) {\n * throw new NotFoundError({ message: 'Activity not found' });\n * }\n * if (activity.organizationId !== input.organizationId) {\n * throw new ForbiddenError({\n * message: 'Not authorized to modify this activity',\n * code: 'ACTIVITY_ACCESS_DENIED',\n * });\n * }\n * return { activity };\n * }\n * }\n * ```\n *\n * @example Role-based authorization\n * ```typescript\n * if (!user.roles.includes('admin')) {\n * throw new ForbiddenError({\n * message: 'Admin role required for this operation',\n * });\n * }\n * ```\n *\n * @extends UseCaseError\n */\nexport class ForbiddenError extends UseCaseError {\n /**\n * Creates a new ForbiddenError instance.\n *\n * @param options - Error configuration\n * @param options.message - Description of why authorization was denied\n * @param options.code - Machine-readable error code (default: 'FORBIDDEN')\n * @param options.cause - Optional underlying error\n */\n constructor({\n message,\n code = ErrorCodes.App.FORBIDDEN,\n cause,\n }: {\n message: string;\n code?: AppErrorCode | string;\n cause?: unknown;\n }) {\n super({ message, code, cause });\n }\n\n /**\n * Creates a ForbiddenError from a caught error.\n *\n * @param cause - The original caught error\n * @returns A new ForbiddenError instance with the cause attached\n */\n static override fromError(cause: unknown): ForbiddenError {\n return new ForbiddenError({\n message: cause instanceof Error ? cause.message : 'Operation forbidden',\n cause,\n });\n }\n}\n","import { CodedError } from '../../global/exceptions/coded-error.error';\nimport { ErrorCodes, type PresentationErrorCode } from '../../global/exceptions/error-codes.const';\n\n/**\n * Error thrown when access to a resource is denied.\n *\n * Indicates that the requester does not have permission to perform\n * the requested operation. Thrown by {@link GuardedController} when\n * an access guard returns `isAllowed: false`.\n *\n * **When thrown:**\n * - Access guard denies the request\n * - User lacks required permissions\n * - Resource ownership check fails\n *\n * @example GuardedController usage\n * ```typescript\n * const controller = GuardedController.create({\n * accessGuard: (req) => ({\n * isAllowed: req.user?.role === 'admin',\n * reason: 'Admin access required',\n * }),\n * // ... other config\n * });\n * ```\n *\n * @example Manual usage\n * ```typescript\n * if (!user.canAccess(resource)) {\n * throw new AccessDeniedError({\n * message: 'You do not have access to this resource',\n * code: 'RESOURCE_ACCESS_DENIED',\n * });\n * }\n * ```\n *\n * @extends CodedError\n */\nexport class AccessDeniedError extends CodedError {\n /**\n * Creates a new AccessDeniedError instance.\n *\n * @param options - Error configuration\n * @param options.message - Description of why access was denied\n * @param options.code - Machine-readable error code (default: 'ACCESS_DENIED')\n * @param options.cause - Optional underlying error\n */\n constructor({\n message,\n code = ErrorCodes.Presentation.ACCESS_DENIED,\n cause,\n }: {\n message: string;\n code?: PresentationErrorCode | string;\n cause?: unknown;\n }) {\n super({ message, code, cause });\n }\n\n /**\n * Creates an AccessDeniedError from a caught error.\n *\n * @param cause - The original caught error\n * @returns A new AccessDeniedError instance with the cause attached\n */\n static override fromError(cause: unknown): AccessDeniedError {\n return new AccessDeniedError({\n message: cause instanceof Error ? cause.message : 'Access denied',\n cause,\n });\n }\n}\n"],"mappings":";;;;;;;;;AA6BO,IAAM,cAAN,MAAM,qBAAoB,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAS1C,YAAY;AAAA,IACV;AAAA,IACA,OAAO,WAAW,OAAO;AAAA,IACzB;AAAA,EACF,GAIG;AACD,UAAM,EAAE,SAAS,MAAM,MAAM,CAAC;AAAA,EAChC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,OAAgB,UAAU,OAA6B;AACrD,WAAO,IAAI,aAAY;AAAA,MACrB,SAAS,iBAAiB,QAAQ,MAAM,UAAU;AAAA,MAClD;AAAA,IACF,CAAC;AAAA,EACH;AACF;;;AC5BO,IAAM,aAAN,MAAM,oBAAmB,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASzC,YAAY;AAAA,IACV;AAAA,IACA,OAAO,WAAW,MAAM;AAAA,IACxB;AAAA,EACF,GAIG;AACD,UAAM,EAAE,SAAS,MAAM,MAAM,CAAC;AAAA,EAChC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,OAAgB,UAAU,OAA4B;AACpD,WAAO,IAAI,YAAW;AAAA,MACpB,SAAS,iBAAiB,QAAQ,MAAM,UAAU;AAAA,MAClD;AAAA,IACF,CAAC;AAAA,EACH;AACF;;;ACxCO,IAAM,gBAAN,MAAM,uBAAsB,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAS9C,YAAY;AAAA,IACV;AAAA,IACA,OAAO,WAAW,IAAI;AAAA,IACtB;AAAA,EACF,GAIG;AACD,UAAM,EAAE,SAAS,MAAM,MAAM,CAAC;AAAA,EAChC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,OAAgB,UAAU,OAA+B;AACvD,WAAO,IAAI,eAAc;AAAA,MACvB,SAAS,iBAAiB,QAAQ,MAAM,UAAU;AAAA,MAClD;AAAA,IACF,CAAC;AAAA,EACH;AACF;;;ACjCO,IAAM,gBAAN,MAAM,uBAAsB,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAS9C,YAAY;AAAA,IACV;AAAA,IACA,OAAO,WAAW,IAAI;AAAA,IACtB;AAAA,EACF,GAIG;AACD,UAAM,EAAE,SAAS,MAAM,MAAM,CAAC;AAAA,EAChC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,OAAgB,UAAU,OAA+B;AACvD,WAAO,IAAI,eAAc;AAAA,MACvB,SAAS,iBAAiB,QAAQ,MAAM,UAAU;AAAA,MAClD;AAAA,IACF,CAAC;AAAA,EACH;AACF;;;AClCO,IAAM,qBAAN,MAAM,4BAA2B,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASnD,YAAY;AAAA,IACV;AAAA,IACA,OAAO,WAAW,IAAI;AAAA,IACtB;AAAA,EACF,GAIG;AACD,UAAM,EAAE,SAAS,MAAM,MAAM,CAAC;AAAA,EAChC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,OAAgB,UAAU,OAAoC;AAC5D,WAAO,IAAI,oBAAmB;AAAA,MAC5B,SAAS,iBAAiB,QAAQ,MAAM,UAAU;AAAA,MAClD;AAAA,IACF,CAAC;AAAA,EACH;AACF;;;ACTO,IAAM,iBAAN,MAAM,wBAAuB,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAS/C,YAAY;AAAA,IACV;AAAA,IACA,OAAO,WAAW,IAAI;AAAA,IACtB;AAAA,EACF,GAIG;AACD,UAAM,EAAE,SAAS,MAAM,MAAM,CAAC;AAAA,EAChC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,OAAgB,UAAU,OAAgC;AACxD,WAAO,IAAI,gBAAe;AAAA,MACxB,SAAS,iBAAiB,QAAQ,MAAM,UAAU;AAAA,MAClD;AAAA,IACF,CAAC;AAAA,EACH;AACF;;;AC7CO,IAAM,oBAAN,MAAM,2BAA0B,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAShD,YAAY;AAAA,IACV;AAAA,IACA,OAAO,WAAW,aAAa;AAAA,IAC/B;AAAA,EACF,GAIG;AACD,UAAM,EAAE,SAAS,MAAM,MAAM,CAAC;AAAA,EAChC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,OAAgB,UAAU,OAAmC;AAC3D,WAAO,IAAI,mBAAkB;AAAA,MAC3B,SAAS,iBAAiB,QAAQ,MAAM,UAAU;AAAA,MAClD;AAAA,IACF,CAAC;AAAA,EACH;AACF;","names":[]}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
CodedError,
|
|
3
3
|
ErrorCodes
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-A4JUAZK4.js";
|
|
5
5
|
|
|
6
|
-
// src/
|
|
6
|
+
// src/global/exceptions/object-validation.error.ts
|
|
7
7
|
var ObjectValidationError = class _ObjectValidationError extends CodedError {
|
|
8
8
|
/**
|
|
9
9
|
* Array of field-level validation errors.
|
|
@@ -49,4 +49,4 @@ var ObjectValidationError = class _ObjectValidationError extends CodedError {
|
|
|
49
49
|
export {
|
|
50
50
|
ObjectValidationError
|
|
51
51
|
};
|
|
52
|
-
//# sourceMappingURL=chunk-
|
|
52
|
+
//# sourceMappingURL=chunk-3BY5RBF2.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/global/exceptions/object-validation.error.ts"],"sourcesContent":["import { CodedError } from './coded-error.error';\nimport { ErrorCodes, type GlobalErrorCode } from './error-codes.const';\nimport type { ValidationError } from '../interfaces/types/validation-error.type';\n\n/**\n * Error thrown when object validation fails.\n *\n * Contains structured validation errors with field paths and messages,\n * making it easy to report specific validation failures to clients.\n * Thrown by all validator implementations (Zod, ArkType, TypeBox, Valibot).\n *\n * **Flow:**\n * 1. Validator throws `ObjectValidationError` with field-level errors\n * 2. Controller catches and converts to {@link InvalidRequestError}\n * 3. HTTP layer maps to 400 Bad Request with error details\n *\n * @example\n * ```typescript\n * try {\n * const dto = CreateUserDto.create(invalidData);\n * } catch (error) {\n * if (error instanceof ObjectValidationError) {\n * console.log(error.validationErrors);\n * // [\n * // { field: 'email', message: 'Invalid email format' },\n * // { field: 'age', message: 'Must be a positive number' }\n * // ]\n * }\n * }\n * ```\n */\nexport class ObjectValidationError extends CodedError {\n /**\n * Array of field-level validation errors.\n *\n * Each entry contains:\n * - `field`: Dot-notation path to the invalid field (e.g., 'user.email')\n * - `message`: Human-readable validation failure message\n */\n validationErrors: ValidationError[];\n\n /**\n * Creates a new ObjectValidationError instance.\n *\n * @param options - Error configuration\n * @param options.message - Human-readable summary message\n * @param options.code - Machine-readable error code (default: 'OBJECT_VALIDATION_ERROR')\n * @param options.cause - Optional underlying error from validation library\n * @param options.validationErrors - Array of field-level validation errors\n */\n constructor({\n message,\n code = ErrorCodes.Global.OBJECT_VALIDATION_ERROR,\n cause,\n validationErrors,\n }: {\n message: string;\n code?: GlobalErrorCode | string;\n cause?: unknown;\n validationErrors: ValidationError[];\n }) {\n super({ message, code, cause });\n this.validationErrors = validationErrors;\n }\n\n /**\n * Creates an ObjectValidationError from a caught error.\n *\n * @param cause - The original caught error\n * @returns A new ObjectValidationError instance with the cause attached\n */\n static override fromError(cause: unknown): ObjectValidationError {\n return new ObjectValidationError({\n message: cause instanceof Error ? cause.message : 'Validation failed',\n cause,\n validationErrors: [],\n });\n }\n}\n"],"mappings":";;;;;;AA+BO,IAAM,wBAAN,MAAM,+BAA8B,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQpD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,YAAY;AAAA,IACV;AAAA,IACA,OAAO,WAAW,OAAO;AAAA,IACzB;AAAA,IACA;AAAA,EACF,GAKG;AACD,UAAM,EAAE,SAAS,MAAM,MAAM,CAAC;AAC9B,SAAK,mBAAmB;AAAA,EAC1B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,OAAgB,UAAU,OAAuC;AAC/D,WAAO,IAAI,uBAAsB;AAAA,MAC/B,SAAS,iBAAiB,QAAQ,MAAM,UAAU;AAAA,MAClD;AAAA,MACA,kBAAkB,CAAC;AAAA,IACrB,CAAC;AAAA,EACH;AACF;","names":[]}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// src/global/utils/field-changed.util.ts
|
|
2
|
+
function fieldChanged({
|
|
3
|
+
value,
|
|
4
|
+
newValue,
|
|
5
|
+
partialUpdate = true
|
|
6
|
+
}) {
|
|
7
|
+
if (partialUpdate && newValue === void 0) return false;
|
|
8
|
+
return value !== newValue;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export {
|
|
12
|
+
fieldChanged
|
|
13
|
+
};
|
|
14
|
+
//# sourceMappingURL=chunk-3QKQCJSP.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/global/utils/field-changed.util.ts"],"sourcesContent":["/**\n * Checks if a field has changed by comparing the current value with a new value.\n *\n * Useful for detecting changes in update operations, supporting both partial\n * and full update semantics.\n *\n * **Modes:**\n * - **Partial update** (default): `undefined` means \"keep existing value\" (no change)\n * - **Full update**: `undefined` means \"set to undefined\" (is a change if value !== undefined)\n *\n * **Limitation:** Uses strict equality (`!==`) for comparison, which only works\n * correctly for primitives and reference equality. For objects or arrays, this\n * compares references, not content. Two objects with identical content but\n * different references will be considered \"changed\".\n *\n * For complex objects, either:\n * - Compare by a unique identifier (e.g., `value.id !== newValue?.id`)\n * - Use value objects with `.equals()` methods\n * - Implement deep equality checking in your update logic\n *\n * @typeParam T - The type of the field being compared\n * @param options - Comparison options\n * @param options.value - The current field value\n * @param options.newValue - The incoming value (may be undefined)\n * @param options.partialUpdate - Whether to use partial update semantics (default: true)\n * @returns `true` if the field has changed, `false` otherwise\n *\n * @example Partial update (PATCH semantics)\n * ```typescript\n * // undefined means \"don't change\"\n * fieldChanged({ value: 'John', newValue: undefined }); // false\n * fieldChanged({ value: 'John', newValue: 'Jane' }); // true\n * fieldChanged({ value: 'John', newValue: 'John' }); // false\n * ```\n *\n * @example Full update (PUT semantics)\n * ```typescript\n * // undefined means \"set to undefined\"\n * fieldChanged({ value: 'John', newValue: undefined, partialUpdate: false }); // true\n * ```\n *\n * @example Object comparison (reference-based)\n * ```typescript\n * const obj1 = { name: 'John' };\n * const obj2 = { name: 'John' };\n * fieldChanged({ value: obj1, newValue: obj2 }); // true (different references)\n * fieldChanged({ value: obj1, newValue: obj1 }); // false (same reference)\n * ```\n */\nexport function fieldChanged<T>({\n value,\n newValue,\n partialUpdate = true,\n}: {\n value: T;\n newValue: T | undefined;\n partialUpdate?: boolean;\n}): boolean {\n if (partialUpdate && newValue === undefined) return false;\n // For full updates, undefined means \"set to undefined\" which is a change if value !== undefined\n return value !== newValue;\n}\n"],"mappings":";AAiDO,SAAS,aAAgB;AAAA,EAC9B;AAAA,EACA;AAAA,EACA,gBAAgB;AAClB,GAIY;AACV,MAAI,iBAAiB,aAAa,OAAW,QAAO;AAEpD,SAAO,UAAU;AACnB;","names":[]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// src/
|
|
1
|
+
// src/presentation/http/schema/types/validation.type.ts
|
|
2
2
|
function isValidationSuccess(result) {
|
|
3
3
|
return result.success === true;
|
|
4
4
|
}
|
|
@@ -6,7 +6,7 @@ function isValidationFailure(result) {
|
|
|
6
6
|
return result.success === false;
|
|
7
7
|
}
|
|
8
8
|
|
|
9
|
-
// src/
|
|
9
|
+
// src/presentation/http/schema/types/schema-adapter.type.ts
|
|
10
10
|
function isSchemaAdapter(value) {
|
|
11
11
|
return typeof value === "object" && value !== null && "validate" in value && typeof value.validate === "function" && "toJsonSchema" in value && typeof value.toJsonSchema === "function";
|
|
12
12
|
}
|
|
@@ -37,4 +37,4 @@ export {
|
|
|
37
37
|
createPassthroughAdapter,
|
|
38
38
|
createRejectingAdapter
|
|
39
39
|
};
|
|
40
|
-
//# sourceMappingURL=chunk-
|
|
40
|
+
//# sourceMappingURL=chunk-42JMR62O.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/presentation/http/schema/types/validation.type.ts","../src/presentation/http/schema/types/schema-adapter.type.ts"],"sourcesContent":["/**\n * @fileoverview Validation result types for schema adapters.\n *\n * These types represent the outcome of schema validation operations,\n * providing a consistent interface across all validation libraries.\n *\n * @module unified/schema/types/validation\n */\n\n/**\n * Represents a single validation error with path and message.\n */\nexport interface ValidationIssue {\n /**\n * Path to the invalid value in the data structure.\n * Empty array indicates the root value is invalid.\n *\n * @example ['body', 'user', 'email'] - nested object path\n * @example ['items', '0', 'name'] - array element path\n * @example [] - root level error\n */\n readonly path: readonly string[];\n\n /**\n * Human-readable error message describing the validation failure.\n */\n readonly message: string;\n\n /**\n * Optional error code for programmatic handling.\n * Codes are library-specific but follow common patterns:\n * - 'required' - missing required field\n * - 'type' - wrong type\n * - 'format' - invalid format (email, uuid, etc.)\n * - 'minimum' / 'maximum' - number out of range\n * - 'minLength' / 'maxLength' - string length violation\n * - 'pattern' - regex pattern mismatch\n * - 'enum' - value not in allowed list\n */\n readonly code?: string;\n\n /**\n * Expected type or value (when available).\n */\n readonly expected?: string;\n\n /**\n * Received type or value (when available).\n */\n readonly received?: string;\n}\n\n/**\n * Successful validation result containing the validated and typed data.\n */\nexport interface ValidationSuccess<T> {\n readonly success: true;\n readonly data: T;\n}\n\n/**\n * Failed validation result containing all validation issues.\n */\nexport interface ValidationFailure {\n readonly success: false;\n readonly issues: readonly ValidationIssue[];\n}\n\n/**\n * Result of a schema validation operation.\n * Discriminated union that allows type-safe handling of success/failure cases.\n *\n * @example\n * ```typescript\n * const result = schema.validate(data);\n * if (result.success) {\n * // result.data is typed as T\n * console.log(result.data);\n * } else {\n * // result.issues contains validation errors\n * console.log(result.issues);\n * }\n * ```\n */\nexport type ValidationResult<T> = ValidationSuccess<T> | ValidationFailure;\n\n/**\n * Type guard to check if a validation result is successful.\n */\nexport function isValidationSuccess<T>(\n result: ValidationResult<T>,\n): result is ValidationSuccess<T> {\n return result.success === true;\n}\n\n/**\n * Type guard to check if a validation result is a failure.\n */\nexport function isValidationFailure<T>(result: ValidationResult<T>): result is ValidationFailure {\n return result.success === false;\n}\n","/**\n * @fileoverview Schema adapter interface for validation library abstraction.\n *\n * The SchemaAdapter interface provides a unified API for working with\n * different validation libraries (Zod, TypeBox, Valibot, ArkType).\n * Each adapter wraps a library-specific schema and provides:\n * - Runtime validation\n * - JSON Schema conversion for OpenAPI\n * - TypeScript type inference via phantom types\n *\n * @module unified/schema/types/schema-adapter\n */\n\nimport type { JsonSchema } from './json-schema.type';\nimport type { ValidationResult } from './validation.type';\n\n/**\n * Schema adapter interface that abstracts validation library specifics.\n *\n * This interface is the core abstraction that enables the unified route\n * system to work with any validation library. Implementations wrap a\n * library-specific schema (Zod, TypeBox, etc.) and provide a consistent API.\n *\n * @typeParam TOutput - The TypeScript type of successfully validated data.\n * For schemas with transforms, this is the output type.\n * @typeParam TInput - The TypeScript type expected as input (before transforms).\n * Defaults to TOutput for schemas without transforms.\n *\n * @example Creating an adapter (using Zod)\n * ```typescript\n * import { z } from 'zod';\n * import { zodSchema } from '@cosmneo/onion-lasagna/http/schema/zod';\n *\n * const userSchema = zodSchema(z.object({\n * name: z.string().min(1),\n * email: z.string().email(),\n * }));\n *\n * // Validate data\n * const result = userSchema.validate(input);\n * if (result.success) {\n * // result.data is typed as { name: string; email: string }\n * }\n *\n * // Get JSON Schema for OpenAPI\n * const jsonSchema = userSchema.toJsonSchema();\n * ```\n */\nexport interface SchemaAdapter<TOutput = unknown, TInput = TOutput> {\n /**\n * Validates unknown data against the schema.\n *\n * This method performs full validation including:\n * - Type checking\n * - Constraint validation (min/max, patterns, etc.)\n * - Nested object/array validation\n * - Custom validations defined in the schema\n *\n * For schemas with transforms, the returned data will be the transformed value.\n *\n * @param data - Unknown data to validate\n * @returns Validation result with typed data on success or issues on failure\n *\n * @example\n * ```typescript\n * const result = schema.validate({ name: 'John', age: 25 });\n * if (result.success) {\n * console.log(result.data.name); // TypeScript knows this is a string\n * } else {\n * console.log(result.issues); // Array of validation errors\n * }\n * ```\n */\n validate(data: unknown): ValidationResult<TOutput>;\n\n /**\n * Converts the schema to JSON Schema format for OpenAPI generation.\n *\n * The returned schema should be compatible with JSON Schema Draft 7\n * and OpenAPI 3.0/3.1 specifications. Complex schemas with transforms\n * or refinements may produce simplified JSON Schema representations.\n *\n * @param options - Optional configuration for schema generation\n * @returns JSON Schema representation of this schema\n *\n * @example\n * ```typescript\n * const jsonSchema = schema.toJsonSchema();\n * // {\n * // type: 'object',\n * // properties: {\n * // name: { type: 'string', minLength: 1 },\n * // email: { type: 'string', format: 'email' }\n * // },\n * // required: ['name', 'email']\n * // }\n * ```\n */\n toJsonSchema(options?: JsonSchemaOptions): JsonSchema;\n\n /**\n * Phantom type marker for output type inference.\n * This property is never accessed at runtime - it exists only for TypeScript.\n *\n * @internal\n */\n readonly _output: TOutput;\n\n /**\n * Phantom type marker for input type inference.\n * This property is never accessed at runtime - it exists only for TypeScript.\n * Useful for schemas with transforms where input and output types differ.\n *\n * @internal\n */\n readonly _input: TInput;\n\n /**\n * Optional: Reference to the underlying schema for advanced use cases.\n * The type depends on the validation library being used.\n *\n * @internal\n */\n readonly _schema?: unknown;\n}\n\n/**\n * Options for JSON Schema generation.\n */\nexport interface JsonSchemaOptions {\n /**\n * Strategy for handling $ref references.\n * - 'none': Inline all schemas, no $refs\n * - 'root': Create $refs only at the root level\n * - 'all': Use $refs wherever possible (most compact)\n *\n * @default 'none'\n */\n readonly refStrategy?: 'none' | 'root' | 'all';\n\n /**\n * Base path for $ref references.\n * @default '#/$defs/'\n */\n readonly basePath?: string;\n\n /**\n * Custom definitions to include in the schema.\n */\n readonly definitions?: Record<string, JsonSchema>;\n\n /**\n * Whether to include schema metadata (title, description, etc.).\n * @default true\n */\n readonly includeMetadata?: boolean;\n}\n\n/**\n * Infers the output type from a SchemaAdapter.\n *\n * @example\n * ```typescript\n * const userSchema = zodSchema(z.object({ name: z.string() }));\n * type User = InferOutput<typeof userSchema>;\n * // { name: string }\n * ```\n */\nexport type InferOutput<T extends SchemaAdapter<unknown, unknown>> =\n T extends SchemaAdapter<infer O, unknown> ? O : never;\n\n/**\n * Infers the input type from a SchemaAdapter.\n * For schemas without transforms, this is the same as InferOutput.\n *\n * @example\n * ```typescript\n * const dateSchema = zodSchema(z.string().transform(s => new Date(s)));\n * type DateInput = InferInput<typeof dateSchema>;\n * // string (the input before transform)\n * type DateOutput = InferOutput<typeof dateSchema>;\n * // Date (the output after transform)\n * ```\n */\nexport type InferInput<T extends SchemaAdapter<unknown, unknown>> =\n T extends SchemaAdapter<unknown, infer I> ? I : never;\n\n/**\n * Type guard to check if a value is a SchemaAdapter.\n */\nexport function isSchemaAdapter(value: unknown): value is SchemaAdapter {\n return (\n typeof value === 'object' &&\n value !== null &&\n 'validate' in value &&\n typeof (value as SchemaAdapter).validate === 'function' &&\n 'toJsonSchema' in value &&\n typeof (value as SchemaAdapter).toJsonSchema === 'function'\n );\n}\n\n/**\n * Creates a schema adapter that always passes validation.\n * Useful for routes that accept any input.\n *\n * @example\n * ```typescript\n * const anySchema = createPassthroughAdapter<unknown>();\n * anySchema.validate(anything); // always succeeds\n * ```\n */\nexport function createPassthroughAdapter<T = unknown>(): SchemaAdapter<T, T> {\n return {\n validate: (data) => ({ success: true, data: data as T }),\n toJsonSchema: () => ({}),\n _output: undefined as T,\n _input: undefined as T,\n };\n}\n\n/**\n * Creates a schema adapter that always fails validation with a message.\n * Useful for deprecating routes or marking them as not accepting input.\n *\n * @example\n * ```typescript\n * const noBodySchema = createRejectingAdapter('This endpoint does not accept a request body');\n * ```\n */\nexport function createRejectingAdapter<T = never>(message: string): SchemaAdapter<T, T> {\n return {\n validate: () => ({\n success: false,\n issues: [{ path: [], message }],\n }),\n toJsonSchema: () => ({ not: {} }),\n _output: undefined as T,\n _input: undefined as T,\n };\n}\n"],"mappings":";AAyFO,SAAS,oBACd,QACgC;AAChC,SAAO,OAAO,YAAY;AAC5B;AAKO,SAAS,oBAAuB,QAA0D;AAC/F,SAAO,OAAO,YAAY;AAC5B;;;AC0FO,SAAS,gBAAgB,OAAwC;AACtE,SACE,OAAO,UAAU,YACjB,UAAU,QACV,cAAc,SACd,OAAQ,MAAwB,aAAa,cAC7C,kBAAkB,SAClB,OAAQ,MAAwB,iBAAiB;AAErD;AAYO,SAAS,2BAA6D;AAC3E,SAAO;AAAA,IACL,UAAU,CAAC,UAAU,EAAE,SAAS,MAAM,KAAgB;AAAA,IACtD,cAAc,OAAO,CAAC;AAAA,IACtB,SAAS;AAAA,IACT,QAAQ;AAAA,EACV;AACF;AAWO,SAAS,uBAAkC,SAAsC;AACtF,SAAO;AAAA,IACL,UAAU,OAAO;AAAA,MACf,SAAS;AAAA,MACT,QAAQ,CAAC,EAAE,MAAM,CAAC,GAAG,QAAQ,CAAC;AAAA,IAChC;AAAA,IACA,cAAc,OAAO,EAAE,KAAK,CAAC,EAAE;AAAA,IAC/B,SAAS;AAAA,IACT,QAAQ;AAAA,EACV;AACF;","names":[]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// src/
|
|
1
|
+
// src/global/exceptions/coded-error.error.ts
|
|
2
2
|
var CodedError = class extends Error {
|
|
3
3
|
/** Machine-readable error code for programmatic handling. */
|
|
4
4
|
code;
|
|
@@ -54,7 +54,7 @@ var CodedError = class extends Error {
|
|
|
54
54
|
}
|
|
55
55
|
};
|
|
56
56
|
|
|
57
|
-
// src/
|
|
57
|
+
// src/global/exceptions/error-codes.const.ts
|
|
58
58
|
var ErrorCodes = {
|
|
59
59
|
/**
|
|
60
60
|
* Domain layer error codes.
|
|
@@ -128,4 +128,4 @@ export {
|
|
|
128
128
|
CodedError,
|
|
129
129
|
ErrorCodes
|
|
130
130
|
};
|
|
131
|
-
//# sourceMappingURL=chunk-
|
|
131
|
+
//# sourceMappingURL=chunk-A4JUAZK4.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/global/exceptions/coded-error.error.ts","../src/global/exceptions/error-codes.const.ts"],"sourcesContent":["import type { ErrorCode } from './error-codes.const';\n\n/**\n * Base error class for all application errors with a machine-readable code.\n *\n * Abstract class that extends the native `Error` with:\n * - A `code` property for programmatic error handling\n * - Optional `cause` for error chaining (ES2022 compatible)\n * - A `fromError` static factory pattern for error transformation\n *\n * **Why abstract:** Prevents non-declarative error usage. All errors must\n * be explicitly defined as subclasses to ensure consistent error taxonomy.\n *\n * @example Subclass implementation\n * ```typescript\n * class DbError extends InfraError {\n * static override fromError(cause: unknown): DbError {\n * return new DbError({\n * message: cause instanceof Error ? cause.message : 'Database error',\n * cause,\n * });\n * }\n * }\n * ```\n *\n * @example Usage with wrapErrorAsync\n * ```typescript\n * await wrapErrorAsync(\n * () => this.db.query(...),\n * DbError.fromError,\n * );\n * ```\n */\nexport abstract class CodedError extends Error {\n /** Machine-readable error code for programmatic handling. */\n public readonly code: ErrorCode | string;\n\n /**\n * Creates a new CodedError instance.\n *\n * @param options - Error configuration\n * @param options.message - Human-readable error message\n * @param options.code - Machine-readable error code from ErrorCodes registry or custom string\n * @param options.cause - Optional underlying error that caused this error\n */\n constructor({\n message,\n code,\n cause,\n }: {\n message: string;\n code: ErrorCode | string;\n cause?: unknown;\n }) {\n super(message);\n this.name = this.constructor.name;\n this.code = code;\n if (cause !== undefined) {\n Object.defineProperty(this, 'cause', {\n value: cause,\n writable: false,\n enumerable: false,\n configurable: true,\n });\n }\n }\n\n /**\n * Factory method to create a typed error from a caught error.\n *\n * Subclasses should override this to provide proper error transformation.\n * Designed for use with {@link wrapErrorAsync} and {@link wrapError}.\n *\n * @param _cause - The original caught error\n * @returns A new CodedError instance\n * @throws {Error} If not overridden by subclass\n *\n * @example\n * ```typescript\n * class NotFoundError extends UseCaseError {\n * static override fromError(cause: unknown): NotFoundError {\n * return new NotFoundError({\n * message: 'Resource not found',\n * cause,\n * });\n * }\n * }\n * ```\n */\n static fromError(_cause: unknown): CodedError {\n throw new Error(`${this.name}.fromError() must be implemented by subclass`);\n }\n}\n","/**\n * Centralized registry of all error codes used across the application.\n *\n * Error codes are grouped by architectural layer to maintain clear boundaries\n * and make it easy to identify where an error originated.\n *\n * @example Using error codes in custom errors\n * ```typescript\n * import { ErrorCodes } from '@cosmneo/onion-lasagna/global';\n *\n * throw new NotFoundError({\n * message: 'User not found',\n * code: ErrorCodes.App.NOT_FOUND,\n * });\n * ```\n *\n * @example Checking error codes programmatically\n * ```typescript\n * if (error.code === ErrorCodes.App.NOT_FOUND) {\n * // Handle not found case\n * }\n * ```\n */\nexport const ErrorCodes = {\n /**\n * Domain layer error codes.\n * Used for business rule violations and invariant failures.\n */\n Domain: {\n /** Generic domain error */\n DOMAIN_ERROR: 'DOMAIN_ERROR',\n /** Business invariant was violated */\n INVARIANT_VIOLATION: 'INVARIANT_VIOLATION',\n /** Aggregate was partially loaded (missing required relations) */\n PARTIAL_LOAD: 'PARTIAL_LOAD',\n },\n\n /**\n * Application layer (use case) error codes.\n * Used for orchestration failures and business operation errors.\n */\n App: {\n /** Generic use case error */\n USE_CASE_ERROR: 'USE_CASE_ERROR',\n /** Requested resource was not found */\n NOT_FOUND: 'NOT_FOUND',\n /** Resource state conflict (e.g., duplicate, already exists) */\n CONFLICT: 'CONFLICT',\n /** Request is valid but cannot be processed due to business rules */\n UNPROCESSABLE: 'UNPROCESSABLE',\n /** Authorization denied - user lacks permission for this operation */\n FORBIDDEN: 'FORBIDDEN',\n /** Authentication required or invalid - user is not authenticated */\n UNAUTHORIZED: 'UNAUTHORIZED',\n },\n\n /**\n * Infrastructure layer error codes.\n * Used for data access, external services, and I/O failures.\n */\n Infra: {\n /** Generic infrastructure error */\n INFRA_ERROR: 'INFRA_ERROR',\n /** Database operation failed */\n DB_ERROR: 'DB_ERROR',\n /** Network connectivity or communication error */\n NETWORK_ERROR: 'NETWORK_ERROR',\n /** Operation timed out */\n TIMEOUT_ERROR: 'TIMEOUT_ERROR',\n /** External/third-party service error */\n EXTERNAL_SERVICE_ERROR: 'EXTERNAL_SERVICE_ERROR',\n },\n\n /**\n * Presentation layer error codes.\n * Used for controller, request handling, and authorization errors.\n */\n Presentation: {\n /** Generic controller error */\n CONTROLLER_ERROR: 'CONTROLLER_ERROR',\n /** Request denied due to authorization failure */\n ACCESS_DENIED: 'ACCESS_DENIED',\n /** Request validation failed (malformed input) */\n INVALID_REQUEST: 'INVALID_REQUEST',\n },\n\n /**\n * Global/cross-cutting error codes.\n * Used for validation and other cross-layer concerns.\n */\n Global: {\n /** Object/schema validation failed */\n OBJECT_VALIDATION_ERROR: 'OBJECT_VALIDATION_ERROR',\n },\n} as const;\n\n/**\n * Type representing all possible domain error codes.\n */\nexport type DomainErrorCode = (typeof ErrorCodes.Domain)[keyof typeof ErrorCodes.Domain];\n\n/**\n * Type representing all possible application error codes.\n */\nexport type AppErrorCode = (typeof ErrorCodes.App)[keyof typeof ErrorCodes.App];\n\n/**\n * Type representing all possible infrastructure error codes.\n */\nexport type InfraErrorCode = (typeof ErrorCodes.Infra)[keyof typeof ErrorCodes.Infra];\n\n/**\n * Type representing all possible presentation error codes.\n */\nexport type PresentationErrorCode =\n (typeof ErrorCodes.Presentation)[keyof typeof ErrorCodes.Presentation];\n\n/**\n * Type representing all possible global error codes.\n */\nexport type GlobalErrorCode = (typeof ErrorCodes.Global)[keyof typeof ErrorCodes.Global];\n\n/**\n * Union type of all error codes across all layers.\n *\n * Use this when you need to accept any valid error code.\n *\n * @example\n * ```typescript\n * function logError(code: ErrorCode, message: string) {\n * console.error(`[${code}] ${message}`);\n * }\n * ```\n */\nexport type ErrorCode =\n | DomainErrorCode\n | AppErrorCode\n | InfraErrorCode\n | PresentationErrorCode\n | GlobalErrorCode;\n"],"mappings":";AAiCO,IAAe,aAAf,cAAkC,MAAM;AAAA;AAAA,EAE7B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUhB,YAAY;AAAA,IACV;AAAA,IACA;AAAA,IACA;AAAA,EACF,GAIG;AACD,UAAM,OAAO;AACb,SAAK,OAAO,KAAK,YAAY;AAC7B,SAAK,OAAO;AACZ,QAAI,UAAU,QAAW;AACvB,aAAO,eAAe,MAAM,SAAS;AAAA,QACnC,OAAO;AAAA,QACP,UAAU;AAAA,QACV,YAAY;AAAA,QACZ,cAAc;AAAA,MAChB,CAAC;AAAA,IACH;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAwBA,OAAO,UAAU,QAA6B;AAC5C,UAAM,IAAI,MAAM,GAAG,KAAK,IAAI,8CAA8C;AAAA,EAC5E;AACF;;;ACrEO,IAAM,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA,EAKxB,QAAQ;AAAA;AAAA,IAEN,cAAc;AAAA;AAAA,IAEd,qBAAqB;AAAA;AAAA,IAErB,cAAc;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,KAAK;AAAA;AAAA,IAEH,gBAAgB;AAAA;AAAA,IAEhB,WAAW;AAAA;AAAA,IAEX,UAAU;AAAA;AAAA,IAEV,eAAe;AAAA;AAAA,IAEf,WAAW;AAAA;AAAA,IAEX,cAAc;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,OAAO;AAAA;AAAA,IAEL,aAAa;AAAA;AAAA,IAEb,UAAU;AAAA;AAAA,IAEV,eAAe;AAAA;AAAA,IAEf,eAAe;AAAA;AAAA,IAEf,wBAAwB;AAAA,EAC1B;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,cAAc;AAAA;AAAA,IAEZ,kBAAkB;AAAA;AAAA,IAElB,eAAe;AAAA;AAAA,IAEf,iBAAiB;AAAA,EACnB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,QAAQ;AAAA;AAAA,IAEN,yBAAyB;AAAA,EAC3B;AACF;","names":[]}
|
|
@@ -1,26 +1,24 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ControllerError,
|
|
3
|
+
InvalidRequestError,
|
|
4
|
+
UnauthorizedError
|
|
5
|
+
} from "./chunk-T7S574XQ.js";
|
|
6
|
+
import {
|
|
7
|
+
wrapError
|
|
8
|
+
} from "./chunk-ZG26OQFN.js";
|
|
1
9
|
import {
|
|
2
10
|
collectRoutes,
|
|
11
|
+
generateOperationId,
|
|
3
12
|
isRouterDefinition,
|
|
4
13
|
normalizePath
|
|
5
|
-
} from "./chunk-
|
|
6
|
-
import {
|
|
7
|
-
ControllerError,
|
|
8
|
-
InvalidRequestError
|
|
9
|
-
} from "./chunk-RRXLBGQB.js";
|
|
14
|
+
} from "./chunk-XP6PLTV2.js";
|
|
10
15
|
|
|
11
|
-
// src/
|
|
16
|
+
// src/presentation/http/server/types.ts
|
|
12
17
|
function isSimpleHandlerConfig(config) {
|
|
13
18
|
return "handler" in config && typeof config.handler === "function";
|
|
14
19
|
}
|
|
15
20
|
|
|
16
|
-
// src/
|
|
17
|
-
function createServerRoutes(router, handlers, options) {
|
|
18
|
-
return createServerRoutesInternal(
|
|
19
|
-
router,
|
|
20
|
-
handlers,
|
|
21
|
-
options
|
|
22
|
-
);
|
|
23
|
-
}
|
|
21
|
+
// src/presentation/http/server/create-server-routes.ts
|
|
24
22
|
function createServerRoutesInternal(router, handlers, options) {
|
|
25
23
|
const routes = isRouterDefinition(router) ? router.routes : router;
|
|
26
24
|
const collectedRoutes = collectRoutes(routes);
|
|
@@ -42,7 +40,7 @@ function createServerRoutesInternal(router, handlers, options) {
|
|
|
42
40
|
`Missing handler for route "${key}". All routes must have a handler configuration.`
|
|
43
41
|
);
|
|
44
42
|
}
|
|
45
|
-
result.push(createRouteHandler(route, handlerConfig, resolvedOptions));
|
|
43
|
+
result.push(createRouteHandler(key, route, handlerConfig, resolvedOptions));
|
|
46
44
|
}
|
|
47
45
|
return result;
|
|
48
46
|
}
|
|
@@ -67,7 +65,7 @@ function sortRoutesBySpecificity(routes) {
|
|
|
67
65
|
return 0;
|
|
68
66
|
});
|
|
69
67
|
}
|
|
70
|
-
function createRouteHandler(route, config, options) {
|
|
68
|
+
function createRouteHandler(key, route, config, options) {
|
|
71
69
|
const middleware = config.middleware ?? [];
|
|
72
70
|
const globalMiddleware = options?.middleware ?? [];
|
|
73
71
|
const allMiddleware = [...globalMiddleware, ...middleware];
|
|
@@ -77,7 +75,7 @@ function createRouteHandler(route, config, options) {
|
|
|
77
75
|
method: route.method,
|
|
78
76
|
path: normalizePath(route.path),
|
|
79
77
|
metadata: {
|
|
80
|
-
operationId: route.docs.operationId,
|
|
78
|
+
operationId: route.docs.operationId ?? generateOperationId(key),
|
|
81
79
|
summary: route.docs.summary,
|
|
82
80
|
description: route.docs.description,
|
|
83
81
|
tags: route.docs.tags,
|
|
@@ -85,19 +83,23 @@ function createRouteHandler(route, config, options) {
|
|
|
85
83
|
},
|
|
86
84
|
handler: async (rawRequest, ctx) => {
|
|
87
85
|
const rawContext = options?.createContext ? options.createContext(rawRequest) : ctx ?? { requestId: generateRequestId() };
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
86
|
+
const validatedContext = route.request.context ? wrapError(
|
|
87
|
+
() => {
|
|
88
|
+
const result = validateContextData(route, rawContext);
|
|
89
|
+
if (!result.success) {
|
|
90
|
+
const errors = result.errors ?? [];
|
|
91
|
+
throw new InvalidRequestError({
|
|
92
|
+
message: "Context validation failed",
|
|
93
|
+
validationErrors: errors.map((e) => ({
|
|
94
|
+
field: e.path.join("."),
|
|
95
|
+
message: e.message
|
|
96
|
+
}))
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
return result.data;
|
|
100
|
+
},
|
|
101
|
+
() => new UnauthorizedError({ message: "Authentication required" })
|
|
102
|
+
) : rawContext;
|
|
101
103
|
let validatedRequest;
|
|
102
104
|
if (shouldValidateRequest) {
|
|
103
105
|
const validationResult = validateRequestData(route, rawRequest);
|
|
@@ -185,8 +187,8 @@ function createRouteHandler(route, config, options) {
|
|
|
185
187
|
function validateRequestData(route, rawRequest) {
|
|
186
188
|
const errors = [];
|
|
187
189
|
const data = {};
|
|
188
|
-
if (route.request.body
|
|
189
|
-
const result = route.request.body.
|
|
190
|
+
if (route.request.body) {
|
|
191
|
+
const result = route.request.body.validate(rawRequest.body);
|
|
190
192
|
if (result.success) {
|
|
191
193
|
data.body = result.data;
|
|
192
194
|
} else {
|
|
@@ -198,9 +200,9 @@ function validateRequestData(route, rawRequest) {
|
|
|
198
200
|
);
|
|
199
201
|
}
|
|
200
202
|
}
|
|
201
|
-
if (route.request.query
|
|
203
|
+
if (route.request.query) {
|
|
202
204
|
const queryObj = normalizeQuery(rawRequest.query);
|
|
203
|
-
const result = route.request.query.
|
|
205
|
+
const result = route.request.query.validate(queryObj);
|
|
204
206
|
if (result.success) {
|
|
205
207
|
data.query = result.data;
|
|
206
208
|
} else {
|
|
@@ -212,8 +214,8 @@ function validateRequestData(route, rawRequest) {
|
|
|
212
214
|
);
|
|
213
215
|
}
|
|
214
216
|
}
|
|
215
|
-
if (route.request.params
|
|
216
|
-
const result = route.request.params.
|
|
217
|
+
if (route.request.params) {
|
|
218
|
+
const result = route.request.params.validate(rawRequest.params ?? {});
|
|
217
219
|
if (result.success) {
|
|
218
220
|
data.pathParams = result.data;
|
|
219
221
|
} else {
|
|
@@ -227,9 +229,9 @@ function validateRequestData(route, rawRequest) {
|
|
|
227
229
|
} else {
|
|
228
230
|
data.pathParams = normalizePathParams(rawRequest.params);
|
|
229
231
|
}
|
|
230
|
-
if (route.request.headers
|
|
232
|
+
if (route.request.headers) {
|
|
231
233
|
const headersObj = normalizeHeaders(rawRequest.headers);
|
|
232
|
-
const result = route.request.headers.
|
|
234
|
+
const result = route.request.headers.validate(headersObj);
|
|
233
235
|
if (result.success) {
|
|
234
236
|
data.headers = result.data;
|
|
235
237
|
} else {
|
|
@@ -247,13 +249,11 @@ function validateRequestData(route, rawRequest) {
|
|
|
247
249
|
return { success: true, data };
|
|
248
250
|
}
|
|
249
251
|
function validateResponseData(route, response) {
|
|
250
|
-
|
|
251
|
-
const responses = route.responses;
|
|
252
|
-
const responseConfig = responses[statusCode];
|
|
253
|
-
if (!responseConfig) {
|
|
252
|
+
if (!route.responses) {
|
|
254
253
|
return { success: true };
|
|
255
254
|
}
|
|
256
|
-
const
|
|
255
|
+
const entry = route.responses[String(response.status)];
|
|
256
|
+
const schema = entry?.schema;
|
|
257
257
|
if (!schema) {
|
|
258
258
|
return { success: true };
|
|
259
259
|
}
|
|
@@ -268,7 +268,7 @@ function validateResponseData(route, response) {
|
|
|
268
268
|
return { success: false, errors };
|
|
269
269
|
}
|
|
270
270
|
function validateContextData(route, context) {
|
|
271
|
-
const contextSchema = route.request.context
|
|
271
|
+
const contextSchema = route.request.context;
|
|
272
272
|
if (!contextSchema) {
|
|
273
273
|
return { success: true, data: context };
|
|
274
274
|
}
|
|
@@ -352,8 +352,48 @@ function generateRequestId() {
|
|
|
352
352
|
return `req_${crypto.randomUUID()}`;
|
|
353
353
|
}
|
|
354
354
|
|
|
355
|
+
// src/presentation/http/server/server-routes-builder.ts
|
|
356
|
+
var ServerRoutesBuilderImpl = class _ServerRoutesBuilderImpl {
|
|
357
|
+
router;
|
|
358
|
+
handlers;
|
|
359
|
+
constructor(router, handlers) {
|
|
360
|
+
this.router = router;
|
|
361
|
+
this.handlers = handlers ?? /* @__PURE__ */ new Map();
|
|
362
|
+
}
|
|
363
|
+
handle(key, handlerOrConfig) {
|
|
364
|
+
const config = typeof handlerOrConfig === "function" ? { handler: handlerOrConfig } : handlerOrConfig;
|
|
365
|
+
const newHandlers = new Map(this.handlers);
|
|
366
|
+
newHandlers.set(key, config);
|
|
367
|
+
return new _ServerRoutesBuilderImpl(
|
|
368
|
+
this.router,
|
|
369
|
+
newHandlers
|
|
370
|
+
);
|
|
371
|
+
}
|
|
372
|
+
handleWithUseCase(key, config) {
|
|
373
|
+
const newHandlers = new Map(this.handlers);
|
|
374
|
+
newHandlers.set(key, config);
|
|
375
|
+
return new _ServerRoutesBuilderImpl(
|
|
376
|
+
this.router,
|
|
377
|
+
newHandlers
|
|
378
|
+
);
|
|
379
|
+
}
|
|
380
|
+
// The build method's type is determined by the interface conditional type
|
|
381
|
+
// At runtime, it always works the same way - the conditional type only affects compile-time
|
|
382
|
+
build(options) {
|
|
383
|
+
return createServerRoutesInternal(this.router, Object.fromEntries(this.handlers), options);
|
|
384
|
+
}
|
|
385
|
+
buildPartial(options) {
|
|
386
|
+
return createServerRoutesInternal(this.router, Object.fromEntries(this.handlers), {
|
|
387
|
+
...options,
|
|
388
|
+
allowPartial: true
|
|
389
|
+
});
|
|
390
|
+
}
|
|
391
|
+
};
|
|
392
|
+
function serverRoutes(router) {
|
|
393
|
+
return new ServerRoutesBuilderImpl(router);
|
|
394
|
+
}
|
|
395
|
+
|
|
355
396
|
export {
|
|
356
|
-
|
|
357
|
-
createServerRoutesInternal
|
|
397
|
+
serverRoutes
|
|
358
398
|
};
|
|
359
|
-
//# sourceMappingURL=chunk-
|
|
399
|
+
//# sourceMappingURL=chunk-AUMHMWDD.js.map
|