@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.
Files changed (97) hide show
  1. package/dist/backend/core/global.cjs +283 -0
  2. package/dist/backend/core/global.cjs.map +1 -0
  3. package/dist/backend/core/global.d.cts +294 -0
  4. package/dist/backend/core/global.d.ts +294 -0
  5. package/dist/backend/core/global.js +39 -0
  6. package/dist/backend/core/global.js.map +1 -0
  7. package/dist/backend/core/onion-layers.cjs +2302 -0
  8. package/dist/backend/core/onion-layers.cjs.map +1 -0
  9. package/dist/backend/core/onion-layers.d.cts +1675 -0
  10. package/dist/backend/core/onion-layers.d.ts +1675 -0
  11. package/dist/backend/core/onion-layers.js +1158 -0
  12. package/dist/backend/core/onion-layers.js.map +1 -0
  13. package/dist/backend/core/presentation.cjs +573 -0
  14. package/dist/backend/core/presentation.cjs.map +1 -0
  15. package/dist/backend/core/presentation.d.cts +5 -0
  16. package/dist/backend/core/presentation.d.ts +5 -0
  17. package/dist/backend/core/presentation.js +28 -0
  18. package/dist/backend/core/presentation.js.map +1 -0
  19. package/dist/backend/core/validators/arktype.cjs +947 -0
  20. package/dist/backend/core/validators/arktype.cjs.map +1 -0
  21. package/dist/backend/core/validators/arktype.d.cts +188 -0
  22. package/dist/backend/core/validators/arktype.d.ts +188 -0
  23. package/dist/backend/core/validators/arktype.js +287 -0
  24. package/dist/backend/core/validators/arktype.js.map +1 -0
  25. package/dist/backend/core/validators/typebox.cjs +939 -0
  26. package/dist/backend/core/validators/typebox.cjs.map +1 -0
  27. package/dist/backend/core/validators/typebox.d.cts +189 -0
  28. package/dist/backend/core/validators/typebox.d.ts +189 -0
  29. package/dist/backend/core/validators/typebox.js +281 -0
  30. package/dist/backend/core/validators/typebox.js.map +1 -0
  31. package/dist/backend/core/validators/valibot.cjs +942 -0
  32. package/dist/backend/core/validators/valibot.cjs.map +1 -0
  33. package/dist/backend/core/validators/valibot.d.cts +160 -0
  34. package/dist/backend/core/validators/valibot.d.ts +160 -0
  35. package/dist/backend/core/validators/valibot.js +294 -0
  36. package/dist/backend/core/validators/valibot.js.map +1 -0
  37. package/dist/backend/core/validators/zod.cjs +934 -0
  38. package/dist/backend/core/validators/zod.cjs.map +1 -0
  39. package/dist/backend/core/validators/zod.d.cts +188 -0
  40. package/dist/backend/core/validators/zod.d.ts +188 -0
  41. package/dist/backend/core/validators/zod.js +278 -0
  42. package/dist/backend/core/validators/zod.js.map +1 -0
  43. package/dist/backend/frameworks/elysia.cjs +715 -0
  44. package/dist/backend/frameworks/elysia.cjs.map +1 -0
  45. package/dist/backend/frameworks/elysia.d.cts +208 -0
  46. package/dist/backend/frameworks/elysia.d.ts +208 -0
  47. package/dist/backend/frameworks/elysia.js +251 -0
  48. package/dist/backend/frameworks/elysia.js.map +1 -0
  49. package/dist/backend/frameworks/fastify.cjs +677 -0
  50. package/dist/backend/frameworks/fastify.cjs.map +1 -0
  51. package/dist/backend/frameworks/fastify.d.cts +201 -0
  52. package/dist/backend/frameworks/fastify.d.ts +201 -0
  53. package/dist/backend/frameworks/fastify.js +213 -0
  54. package/dist/backend/frameworks/fastify.js.map +1 -0
  55. package/dist/backend/frameworks/hono.cjs +715 -0
  56. package/dist/backend/frameworks/hono.cjs.map +1 -0
  57. package/dist/backend/frameworks/hono.d.cts +163 -0
  58. package/dist/backend/frameworks/hono.d.ts +163 -0
  59. package/dist/backend/frameworks/hono.js +249 -0
  60. package/dist/backend/frameworks/hono.js.map +1 -0
  61. package/dist/backend/frameworks/nestjs.cjs +260 -0
  62. package/dist/backend/frameworks/nestjs.cjs.map +1 -0
  63. package/dist/backend/frameworks/nestjs.d.cts +168 -0
  64. package/dist/backend/frameworks/nestjs.d.ts +168 -0
  65. package/dist/backend/frameworks/nestjs.js +193 -0
  66. package/dist/backend/frameworks/nestjs.js.map +1 -0
  67. package/dist/base-dto.class-D7W9iqoU.d.cts +146 -0
  68. package/dist/base-dto.class-D7W9iqoU.d.ts +146 -0
  69. package/dist/base-uuid-v7.vo-BPGEIWLM.d.ts +799 -0
  70. package/dist/base-uuid-v7.vo-BjqKX44G.d.cts +799 -0
  71. package/dist/chunk-74IKUOSE.js +116 -0
  72. package/dist/chunk-74IKUOSE.js.map +1 -0
  73. package/dist/chunk-BKZOLGQW.js +29 -0
  74. package/dist/chunk-BKZOLGQW.js.map +1 -0
  75. package/dist/chunk-CGZBV6BD.js +54 -0
  76. package/dist/chunk-CGZBV6BD.js.map +1 -0
  77. package/dist/chunk-DDAHJZVK.js +258 -0
  78. package/dist/chunk-DDAHJZVK.js.map +1 -0
  79. package/dist/chunk-MQD5GXMT.js +171 -0
  80. package/dist/chunk-MQD5GXMT.js.map +1 -0
  81. package/dist/chunk-OKFXZHBC.js +43 -0
  82. package/dist/chunk-OKFXZHBC.js.map +1 -0
  83. package/dist/chunk-RLLWYFPI.js +168 -0
  84. package/dist/chunk-RLLWYFPI.js.map +1 -0
  85. package/dist/chunk-VCHFXT5W.js +425 -0
  86. package/dist/chunk-VCHFXT5W.js.map +1 -0
  87. package/dist/chunk-ZWLYNGO3.js +40 -0
  88. package/dist/chunk-ZWLYNGO3.js.map +1 -0
  89. package/dist/http-response-BAhi8lF4.d.cts +124 -0
  90. package/dist/http-response-BAhi8lF4.d.ts +124 -0
  91. package/dist/index-DingXh7B.d.cts +1187 -0
  92. package/dist/index-tOH7XBa3.d.ts +1187 -0
  93. package/dist/routing.type-DB4pt-d9.d.ts +184 -0
  94. package/dist/routing.type-DF2BIL7x.d.cts +184 -0
  95. package/dist/validation-error.type-kD4_qNZ9.d.cts +199 -0
  96. package/dist/validation-error.type-kD4_qNZ9.d.ts +199 -0
  97. package/package.json +191 -0
@@ -0,0 +1,1187 @@
1
+ import { B as BaseDto } from './base-dto.class-D7W9iqoU.cjs';
2
+ import { C as CodedError, P as PresentationErrorCode, V as ValidationError } from './validation-error.type-kD4_qNZ9.cjs';
3
+ import { H as HttpRequest, a as HttpResponse } from './http-response-BAhi8lF4.cjs';
4
+ import './routing.type-DF2BIL7x.cjs';
5
+
6
+ /**
7
+ * Primary port interface for use case execution (Hexagonal Architecture).
8
+ *
9
+ * Defines the contract for inbound adapters that handle application use cases.
10
+ * Implementations receive a validated input DTO and return an output DTO.
11
+ *
12
+ * @typeParam TInDto - Input DTO type, must extend BaseDto
13
+ * @typeParam TOutDto - Output DTO type, must extend BaseDto
14
+ *
15
+ * @example
16
+ * ```typescript
17
+ * interface CreateUserPort extends BaseInboundPort<CreateUserInputDto, CreateUserOutputDto> {}
18
+ * ```
19
+ */
20
+ interface BaseInboundPort<TInDto extends BaseDto<unknown>, TOutDto extends BaseDto<unknown>> {
21
+ /**
22
+ * Executes the use case with the provided input.
23
+ *
24
+ * @param input - Validated input DTO
25
+ * @returns Promise resolving to the output DTO
26
+ * @throws {UseCaseError} When use case execution fails
27
+ * @throws {DomainError} When domain invariants are violated
28
+ * @throws {InfraError} When infrastructure operations fail
29
+ */
30
+ execute(input: TInDto): Promise<TOutDto>;
31
+ }
32
+
33
+ /**
34
+ * Configuration for creating a BaseController instance.
35
+ *
36
+ * All types must be DTOs (extending BaseDto) to ensure validation at every boundary:
37
+ * - TRequestDto: Validated HTTP request (body, headers, params, query)
38
+ * - TResponseDto: Validated HTTP response structure
39
+ * - TInDto: Validated use case input
40
+ * - TOutDto: Validated use case output
41
+ *
42
+ * @typeParam TRequestDto - Validated request DTO from the framework layer
43
+ * @typeParam TResponseDto - Validated response DTO to return to the framework
44
+ * @typeParam TInDto - Input DTO type for the use case
45
+ * @typeParam TOutDto - Output DTO type from the use case
46
+ */
47
+ interface BaseControllerConfig<TRequestDto extends BaseDto<unknown>, TResponseDto extends BaseDto<unknown>, TInDto extends BaseDto<unknown>, TOutDto extends BaseDto<unknown>> {
48
+ /** Maps the validated request DTO to a use case input DTO. */
49
+ requestMapper: (request: TRequestDto) => TInDto;
50
+ /** The use case to execute. */
51
+ useCase: BaseInboundPort<TInDto, TOutDto>;
52
+ /** Maps the use case output DTO to a validated response DTO. */
53
+ responseMapper: (output: TOutDto) => TResponseDto;
54
+ }
55
+ /**
56
+ * Base controller implementing the request/response pipeline.
57
+ *
58
+ * Orchestrates the flow: `requestDto → mapRequest → executeUseCase → mapResponse → responseDto`
59
+ *
60
+ * All boundaries are validated DTOs:
61
+ * - Input: TRequestDto (validated by framework layer before controller)
62
+ * - Use case input: TInDto (validated by mapRequest)
63
+ * - Use case output: TOutDto (validated by use case)
64
+ * - Output: TResponseDto (validated by mapResponse)
65
+ *
66
+ * Features:
67
+ * - Converts {@link ObjectValidationError} to {@link InvalidRequestError}
68
+ * - Passes through known {@link CodedError} types
69
+ * - Wraps unknown errors in {@link ControllerError}
70
+ *
71
+ * Architecture:
72
+ * - {@link execute} - Public entry point with error wrapping (do not override)
73
+ * - {@link pipeline} - Protected pipeline orchestration (override for custom flow)
74
+ * - {@link mapRequest} - Request-to-input transformation
75
+ * - {@link executeUseCase} - Use case execution
76
+ * - {@link mapResponse} - Output-to-response transformation
77
+ *
78
+ * @typeParam TRequestDto - Validated request DTO from the framework layer
79
+ * @typeParam TResponseDto - Validated response DTO to return to the framework
80
+ * @typeParam TInDto - Input DTO type for the use case
81
+ * @typeParam TOutDto - Output DTO type from the use case
82
+ *
83
+ * @example Basic usage
84
+ * ```typescript
85
+ * const controller = BaseController.create({
86
+ * requestMapper: (req) => CreateUserInputDto.create(req.data),
87
+ * useCase: createUserUseCase,
88
+ * responseMapper: (output) => CreateUserResponseDto.create({ id: output.data.id }),
89
+ * });
90
+ *
91
+ * // Framework layer creates the request DTO
92
+ * const requestDto = CreateUserRequestDto.create(httpRequest);
93
+ * const responseDto = await controller.execute(requestDto);
94
+ * ```
95
+ *
96
+ * @example Custom controller overriding pipeline
97
+ * ```typescript
98
+ * class LoggingController extends BaseController<...> {
99
+ * protected override async pipeline(input: TRequestDto): Promise<TResponseDto> {
100
+ * console.log('Request received:', input);
101
+ * const result = await super.pipeline(input);
102
+ * console.log('Response:', result);
103
+ * return result;
104
+ * }
105
+ * }
106
+ * ```
107
+ *
108
+ * @example Custom controller overriding individual methods
109
+ * ```typescript
110
+ * class CachingController extends BaseController<...> {
111
+ * private cache = new Map();
112
+ *
113
+ * protected override async executeUseCase(input: TInDto): Promise<TOutDto> {
114
+ * const key = JSON.stringify(input.data);
115
+ * if (this.cache.has(key)) return this.cache.get(key);
116
+ * const result = await super.executeUseCase(input);
117
+ * this.cache.set(key, result);
118
+ * return result;
119
+ * }
120
+ * }
121
+ * ```
122
+ */
123
+ declare class BaseController<TRequestDto extends BaseDto<unknown>, TResponseDto extends BaseDto<unknown>, TInDto extends BaseDto<unknown>, TOutDto extends BaseDto<unknown>> {
124
+ protected readonly requestMapper: (request: TRequestDto) => TInDto;
125
+ protected readonly useCase: BaseInboundPort<TInDto, TOutDto>;
126
+ protected readonly responseMapper: (output: TOutDto) => TResponseDto;
127
+ /**
128
+ * Creates a new BaseController instance.
129
+ *
130
+ * @param requestMapper - Function to map request DTO to use case input DTO
131
+ * @param useCase - The use case port to execute
132
+ * @param responseMapper - Function to map use case output DTO to response DTO
133
+ */
134
+ constructor(requestMapper: (request: TRequestDto) => TInDto, useCase: BaseInboundPort<TInDto, TOutDto>, responseMapper: (output: TOutDto) => TResponseDto);
135
+ /**
136
+ * Factory method to create a controller from a configuration object.
137
+ *
138
+ * @param config - Controller configuration
139
+ * @returns A new BaseController instance
140
+ */
141
+ static create<TRequestDto extends BaseDto<unknown>, TResponseDto extends BaseDto<unknown>, TInDto extends BaseDto<unknown>, TOutDto extends BaseDto<unknown>>(config: BaseControllerConfig<TRequestDto, TResponseDto, TInDto, TOutDto>): BaseController<TRequestDto, TResponseDto, TInDto, TOutDto>;
142
+ /**
143
+ * Executes the controller pipeline with error wrapping.
144
+ *
145
+ * This is the public entry point that ensures consistent error handling.
146
+ * All errors are wrapped in {@link ControllerError} unless they extend {@link CodedError}.
147
+ *
148
+ * **Do not override this method.** Override {@link pipeline} instead for custom pipeline logic.
149
+ *
150
+ * @param input - The validated request DTO
151
+ * @returns Promise resolving to the validated response DTO
152
+ * @throws {InvalidRequestError} When request mapping/validation fails
153
+ * @throws {ControllerError} When an unexpected error occurs
154
+ * @throws {CodedError} When use case throws a known error type
155
+ */
156
+ execute(input: TRequestDto): Promise<TResponseDto>;
157
+ /**
158
+ * Runs the controller pipeline.
159
+ *
160
+ * Orchestrates: `mapRequest → executeUseCase → mapResponse`
161
+ *
162
+ * Override this method to customize the entire pipeline flow, or override
163
+ * individual protected methods ({@link mapRequest}, {@link executeUseCase},
164
+ * {@link mapResponse}) for more granular control.
165
+ *
166
+ * @param input - The validated request DTO
167
+ * @returns Promise resolving to the validated response DTO
168
+ */
169
+ protected pipeline(input: TRequestDto): Promise<TResponseDto>;
170
+ /**
171
+ * Maps the request DTO to a use case input DTO.
172
+ *
173
+ * Override to add custom pre-processing, logging, or transformation logic.
174
+ * The default implementation uses the configured `requestMapper` and converts
175
+ * {@link ObjectValidationError} to {@link InvalidRequestError}.
176
+ *
177
+ * @param input - The validated request DTO
178
+ * @returns The use case input DTO
179
+ * @throws {InvalidRequestError} When validation fails
180
+ * @throws {ControllerError} When mapping fails unexpectedly
181
+ */
182
+ protected mapRequest(input: TRequestDto): TInDto;
183
+ /**
184
+ * Executes the use case with the mapped input.
185
+ *
186
+ * Override to add custom logic around use case execution, such as:
187
+ * - Logging/tracing
188
+ * - Caching
189
+ * - Retry logic
190
+ * - Multi-use-case orchestration
191
+ *
192
+ * @param input - The use case input DTO
193
+ * @returns Promise resolving to the use case output DTO
194
+ */
195
+ protected executeUseCase(input: TInDto): Promise<TOutDto>;
196
+ /**
197
+ * Maps the use case output DTO to a response DTO.
198
+ *
199
+ * Override to add custom post-processing, logging, or transformation logic.
200
+ * The default implementation uses the configured `responseMapper`.
201
+ *
202
+ * @param output - The use case output DTO
203
+ * @returns The response DTO
204
+ * @throws {ControllerError} When mapping or validation fails
205
+ */
206
+ protected mapResponse(output: TOutDto): TResponseDto;
207
+ }
208
+
209
+ /**
210
+ * Result returned by an {@link AccessGuard} function.
211
+ *
212
+ * Represents the outcome of an authorization check, indicating whether
213
+ * access should be granted and optionally providing a reason for denial.
214
+ *
215
+ * **Usage with GuardedController:**
216
+ * - If `isAllowed: true`, the controller method executes normally
217
+ * - If `isAllowed: false`, throws {@link AccessDeniedError} with the reason
218
+ *
219
+ * @example Allowing access
220
+ * ```typescript
221
+ * const result: AccessGuardResult = {
222
+ * isAllowed: true,
223
+ * };
224
+ * ```
225
+ *
226
+ * @example Denying access with reason
227
+ * ```typescript
228
+ * const result: AccessGuardResult = {
229
+ * isAllowed: false,
230
+ * reason: 'User does not have admin privileges',
231
+ * };
232
+ * ```
233
+ */
234
+ interface AccessGuardResult {
235
+ /**
236
+ * Whether the request should be allowed to proceed.
237
+ *
238
+ * - `true`: Access granted, method executes
239
+ * - `false`: Access denied, throws {@link AccessDeniedError}
240
+ */
241
+ isAllowed: boolean;
242
+ /**
243
+ * Optional explanation for why access was denied.
244
+ *
245
+ * When `isAllowed` is `false`, this message is passed to
246
+ * {@link AccessDeniedError} and can be returned to the client.
247
+ * Defaults to "Access denied" if not provided.
248
+ */
249
+ reason?: string;
250
+ }
251
+
252
+ /**
253
+ * Access guard types for controller authorization.
254
+ *
255
+ * Provides type definitions for the authorization pattern used by
256
+ * {@link GuardedController}. Guards can be synchronous or asynchronous,
257
+ * enabling both simple checks and complex authorization logic.
258
+ *
259
+ * @example Synchronous guard (simple role check)
260
+ * ```typescript
261
+ * const adminGuard: AccessGuard<Request> = (req) => ({
262
+ * isAllowed: req.user?.role === 'admin',
263
+ * reason: 'Admin access required',
264
+ * });
265
+ * ```
266
+ *
267
+ * @example Asynchronous guard (database lookup)
268
+ * ```typescript
269
+ * const resourceOwnerGuard: AccessGuard<Request> = async (req) => {
270
+ * const resource = await db.findById(req.resourceId);
271
+ * return {
272
+ * isAllowed: resource?.ownerId === req.user?.id,
273
+ * reason: 'You do not own this resource',
274
+ * };
275
+ * };
276
+ * ```
277
+ *
278
+ * @module
279
+ */
280
+
281
+ /**
282
+ * Function type for authorization checks in controllers.
283
+ *
284
+ * An AccessGuard receives the incoming request and returns an
285
+ * {@link AccessGuardResult} indicating whether access should be granted.
286
+ * Guards can be synchronous or return a Promise for async operations.
287
+ *
288
+ * @typeParam T - The request type being guarded (defaults to `unknown`)
289
+ * @param request - The incoming request to evaluate
290
+ * @returns An {@link AccessGuardResult} or Promise resolving to one
291
+ *
292
+ * @example With GuardedController.create()
293
+ * ```typescript
294
+ * const controller = GuardedController.create({
295
+ * accessGuard: (req) => ({
296
+ * isAllowed: req.authenticated,
297
+ * reason: 'Authentication required',
298
+ * }),
299
+ * requestMapper: (req) => MyInputDto.create(req),
300
+ * useCase: myUseCase,
301
+ * responseMapper: (out) => MyOutputDto.create(out),
302
+ * });
303
+ * ```
304
+ */
305
+ type AccessGuard<T = unknown> = (request: T) => AccessGuardResult | Promise<AccessGuardResult>;
306
+
307
+ /**
308
+ * Configuration for creating a GuardedController instance.
309
+ *
310
+ * All types must be DTOs (extending BaseDto) to ensure validation at every boundary.
311
+ *
312
+ * @typeParam TRequestDto - Validated request DTO from the framework layer
313
+ * @typeParam TResponseDto - Validated response DTO to return to the framework
314
+ * @typeParam TInDto - Input DTO type for the use case
315
+ * @typeParam TOutDto - Output DTO type from the use case
316
+ */
317
+ interface GuardedControllerConfig<TRequestDto extends BaseDto<unknown>, TResponseDto extends BaseDto<unknown>, TInDto extends BaseDto<unknown>, TOutDto extends BaseDto<unknown>> {
318
+ /** Maps the validated request DTO to a use case input DTO. */
319
+ requestMapper: (request: TRequestDto) => TInDto;
320
+ /** The use case to execute. */
321
+ useCase: BaseInboundPort<TInDto, TOutDto>;
322
+ /** Maps the use case output DTO to a validated response DTO. */
323
+ responseMapper: (output: TOutDto) => TResponseDto;
324
+ /** Optional access guard; defaults to allowing all requests. */
325
+ accessGuard?: AccessGuard<TRequestDto>;
326
+ }
327
+ /**
328
+ * Controller with access control.
329
+ *
330
+ * Extends {@link BaseController} with an access guard that runs before
331
+ * the pipeline. If the guard denies access, an {@link AccessDeniedError}
332
+ * is thrown.
333
+ *
334
+ * All types must be DTOs (extending BaseDto) to ensure validation at every boundary.
335
+ *
336
+ * @typeParam TRequestDto - Validated request DTO from the framework layer
337
+ * @typeParam TResponseDto - Validated response DTO to return to the framework
338
+ * @typeParam TInDto - Input DTO type for the use case
339
+ * @typeParam TOutDto - Output DTO type from the use case
340
+ *
341
+ * @example
342
+ * ```typescript
343
+ * const controller = GuardedController.create({
344
+ * requestMapper: (req) => UpdateUserInputDto.create(req.data),
345
+ * useCase: updateUserUseCase,
346
+ * responseMapper: (output) => UpdateUserResponseDto.create(output.data),
347
+ * accessGuard: async (req) => ({
348
+ * isAllowed: req.data.user?.role === 'admin',
349
+ * reason: 'Admin access required',
350
+ * }),
351
+ * });
352
+ * ```
353
+ */
354
+ declare class GuardedController<TRequestDto extends BaseDto<unknown>, TResponseDto extends BaseDto<unknown>, TInDto extends BaseDto<unknown>, TOutDto extends BaseDto<unknown>> extends BaseController<TRequestDto, TResponseDto, TInDto, TOutDto> {
355
+ /** The access guard function for this controller. */
356
+ protected readonly accessGuard: AccessGuard<TRequestDto>;
357
+ /**
358
+ * Creates a new GuardedController instance.
359
+ *
360
+ * @param requestMapper - Function to map request DTO to use case input DTO
361
+ * @param useCase - The use case port to execute
362
+ * @param responseMapper - Function to map use case output DTO to response DTO
363
+ * @param accessGuard - Optional access guard; defaults to allowing all
364
+ */
365
+ constructor(requestMapper: (request: TRequestDto) => TInDto, useCase: BaseInboundPort<TInDto, TOutDto>, responseMapper: (output: TOutDto) => TResponseDto, accessGuard?: AccessGuard<TRequestDto>);
366
+ /**
367
+ * Factory method to create a guarded controller from a configuration object.
368
+ *
369
+ * @param config - Controller configuration including optional access guard
370
+ * @returns A new GuardedController instance
371
+ */
372
+ static create<TRequestDto extends BaseDto<unknown>, TResponseDto extends BaseDto<unknown>, TInDto extends BaseDto<unknown>, TOutDto extends BaseDto<unknown>>(config: GuardedControllerConfig<TRequestDto, TResponseDto, TInDto, TOutDto>): GuardedController<TRequestDto, TResponseDto, TInDto, TOutDto>;
373
+ /**
374
+ * Runs the controller pipeline with access control.
375
+ *
376
+ * Checks the access guard before executing the pipeline.
377
+ * If denied, throws {@link AccessDeniedError}.
378
+ *
379
+ * @param input - The validated request DTO
380
+ * @returns Promise resolving to the validated response DTO
381
+ * @throws {AccessDeniedError} When access guard denies the request
382
+ */
383
+ protected pipeline(input: TRequestDto): Promise<TResponseDto>;
384
+ /**
385
+ * Checks access using the configured guard.
386
+ *
387
+ * Override to customize access control logic.
388
+ *
389
+ * @param input - The validated request DTO
390
+ * @throws {AccessDeniedError} When access is denied
391
+ */
392
+ protected checkAccess(input: TRequestDto): Promise<void>;
393
+ }
394
+
395
+ /**
396
+ * Error thrown when access to a resource is denied.
397
+ *
398
+ * Indicates that the requester does not have permission to perform
399
+ * the requested operation. Thrown by {@link GuardedController} when
400
+ * an access guard returns `isAllowed: false`.
401
+ *
402
+ * **When thrown:**
403
+ * - Access guard denies the request
404
+ * - User lacks required permissions
405
+ * - Resource ownership check fails
406
+ *
407
+ * @example GuardedController usage
408
+ * ```typescript
409
+ * const controller = GuardedController.create({
410
+ * accessGuard: (req) => ({
411
+ * isAllowed: req.user?.role === 'admin',
412
+ * reason: 'Admin access required',
413
+ * }),
414
+ * // ... other config
415
+ * });
416
+ * ```
417
+ *
418
+ * @example Manual usage
419
+ * ```typescript
420
+ * if (!user.canAccess(resource)) {
421
+ * throw new AccessDeniedError({
422
+ * message: 'You do not have access to this resource',
423
+ * code: 'RESOURCE_ACCESS_DENIED',
424
+ * });
425
+ * }
426
+ * ```
427
+ *
428
+ * @extends CodedError
429
+ */
430
+ declare class AccessDeniedError extends CodedError {
431
+ /**
432
+ * Creates a new AccessDeniedError instance.
433
+ *
434
+ * @param options - Error configuration
435
+ * @param options.message - Description of why access was denied
436
+ * @param options.code - Machine-readable error code (default: 'ACCESS_DENIED')
437
+ * @param options.cause - Optional underlying error
438
+ */
439
+ constructor({ message, code, cause, }: {
440
+ message: string;
441
+ code?: PresentationErrorCode | string;
442
+ cause?: unknown;
443
+ });
444
+ /**
445
+ * Creates an AccessDeniedError from a caught error.
446
+ *
447
+ * @param cause - The original caught error
448
+ * @returns A new AccessDeniedError instance with the cause attached
449
+ */
450
+ static fromError(cause: unknown): AccessDeniedError;
451
+ }
452
+
453
+ /**
454
+ * Base error class for presentation layer (controller) failures.
455
+ *
456
+ * Controller errors represent failures in request handling,
457
+ * such as access control violations or malformed requests.
458
+ * They are the outermost error layer and typically map to HTTP responses.
459
+ *
460
+ * **When to throw:**
461
+ * - Access control failures (unauthorized/forbidden)
462
+ * - Request validation failures
463
+ * - Unexpected controller execution errors
464
+ *
465
+ * **Child classes:**
466
+ * - {@link AccessDeniedError} - Authorization failures (HTTP 403)
467
+ * - {@link InvalidRequestError} - Request validation failures (HTTP 400)
468
+ *
469
+ * @example
470
+ * ```typescript
471
+ * // Thrown automatically by BaseController for unexpected errors
472
+ * throw new ControllerError({
473
+ * message: 'Controller execution failed',
474
+ * cause: originalError,
475
+ * });
476
+ * ```
477
+ */
478
+ declare class ControllerError extends CodedError {
479
+ /**
480
+ * Creates a new ControllerError instance.
481
+ *
482
+ * @param options - Error configuration
483
+ * @param options.message - Human-readable error description
484
+ * @param options.code - Machine-readable error code (default: 'CONTROLLER_ERROR')
485
+ * @param options.cause - Optional underlying error
486
+ */
487
+ constructor({ message, code, cause, }: {
488
+ message: string;
489
+ code?: PresentationErrorCode | string;
490
+ cause?: unknown;
491
+ });
492
+ /**
493
+ * Creates a ControllerError from a caught error.
494
+ *
495
+ * @param cause - The original caught error
496
+ * @returns A new ControllerError instance with the cause attached
497
+ */
498
+ static fromError(cause: unknown): ControllerError;
499
+ }
500
+
501
+ /**
502
+ * Error thrown when request validation fails at the controller level.
503
+ *
504
+ * Contains structured validation errors with field paths and messages,
505
+ * converted from {@link ObjectValidationError} by {@link BaseController}.
506
+ * Provides detailed feedback about which fields failed validation.
507
+ *
508
+ * **When thrown:**
509
+ * - Request DTO validation fails
510
+ * - Malformed request data
511
+ * - Missing required fields
512
+ *
513
+ * @example
514
+ * ```typescript
515
+ * // Automatically thrown by BaseController when DTO validation fails
516
+ * // The validationErrors array contains field-level details:
517
+ * // [
518
+ * // { field: 'email', message: 'Invalid email format' },
519
+ * // { field: 'age', message: 'Must be a positive number' }
520
+ * // ]
521
+ * ```
522
+ *
523
+ * @example Manual usage
524
+ * ```typescript
525
+ * throw new InvalidRequestError({
526
+ * message: 'Request validation failed',
527
+ * validationErrors: [
528
+ * { field: 'username', message: 'Username is required' },
529
+ * ],
530
+ * });
531
+ * ```
532
+ *
533
+ * @extends CodedError
534
+ */
535
+ declare class InvalidRequestError extends CodedError {
536
+ /**
537
+ * Array of field-level validation errors.
538
+ *
539
+ * Each entry contains:
540
+ * - `field`: Dot-notation path to the invalid field
541
+ * - `message`: Human-readable validation failure message
542
+ */
543
+ readonly validationErrors: ValidationError[];
544
+ /**
545
+ * Creates a new InvalidRequestError instance.
546
+ *
547
+ * @param options - Error configuration
548
+ * @param options.message - Summary of the validation failure
549
+ * @param options.code - Machine-readable error code (default: 'INVALID_REQUEST')
550
+ * @param options.cause - Optional underlying error
551
+ * @param options.validationErrors - Array of field-level validation errors
552
+ */
553
+ constructor({ message, code, cause, validationErrors, }: {
554
+ message: string;
555
+ code?: PresentationErrorCode | string;
556
+ cause?: unknown;
557
+ validationErrors: ValidationError[];
558
+ });
559
+ /**
560
+ * Creates an InvalidRequestError from a caught error.
561
+ *
562
+ * @param cause - The original caught error
563
+ * @returns A new InvalidRequestError instance with the cause attached
564
+ */
565
+ static fromError(cause: unknown): InvalidRequestError;
566
+ }
567
+
568
+ /**
569
+ * Enhanced request wrapper with metadata and context.
570
+ *
571
+ * Provides a generic structure for wrapping any request type with
572
+ * additional metadata (e.g., trace ID, timestamp) and execution context
573
+ * (e.g., authenticated user, permissions).
574
+ *
575
+ * This is a presentation-layer concern as it represents how external
576
+ * systems (HTTP, Kafka, WebSocket, gRPC, CLI, etc.) interact with
577
+ * our services.
578
+ *
579
+ * @typeParam TMetadata - Request metadata type (e.g., trace ID, correlation ID)
580
+ * @typeParam TContext - Execution context type (e.g., auth user, API key, permissions)
581
+ * @typeParam TRequest - The actual request payload type
582
+ *
583
+ * @example
584
+ * ```typescript
585
+ * interface RequestMetadata {
586
+ * traceId: string;
587
+ * timestamp: Date;
588
+ * }
589
+ *
590
+ * interface UserContext {
591
+ * userId: string;
592
+ * roles: string[];
593
+ * }
594
+ *
595
+ * type MyEnhancedRequest = EnhancedRequest<RequestMetadata, UserContext, HttpRequest>;
596
+ *
597
+ * const request: MyEnhancedRequest = {
598
+ * metadata: { traceId: 'abc-123', timestamp: new Date() },
599
+ * context: { userId: 'user-1', roles: ['admin'] },
600
+ * request: { body: { name: 'John' } },
601
+ * };
602
+ * ```
603
+ */
604
+ interface EnhancedRequest<TMetadata, TContext, TRequest> {
605
+ /**
606
+ * Request metadata containing operational information.
607
+ * Typically includes trace IDs, timestamps, and other observability data.
608
+ */
609
+ metadata: TMetadata;
610
+ /**
611
+ * Execution context containing authorization and identity information.
612
+ * Typically includes authenticated user data, permissions, and API key info.
613
+ */
614
+ context: TContext;
615
+ /**
616
+ * The actual request payload.
617
+ * Contains the business-relevant data from the incoming request.
618
+ */
619
+ request: TRequest;
620
+ }
621
+
622
+ /**
623
+ * Enhanced HTTP request with metadata and context.
624
+ *
625
+ * A specialized version of {@link EnhancedRequest} where the request payload
626
+ * is fixed to {@link HttpRequest}. This is the standard type for HTTP-based
627
+ * frameworks (AWS API Gateway, Cloudflare Workers, Express, etc.).
628
+ *
629
+ * @typeParam TMetadata - Request metadata type (e.g., request ID, correlation ID)
630
+ * @typeParam TContext - Execution context type (e.g., authenticated user, API key)
631
+ *
632
+ * @example AWS API Gateway usage
633
+ * ```typescript
634
+ * interface AwsMetadata {
635
+ * requestId: string;
636
+ * stage: string;
637
+ * }
638
+ *
639
+ * interface AuthorizerContext {
640
+ * userId: string;
641
+ * permissions: string[];
642
+ * }
643
+ *
644
+ * type AwsEnhancedRequest = EnhancedHttpRequest<AwsMetadata, AuthorizerContext>;
645
+ *
646
+ * const request: AwsEnhancedRequest = {
647
+ * metadata: { requestId: 'req-123', stage: 'prod' },
648
+ * context: { userId: 'user-1', permissions: ['read', 'write'] },
649
+ * request: {
650
+ * body: { name: 'John' },
651
+ * headers: { 'content-type': 'application/json' },
652
+ * pathParams: { id: '123' },
653
+ * queryParams: { limit: '10' },
654
+ * },
655
+ * };
656
+ * ```
657
+ */
658
+ type EnhancedHttpRequest<TMetadata, TContext> = EnhancedRequest<TMetadata, TContext, HttpRequest>;
659
+
660
+ /**
661
+ * Service metadata.
662
+ *
663
+ * Describes a service (bounded context / API surface) in a stable, serializable way.
664
+ *
665
+ * Intended use:
666
+ * - building OpenAPI specs (grouping, base paths)
667
+ * - generating clients/docs
668
+ * - consistent identification across repos
669
+ */
670
+ interface ServiceMetadata {
671
+ /**
672
+ * Stable identifier for the service.
673
+ *
674
+ * Recommendation: kebab-case and unique across the system.
675
+ * Example: `user-service`
676
+ */
677
+ id: string;
678
+ /**
679
+ * Short identifier used in logs, URLs, or UI labels.
680
+ *
681
+ * Recommendation: short kebab-case.
682
+ * Example: `user`
683
+ */
684
+ shortId: string;
685
+ /**
686
+ * Human-readable service name.
687
+ *
688
+ * Example: `User Service`
689
+ */
690
+ name: string;
691
+ /**
692
+ * Human-readable description of the service.
693
+ */
694
+ description: string;
695
+ /**
696
+ * Service base path prefix used to namespace HTTP routes.
697
+ *
698
+ * Example: `/user-service`
699
+ */
700
+ basePath: string;
701
+ /**
702
+ * OpenAPI-specific configuration for per-service spec generation.
703
+ */
704
+ openApi: {
705
+ /**
706
+ * OpenAPI info.title for per-service spec.
707
+ *
708
+ * Example: `User Service API`
709
+ */
710
+ title: string;
711
+ /**
712
+ * OpenAPI info.description for per-service spec.
713
+ * If not set, uses the service's `description`.
714
+ */
715
+ description?: string;
716
+ };
717
+ }
718
+
719
+ /**
720
+ * Resource metadata.
721
+ *
722
+ * A "resource" is a group of endpoints inside a service (often aligned with a domain aggregate
723
+ * or a REST-ish resource folder like `organization-membership-invite`).
724
+ *
725
+ * Intended use:
726
+ * - OpenAPI tags (2nd-level grouping)
727
+ * - stable tag naming/ordering independent of folder name changes
728
+ */
729
+ interface ResourceMetadata {
730
+ /**
731
+ * Stable identifier for the resource.
732
+ *
733
+ * Recommendation: kebab-case and matches its folder name.
734
+ * Example: `organization-membership-invite`
735
+ */
736
+ id: string;
737
+ /**
738
+ * Short identifier used in logs or metrics.
739
+ *
740
+ * Recommendation: short kebab-case.
741
+ * Example: `org-invite`
742
+ */
743
+ shortId: string;
744
+ /**
745
+ * Human-readable resource name.
746
+ *
747
+ * Example: `Organization Membership Invite`
748
+ */
749
+ name: string;
750
+ /**
751
+ * Human-readable description of the resource.
752
+ */
753
+ description: string;
754
+ /**
755
+ * Resource path segment (relative to service basePath).
756
+ *
757
+ * Combined with service basePath and endpoint path to form the full route.
758
+ *
759
+ * Example: `/users`
760
+ */
761
+ path: string;
762
+ /**
763
+ * Explicit ordering for UI grouping within the service.
764
+ *
765
+ * Lower numbers come first.
766
+ */
767
+ order: number;
768
+ /**
769
+ * OpenAPI-specific configuration for tag generation.
770
+ */
771
+ openApi: {
772
+ /**
773
+ * OpenAPI tag display name.
774
+ *
775
+ * Example: `Organization Membership Invite`
776
+ */
777
+ tag: string;
778
+ /**
779
+ * OpenAPI tag description shown in documentation.
780
+ */
781
+ tagDescription: string;
782
+ };
783
+ }
784
+
785
+ /**
786
+ * System metadata.
787
+ *
788
+ * Top-level metadata for the whole API surface ("the system"), sitting above
789
+ * individual services/resources/endpoints.
790
+ *
791
+ * This is intentionally stable and serializable so it can be consumed by tools
792
+ * (OpenAPI generation, docs, code generation).
793
+ */
794
+ /**
795
+ * API Key authentication scheme (header, query, or cookie).
796
+ */
797
+ interface ApiKeyAuthScheme {
798
+ type: 'apiKey';
799
+ in: 'header' | 'query' | 'cookie';
800
+ /** Header/query/cookie parameter name, e.g. 'x-api-key' */
801
+ name: string;
802
+ description?: string;
803
+ }
804
+ /**
805
+ * HTTP Bearer authentication scheme.
806
+ */
807
+ interface HttpBearerAuthScheme {
808
+ type: 'http';
809
+ scheme: 'bearer';
810
+ bearerFormat?: string;
811
+ description?: string;
812
+ }
813
+ /**
814
+ * HTTP Basic authentication scheme.
815
+ */
816
+ interface HttpBasicAuthScheme {
817
+ type: 'http';
818
+ scheme: 'basic';
819
+ description?: string;
820
+ }
821
+ /**
822
+ * Union of all supported authentication schemes.
823
+ */
824
+ type AuthScheme = ApiKeyAuthScheme | HttpBearerAuthScheme | HttpBasicAuthScheme;
825
+ interface SystemMetadata {
826
+ /**
827
+ * Stable system identifier.
828
+ *
829
+ * Recommendation: kebab-case.
830
+ * Example: `acmp-connector`
831
+ */
832
+ id: string;
833
+ /**
834
+ * Short identifier for compact displays/logging.
835
+ *
836
+ * Example: `acmp`
837
+ */
838
+ shortId: string;
839
+ /**
840
+ * Human-readable system name.
841
+ *
842
+ * Example: `ACMP Connector`
843
+ */
844
+ name: string;
845
+ /**
846
+ * Human-readable description.
847
+ */
848
+ description?: string;
849
+ /**
850
+ * System/API version (SemVer recommended).
851
+ *
852
+ * Example: `1.0.0`
853
+ */
854
+ version: string;
855
+ /**
856
+ * Default servers for the API.
857
+ * Used by OpenAPI generation and client configuration.
858
+ */
859
+ servers?: {
860
+ url: string;
861
+ description?: string;
862
+ }[];
863
+ /**
864
+ * Authentication configuration.
865
+ */
866
+ auth?: {
867
+ /**
868
+ * Whether endpoints should be considered secure by default.
869
+ * @default true
870
+ */
871
+ secureByDefault?: boolean;
872
+ /**
873
+ * Available authentication schemes.
874
+ *
875
+ * Keyed by scheme name (must be unique within the system).
876
+ * Example: `{ apiKeyAuth: { type: 'apiKey', in: 'header', name: 'x-api-key' } }`
877
+ */
878
+ schemes: Record<string, AuthScheme>;
879
+ /**
880
+ * Default security requirements (applies to all secure endpoints).
881
+ *
882
+ * OpenAPI semantics:
883
+ * - Array is OR (any requirement can satisfy)
884
+ * - Object is AND (all schemes required together)
885
+ *
886
+ * Example: `[{ apiKeyAuth: [] }]`
887
+ */
888
+ defaultSecurity?: Record<string, string[]>[];
889
+ };
890
+ /**
891
+ * OpenAPI-specific overrides for global spec generation.
892
+ */
893
+ openApi?: {
894
+ /**
895
+ * OpenAPI info.title.
896
+ * Overrides `name` if set.
897
+ */
898
+ title?: string;
899
+ /**
900
+ * OpenAPI info.description.
901
+ * Overrides `description` if set.
902
+ */
903
+ description?: string;
904
+ /**
905
+ * OpenAPI info.termsOfService URL.
906
+ */
907
+ termsOfService?: string;
908
+ /**
909
+ * OpenAPI info.contact.
910
+ */
911
+ contact?: {
912
+ name?: string;
913
+ url?: string;
914
+ email?: string;
915
+ };
916
+ /**
917
+ * OpenAPI info.license.
918
+ */
919
+ license?: {
920
+ name: string;
921
+ url?: string;
922
+ };
923
+ };
924
+ }
925
+ /**
926
+ * Extracts the scheme names (keys) from a SystemMetadata constant.
927
+ *
928
+ * @example
929
+ * const systemMeta = { auth: { schemes: { apiKeyAuth: {...}, bearerAuth: {...} } } } as const;
930
+ * type Names = SchemeNamesOf<typeof systemMeta>; // 'apiKeyAuth' | 'bearerAuth'
931
+ */
932
+ type SchemeNamesOf<TSystem> = TSystem extends {
933
+ auth: {
934
+ schemes: infer S;
935
+ };
936
+ } ? keyof S & string : never;
937
+ /**
938
+ * Creates a typed OpenAPI security requirement array from scheme names.
939
+ *
940
+ * @example
941
+ * type Req = SecurityRequirementOf<'apiKeyAuth' | 'bearerAuth'>;
942
+ * // Array<Partial<Record<'apiKeyAuth' | 'bearerAuth', string[]>>>
943
+ */
944
+ type SecurityRequirementOf<TSchemeNames extends string> = Partial<Record<TSchemeNames, string[]>>[];
945
+ /**
946
+ * Input type for defineSystemMetadata helper (with generic auth).
947
+ */
948
+ type SystemMetadataInput<TSchemeNames extends string> = Omit<SystemMetadata, 'auth'> & {
949
+ auth?: {
950
+ secureByDefault?: boolean;
951
+ schemes: Record<TSchemeNames, AuthScheme>;
952
+ defaultSecurity?: Partial<Record<TSchemeNames, string[]>>[];
953
+ };
954
+ };
955
+ /**
956
+ * Defines system metadata with fully-typed `defaultSecurity`.
957
+ *
958
+ * Infers scheme names from the `schemes` object and validates that
959
+ * `defaultSecurity` only references existing scheme names.
960
+ *
961
+ * @example
962
+ * export const systemMetadata = defineSystemMetadata({
963
+ * id: 'my-api',
964
+ * shortId: 'api',
965
+ * name: 'My API',
966
+ * version: '1.0.0',
967
+ * auth: {
968
+ * schemes: {
969
+ * apiKeyAuth: { type: 'apiKey', in: 'header', name: 'x-api-key' },
970
+ * },
971
+ * defaultSecurity: [{ apiKeyAuth: [] }], // ✅ Valid
972
+ * // defaultSecurity: [{ typoAuth: [] }], // ❌ TypeScript error!
973
+ * },
974
+ * });
975
+ */
976
+ declare function defineSystemMetadata<const TSchemeNames extends string>(metadata: SystemMetadataInput<TSchemeNames>): SystemMetadataInput<TSchemeNames> & SystemMetadata;
977
+
978
+ /**
979
+ * Allowed HTTP methods for endpoint metadata.
980
+ */
981
+ type HttpEndpointMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
982
+ /**
983
+ * Allowed HTTP success status codes.
984
+ */
985
+ type HttpSuccessStatus = 200 | 201 | 202 | 204;
986
+ /**
987
+ * OpenAPI-specific fields for endpoint metadata (loosely typed).
988
+ */
989
+ interface HttpEndpointOpenApi {
990
+ /**
991
+ * OpenAPI operation summary.
992
+ * Overrides `description` for the summary field if set.
993
+ */
994
+ summary?: string;
995
+ /**
996
+ * OpenAPI operation description (detailed).
997
+ * Overrides `description` for the description field if set.
998
+ */
999
+ description?: string;
1000
+ /**
1001
+ * Explicit OpenAPI operationId.
1002
+ * Defaults to endpoint `name` if not set.
1003
+ */
1004
+ operationId?: string;
1005
+ /**
1006
+ * Override resource tag(s) for this endpoint.
1007
+ * Defaults to resource's openApi.tag or name if not set.
1008
+ */
1009
+ tags?: string[];
1010
+ /**
1011
+ * Mark endpoint as deprecated in OpenAPI documentation.
1012
+ * @default false
1013
+ */
1014
+ deprecated?: boolean;
1015
+ /**
1016
+ * HTTP success status code for OpenAPI documentation.
1017
+ *
1018
+ * @default Derived from HTTP method:
1019
+ * - GET: 200
1020
+ * - POST: 201
1021
+ * - PUT: 200
1022
+ * - PATCH: 200
1023
+ * - DELETE: 204
1024
+ */
1025
+ successStatus?: HttpSuccessStatus;
1026
+ /**
1027
+ * Explicit OpenAPI `security` requirements for this endpoint.
1028
+ *
1029
+ * OpenAPI semantics:
1030
+ * - The array is OR (any requirement can satisfy).
1031
+ * - Each object is AND (all schemes in the object are required together).
1032
+ *
1033
+ * Examples:
1034
+ * - Public endpoint (overrides any global security): `[]`
1035
+ * - Require api key: `[ { apiKeyAuth: [] } ]`
1036
+ * - Allow either api key OR bearer: `[ { apiKeyAuth: [] }, { bearerAuth: [] } ]`
1037
+ */
1038
+ security?: Record<string, string[]>[];
1039
+ }
1040
+ /**
1041
+ * OpenAPI-specific fields for endpoint metadata (strongly typed security).
1042
+ */
1043
+ interface HttpEndpointOpenApiFor<TSystem> extends Omit<HttpEndpointOpenApi, 'security'> {
1044
+ /**
1045
+ * Explicit OpenAPI `security` requirements for this endpoint.
1046
+ * Scheme names are validated against the system metadata at compile time.
1047
+ */
1048
+ security?: SecurityRequirementOf<SchemeNamesOf<TSystem>>;
1049
+ }
1050
+ /**
1051
+ * HTTP endpoint metadata.
1052
+ *
1053
+ * Describes an HTTP endpoint in a stable, serializable way.
1054
+ *
1055
+ * Intended use:
1056
+ * - documentation (OpenAPI generation)
1057
+ * - HTTP client generation
1058
+ * - consistent endpoint identification (id/shortId)
1059
+ */
1060
+ interface HttpEndpointMetadata {
1061
+ /**
1062
+ * Stable endpoint identifier.
1063
+ *
1064
+ * Recommendation: kebab-case.
1065
+ * Example: `get-user-by-id`
1066
+ */
1067
+ id: string;
1068
+ /**
1069
+ * Short endpoint identifier.
1070
+ *
1071
+ * Useful for logs/metrics.
1072
+ * Example: `gubi`
1073
+ */
1074
+ shortId: string;
1075
+ /**
1076
+ * Stable endpoint name used in code.
1077
+ *
1078
+ * Recommendation: camelCase.
1079
+ * Example: `getUserById`
1080
+ */
1081
+ name: string;
1082
+ /**
1083
+ * Human-readable description.
1084
+ *
1085
+ * Used as default for OpenAPI summary/description.
1086
+ */
1087
+ description: string;
1088
+ /**
1089
+ * Endpoint-relative path (without service or resource path).
1090
+ *
1091
+ * Combined with service basePath and resource path to form the full route.
1092
+ * Use `computeRoutePath()` to compute the full path when needed.
1093
+ *
1094
+ * Example: `/{id}` or `/` for collection endpoints
1095
+ */
1096
+ path: string;
1097
+ /**
1098
+ * HTTP method.
1099
+ */
1100
+ method: HttpEndpointMethod;
1101
+ /**
1102
+ * OpenAPI-specific overrides for this endpoint.
1103
+ */
1104
+ openApi?: HttpEndpointOpenApi;
1105
+ }
1106
+ /**
1107
+ * HTTP endpoint metadata with strongly-typed `openApi.security`.
1108
+ *
1109
+ * Use this to get compile-time validation of security scheme names
1110
+ * against a SystemMetadata constant.
1111
+ *
1112
+ * @example
1113
+ * import type { HttpEndpointMetadataFor } from '@cosmneo/org-lib-backend-common-kit';
1114
+ * import { systemMetadata } from '@/contracts/system-metadata';
1115
+ *
1116
+ * export const getUserHttpMetadata: HttpEndpointMetadataFor<typeof systemMetadata> = {
1117
+ * id: 'get-user',
1118
+ * // ...
1119
+ * openApi: {
1120
+ * security: [{ apiKeyAuth: [] }], // ✅ Compile-time checked!
1121
+ * },
1122
+ * };
1123
+ */
1124
+ interface HttpEndpointMetadataFor<TSystem> extends Omit<HttpEndpointMetadata, 'openApi'> {
1125
+ /**
1126
+ * OpenAPI-specific overrides for this endpoint (with typed security).
1127
+ */
1128
+ openApi?: HttpEndpointOpenApiFor<TSystem>;
1129
+ }
1130
+
1131
+ /**
1132
+ * Computes the full route path from service, resource, and endpoint metadata.
1133
+ *
1134
+ * Handles path normalization:
1135
+ * - Ensures leading slash
1136
+ * - Joins segments with single slashes
1137
+ * - Removes trailing slash (except for root)
1138
+ *
1139
+ * @example
1140
+ * ```typescript
1141
+ * computeRoutePath(
1142
+ * { basePath: '/user-service' },
1143
+ * { path: '/users' },
1144
+ * { path: '/{id}' }
1145
+ * ); // => '/user-service/users/{id}'
1146
+ * ```
1147
+ */
1148
+ declare function computeRoutePath(service: Pick<ServiceMetadata, 'basePath'>, resource: Pick<ResourceMetadata, 'path'>, endpoint: Pick<HttpEndpointMetadata, 'path'>): string;
1149
+
1150
+ /**
1151
+ * Type guard to validate that a value is a valid HttpResponse.
1152
+ *
1153
+ * Checks that the value has the required `statusCode` property as a number.
1154
+ * This is used to validate controller outputs before passing to response mappers.
1155
+ *
1156
+ * @param value - The value to check
1157
+ * @returns True if the value is a valid HttpResponse
1158
+ *
1159
+ * @example
1160
+ * ```typescript
1161
+ * const output = controller.execute(input);
1162
+ * if (!isHttpResponse(output)) {
1163
+ * throw new Error('Controller must return an HttpResponse');
1164
+ * }
1165
+ * ```
1166
+ */
1167
+ declare function isHttpResponse(value: unknown): value is HttpResponse;
1168
+ /**
1169
+ * Asserts that a value is a valid HttpResponse.
1170
+ *
1171
+ * Throws a descriptive error if the value is not a valid HttpResponse,
1172
+ * making it easier to debug controller output issues.
1173
+ *
1174
+ * @param value - The value to validate
1175
+ * @param context - Optional context for the error message (e.g., 'mapOutput')
1176
+ * @throws Error if the value is not a valid HttpResponse
1177
+ *
1178
+ * @example
1179
+ * ```typescript
1180
+ * const output = controller.execute(input);
1181
+ * assertHttpResponse(output, 'controller output');
1182
+ * // Now TypeScript knows output is HttpResponse
1183
+ * ```
1184
+ */
1185
+ declare function assertHttpResponse(value: unknown, context?: string): asserts value is HttpResponse;
1186
+
1187
+ export { AccessDeniedError as A, type BaseInboundPort as B, ControllerError as C, type EnhancedHttpRequest as E, type GuardedControllerConfig as G, type HttpEndpointMethod as H, InvalidRequestError as I, type ResourceMetadata as R, type ServiceMetadata as S, type BaseControllerConfig as a, BaseController as b, GuardedController as c, type AccessGuard as d, type AccessGuardResult as e, type EnhancedRequest as f, type HttpSuccessStatus as g, type HttpEndpointOpenApi as h, type HttpEndpointOpenApiFor as i, type HttpEndpointMetadata as j, type HttpEndpointMetadataFor as k, type ApiKeyAuthScheme as l, type HttpBearerAuthScheme as m, type HttpBasicAuthScheme as n, type AuthScheme as o, type SystemMetadata as p, type SchemeNamesOf as q, type SecurityRequirementOf as r, defineSystemMetadata as s, computeRoutePath as t, isHttpResponse as u, assertHttpResponse as v };