@kontract/adonis 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +507 -0
- package/dist/adapters/controller-registrar.d.ts +313 -0
- package/dist/adapters/controller-registrar.d.ts.map +1 -0
- package/dist/adapters/controller-registrar.js +324 -0
- package/dist/adapters/controller-registrar.js.map +1 -0
- package/dist/adapters/index.d.ts +2 -0
- package/dist/adapters/index.d.ts.map +1 -0
- package/dist/adapters/index.js +2 -0
- package/dist/adapters/index.js.map +1 -0
- package/dist/adapters/route-registrar.d.ts +53 -0
- package/dist/adapters/route-registrar.d.ts.map +1 -0
- package/dist/adapters/route-registrar.js +139 -0
- package/dist/adapters/route-registrar.js.map +1 -0
- package/dist/adapters/router.d.ts +37 -0
- package/dist/adapters/router.d.ts.map +1 -0
- package/dist/adapters/router.js +129 -0
- package/dist/adapters/router.js.map +1 -0
- package/dist/builder/index.d.ts +2 -0
- package/dist/builder/index.d.ts.map +1 -0
- package/dist/builder/index.js +3 -0
- package/dist/builder/index.js.map +1 -0
- package/dist/builder/openapi-builder.d.ts +100 -0
- package/dist/builder/openapi-builder.d.ts.map +1 -0
- package/dist/builder/openapi-builder.js +388 -0
- package/dist/builder/openapi-builder.js.map +1 -0
- package/dist/index.d.ts +34 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +45 -0
- package/dist/index.js.map +1 -0
- package/dist/serializers/index.d.ts +2 -0
- package/dist/serializers/index.d.ts.map +1 -0
- package/dist/serializers/index.js +2 -0
- package/dist/serializers/index.js.map +1 -0
- package/dist/serializers/lucid.d.ts +100 -0
- package/dist/serializers/lucid.d.ts.map +1 -0
- package/dist/serializers/lucid.js +114 -0
- package/dist/serializers/lucid.js.map +1 -0
- package/dist/validation/ajv.d.ts +42 -0
- package/dist/validation/ajv.d.ts.map +1 -0
- package/dist/validation/ajv.js +170 -0
- package/dist/validation/ajv.js.map +1 -0
- package/dist/validation/index.d.ts +2 -0
- package/dist/validation/index.d.ts.map +1 -0
- package/dist/validation/index.js +3 -0
- package/dist/validation/index.js.map +1 -0
- package/package.json +96 -0
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Register route definitions (from defineRoute/defineController) with AdonisJS.
|
|
3
|
+
*
|
|
4
|
+
* This provides an alternative to decorator-based route registration with
|
|
5
|
+
* full TypeScript type inference.
|
|
6
|
+
*/
|
|
7
|
+
import type { Router, HttpContext } from '@adonisjs/core/http';
|
|
8
|
+
import type { ApplicationService } from '@adonisjs/core/types';
|
|
9
|
+
import type { TSchema, Static } from '@sinclair/typebox';
|
|
10
|
+
import { type ControllerDefinition, type RouteDefinition, type RouteConfig, type AnyResponse, type ApiResponse, type RouteString, type ResponsesConfig, type ParamsFromPath, noContent } from 'kontract';
|
|
11
|
+
export { noContent };
|
|
12
|
+
/**
|
|
13
|
+
* Validate function signature.
|
|
14
|
+
* Takes a schema and data, returns validated/coerced data or throws.
|
|
15
|
+
*/
|
|
16
|
+
export type ValidateFn = <T extends TSchema>(schema: T, data: unknown) => Static<T>;
|
|
17
|
+
/**
|
|
18
|
+
* Options for registerController.
|
|
19
|
+
*/
|
|
20
|
+
export interface RegisterControllerOptions {
|
|
21
|
+
/**
|
|
22
|
+
* Validation function that validates and coerces data against a schema.
|
|
23
|
+
* Should throw on validation failure.
|
|
24
|
+
*
|
|
25
|
+
* Optional - uses built-in AJV validator by default.
|
|
26
|
+
*/
|
|
27
|
+
validate?: ValidateFn;
|
|
28
|
+
/**
|
|
29
|
+
* Optional AdonisJS container for dependency injection.
|
|
30
|
+
* If provided, services can be resolved using container.make()
|
|
31
|
+
*/
|
|
32
|
+
container?: ApplicationService['container'];
|
|
33
|
+
}
|
|
34
|
+
import type { ResponseSchemaFor } from 'kontract';
|
|
35
|
+
/**
|
|
36
|
+
* Helper type to create a typed response function for a specific status code.
|
|
37
|
+
*/
|
|
38
|
+
type TypedHelper<TResponses, Status extends number> = ResponseSchemaFor<TResponses, Status> extends TSchema ? (data: Static<ResponseSchemaFor<TResponses, Status>>) => ApiResponse<Status, Static<ResponseSchemaFor<TResponses, Status>>> : never;
|
|
39
|
+
/**
|
|
40
|
+
* Error helper that accepts:
|
|
41
|
+
* - No args: use description from response definition as message
|
|
42
|
+
* - A string: use as message, auto-fill status and code
|
|
43
|
+
* - An object: merge with defaults (status, code, description as message)
|
|
44
|
+
*/
|
|
45
|
+
type TypedErrorHelper<TResponses, Status extends number> = ResponseSchemaFor<TResponses, Status> extends TSchema ? (dataOrMessage?: string | Partial<Static<ResponseSchemaFor<TResponses, Status>>>) => ApiResponse<Status, Static<ResponseSchemaFor<TResponses, Status>>> : never;
|
|
46
|
+
/**
|
|
47
|
+
* Success response helpers namespace (2xx).
|
|
48
|
+
* Only includes methods for status codes that are defined in responses.
|
|
49
|
+
*/
|
|
50
|
+
export type ReplyHelpers<TResponses extends ResponsesConfig> = (200 extends keyof TResponses ? {
|
|
51
|
+
ok: TypedHelper<TResponses, 200>;
|
|
52
|
+
list: TypedHelper<TResponses, 200>;
|
|
53
|
+
} : unknown) & (201 extends keyof TResponses ? {
|
|
54
|
+
created: TypedHelper<TResponses, 201>;
|
|
55
|
+
} : unknown) & (202 extends keyof TResponses ? {
|
|
56
|
+
accepted: TypedHelper<TResponses, 202>;
|
|
57
|
+
} : unknown) & (204 extends keyof TResponses ? {
|
|
58
|
+
noContent: () => ApiResponse<204, null>;
|
|
59
|
+
} : unknown);
|
|
60
|
+
/**
|
|
61
|
+
* Error response helpers namespace (4xx/5xx).
|
|
62
|
+
* Only includes methods for status codes that are defined in responses.
|
|
63
|
+
*
|
|
64
|
+
* Each method accepts:
|
|
65
|
+
* - No args: `error.internal()` - uses response description as message
|
|
66
|
+
* - A string: `error.badRequest('Invalid token')`
|
|
67
|
+
* - An object: `error.badRequest({ message: 'Invalid', details: {...} })`
|
|
68
|
+
*
|
|
69
|
+
* Status, code, and message are auto-filled from sensible defaults.
|
|
70
|
+
*/
|
|
71
|
+
export type ErrorHelpers<TResponses extends ResponsesConfig> = (400 extends keyof TResponses ? {
|
|
72
|
+
badRequest: TypedErrorHelper<TResponses, 400>;
|
|
73
|
+
} : unknown) & (401 extends keyof TResponses ? {
|
|
74
|
+
unauthorized: TypedErrorHelper<TResponses, 401>;
|
|
75
|
+
} : unknown) & (403 extends keyof TResponses ? {
|
|
76
|
+
forbidden: TypedErrorHelper<TResponses, 403>;
|
|
77
|
+
} : unknown) & (404 extends keyof TResponses ? {
|
|
78
|
+
notFound: TypedErrorHelper<TResponses, 404>;
|
|
79
|
+
} : unknown) & (409 extends keyof TResponses ? {
|
|
80
|
+
conflict: TypedErrorHelper<TResponses, 409>;
|
|
81
|
+
} : unknown) & (422 extends keyof TResponses ? {
|
|
82
|
+
validationError: TypedErrorHelper<TResponses, 422>;
|
|
83
|
+
} : unknown) & (429 extends keyof TResponses ? {
|
|
84
|
+
tooManyRequests: TypedErrorHelper<TResponses, 429>;
|
|
85
|
+
} : unknown) & (500 extends keyof TResponses ? {
|
|
86
|
+
internal: TypedErrorHelper<TResponses, 500>;
|
|
87
|
+
} : unknown) & (503 extends keyof TResponses ? {
|
|
88
|
+
serviceUnavailable: TypedErrorHelper<TResponses, 503>;
|
|
89
|
+
} : unknown);
|
|
90
|
+
/**
|
|
91
|
+
* Extended handler context for AdonisJS with typed body, query, params,
|
|
92
|
+
* AND namespaced response helpers derived from the responses config.
|
|
93
|
+
*
|
|
94
|
+
* Path parameters are automatically inferred from the route path when not
|
|
95
|
+
* explicitly provided. For example, `/users/:id` will infer `{ id: string }`.
|
|
96
|
+
*/
|
|
97
|
+
export interface AdonisHandlerContext<TPath extends string = string, TBody extends TSchema | undefined = undefined, TQuery extends TSchema | undefined = undefined, TParams extends TSchema | undefined = undefined, TResponses extends ResponsesConfig = ResponsesConfig> {
|
|
98
|
+
/** Validated request body (typed from body schema) */
|
|
99
|
+
body: TBody extends TSchema ? Static<TBody> : undefined;
|
|
100
|
+
/** Validated query parameters (typed from query schema) */
|
|
101
|
+
query: TQuery extends TSchema ? Static<TQuery> : undefined;
|
|
102
|
+
/** Validated path parameters (inferred from path or explicit params schema) */
|
|
103
|
+
params: TParams extends TSchema ? Static<TParams> : ParamsFromPath<TPath>;
|
|
104
|
+
/** Authenticated user (available when auth is 'required' or 'optional') */
|
|
105
|
+
user: unknown;
|
|
106
|
+
/** Full AdonisJS HttpContext */
|
|
107
|
+
ctx: HttpContext;
|
|
108
|
+
/** Raw context (alias for ctx, for compatibility with generic HandlerContext) */
|
|
109
|
+
raw: HttpContext;
|
|
110
|
+
/** AdonisJS container for service resolution */
|
|
111
|
+
container?: ApplicationService['container'];
|
|
112
|
+
/** Success response helpers (2xx) - methods typed from responses config */
|
|
113
|
+
reply: ReplyHelpers<TResponses>;
|
|
114
|
+
/** Error response helpers (4xx/5xx) - methods typed from responses config */
|
|
115
|
+
error: ErrorHelpers<TResponses>;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Handler function type for AdonisJS routes.
|
|
119
|
+
* Path parameters are automatically inferred from TPath when TParams is undefined.
|
|
120
|
+
*/
|
|
121
|
+
export type AdonisRouteHandler<TPath extends string = string, TBody extends TSchema | undefined = undefined, TQuery extends TSchema | undefined = undefined, TParams extends TSchema | undefined = undefined, TResponses extends ResponsesConfig = ResponsesConfig> = (ctx: AdonisHandlerContext<TPath, TBody, TQuery, TParams, TResponses>) => Promise<AnyResponse> | AnyResponse;
|
|
122
|
+
/**
|
|
123
|
+
* AdonisJS middleware type (from route.use())
|
|
124
|
+
*/
|
|
125
|
+
type Middleware = any;
|
|
126
|
+
/**
|
|
127
|
+
* Extended RouteConfig for AdonisJS with middleware support.
|
|
128
|
+
*/
|
|
129
|
+
export interface AdonisRouteConfig<TBody extends TSchema | undefined = undefined, TQuery extends TSchema | undefined = undefined, TParams extends TSchema | undefined = undefined, TResponses extends ResponsesConfig = ResponsesConfig> extends RouteConfig<RouteString, TBody, TQuery, TParams> {
|
|
130
|
+
/** AdonisJS middleware to apply to this route */
|
|
131
|
+
middleware?: Middleware[];
|
|
132
|
+
/** Response definitions for this route */
|
|
133
|
+
responses: TResponses;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Extended RouteDefinition that includes middleware.
|
|
137
|
+
*/
|
|
138
|
+
export interface AdonisRouteDefinition<TPath extends string = string, TBody extends TSchema | undefined = undefined, TQuery extends TSchema | undefined = undefined, TParams extends TSchema | undefined = undefined> extends RouteDefinition<TPath, TBody, TQuery, TParams> {
|
|
139
|
+
/** AdonisJS middleware to apply to this route */
|
|
140
|
+
middleware?: Middleware[];
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Define an AdonisJS route with properly typed context and response helpers.
|
|
144
|
+
*
|
|
145
|
+
* This is a wrapper around `defineRoute` that provides AdonisJS-specific
|
|
146
|
+
* typed context including `ctx` (HttpContext), `container`, and pre-typed
|
|
147
|
+
* namespaced response helpers based on the responses config.
|
|
148
|
+
*
|
|
149
|
+
* @example
|
|
150
|
+
* ```typescript
|
|
151
|
+
* import { defineAdonisRoute, defineController } from '@kontract/adonis'
|
|
152
|
+
* import StatsService from '#services/stats_service'
|
|
153
|
+
*
|
|
154
|
+
* const getStats = defineAdonisRoute({
|
|
155
|
+
* route: 'GET /api/v1/stats',
|
|
156
|
+
* responses: {
|
|
157
|
+
* 200: { schema: StatsResponse },
|
|
158
|
+
* 401: { schema: ApiError },
|
|
159
|
+
* },
|
|
160
|
+
* }, async ({ ctx, reply, error }) => {
|
|
161
|
+
* // ctx is typed as HttpContext
|
|
162
|
+
* // reply.ok() and error.unauthorized() are pre-typed from responses config
|
|
163
|
+
* const statsService = await ctx.containerResolver.make(StatsService)
|
|
164
|
+
* return reply.ok(await statsService.getOverview())
|
|
165
|
+
* })
|
|
166
|
+
* ```
|
|
167
|
+
*/
|
|
168
|
+
export declare function defineAdonisRoute<TPath extends string = string, TBody extends TSchema | undefined = undefined, TQuery extends TSchema | undefined = undefined, TParams extends TSchema | undefined = undefined, TResponses extends ResponsesConfig = ResponsesConfig>(config: AdonisRouteConfig<TBody, TQuery, TParams, TResponses>, handler: AdonisRouteHandler<TPath, TBody, TQuery, TParams, TResponses>): AdonisRouteDefinition<TPath, TBody, TQuery, TParams>;
|
|
169
|
+
/**
|
|
170
|
+
* Options for GET and DELETE routes (no body).
|
|
171
|
+
*/
|
|
172
|
+
export type GetRouteOptions<TQuery extends TSchema | undefined = undefined, TParams extends TSchema | undefined = undefined, TResponses extends ResponsesConfig = ResponsesConfig> = Omit<AdonisRouteConfig<undefined, TQuery, TParams, TResponses>, 'route' | 'body'>;
|
|
173
|
+
/**
|
|
174
|
+
* Options for POST, PUT, PATCH routes (with body).
|
|
175
|
+
*/
|
|
176
|
+
export type BodyRouteOptions<TBody extends TSchema | undefined = undefined, TQuery extends TSchema | undefined = undefined, TParams extends TSchema | undefined = undefined, TResponses extends ResponsesConfig = ResponsesConfig> = Omit<AdonisRouteConfig<TBody, TQuery, TParams, TResponses>, 'route'>;
|
|
177
|
+
/**
|
|
178
|
+
* Define a GET route with Elysia-style API.
|
|
179
|
+
*
|
|
180
|
+
* @example
|
|
181
|
+
* ```typescript
|
|
182
|
+
* const listUsers = get('/api/v1/users',
|
|
183
|
+
* async ({ query, reply }) => {
|
|
184
|
+
* const users = await User.query().paginate(query.page, query.perPage)
|
|
185
|
+
* return reply.list(users)
|
|
186
|
+
* },
|
|
187
|
+
* {
|
|
188
|
+
* summary: 'List users',
|
|
189
|
+
* query: UserQueryParams,
|
|
190
|
+
* responses: { 200: { schema: UserListResponse } },
|
|
191
|
+
* }
|
|
192
|
+
* )
|
|
193
|
+
* ```
|
|
194
|
+
*/
|
|
195
|
+
export declare function get<TPath extends string, TQuery extends TSchema | undefined = undefined, TParams extends TSchema | undefined = undefined, TResponses extends ResponsesConfig = ResponsesConfig>(path: TPath, handler: AdonisRouteHandler<TPath, undefined, TQuery, TParams, TResponses>, options: GetRouteOptions<TQuery, TParams, TResponses>): AdonisRouteDefinition<TPath, undefined, TQuery, TParams>;
|
|
196
|
+
/**
|
|
197
|
+
* Define a POST route with Elysia-style API.
|
|
198
|
+
*
|
|
199
|
+
* @example
|
|
200
|
+
* ```typescript
|
|
201
|
+
* const createUser = post('/api/v1/users',
|
|
202
|
+
* async ({ body, reply }) => {
|
|
203
|
+
* const user = await User.create(body)
|
|
204
|
+
* return reply.created(user)
|
|
205
|
+
* },
|
|
206
|
+
* {
|
|
207
|
+
* summary: 'Create a user',
|
|
208
|
+
* body: CreateUserRequest,
|
|
209
|
+
* responses: {
|
|
210
|
+
* 201: { schema: UserResponse },
|
|
211
|
+
* 400: { schema: ApiError },
|
|
212
|
+
* },
|
|
213
|
+
* }
|
|
214
|
+
* )
|
|
215
|
+
* ```
|
|
216
|
+
*/
|
|
217
|
+
export declare function post<TPath extends string, TBody extends TSchema | undefined = undefined, TQuery extends TSchema | undefined = undefined, TParams extends TSchema | undefined = undefined, TResponses extends ResponsesConfig = ResponsesConfig>(path: TPath, handler: AdonisRouteHandler<TPath, TBody, TQuery, TParams, TResponses>, options: BodyRouteOptions<TBody, TQuery, TParams, TResponses>): AdonisRouteDefinition<TPath, TBody, TQuery, TParams>;
|
|
218
|
+
/**
|
|
219
|
+
* Define a PUT route with Elysia-style API.
|
|
220
|
+
*
|
|
221
|
+
* @example
|
|
222
|
+
* ```typescript
|
|
223
|
+
* const updateUser = put('/api/v1/users/:id',
|
|
224
|
+
* async ({ params, body, reply }) => {
|
|
225
|
+
* const user = await User.findOrFail(params.id)
|
|
226
|
+
* user.merge(body)
|
|
227
|
+
* await user.save()
|
|
228
|
+
* return reply.ok(user)
|
|
229
|
+
* },
|
|
230
|
+
* {
|
|
231
|
+
* summary: 'Update a user',
|
|
232
|
+
* params: IdParams,
|
|
233
|
+
* body: UpdateUserRequest,
|
|
234
|
+
* responses: { 200: { schema: UserResponse } },
|
|
235
|
+
* }
|
|
236
|
+
* )
|
|
237
|
+
* ```
|
|
238
|
+
*/
|
|
239
|
+
export declare function put<TPath extends string, TBody extends TSchema | undefined = undefined, TQuery extends TSchema | undefined = undefined, TParams extends TSchema | undefined = undefined, TResponses extends ResponsesConfig = ResponsesConfig>(path: TPath, handler: AdonisRouteHandler<TPath, TBody, TQuery, TParams, TResponses>, options: BodyRouteOptions<TBody, TQuery, TParams, TResponses>): AdonisRouteDefinition<TPath, TBody, TQuery, TParams>;
|
|
240
|
+
/**
|
|
241
|
+
* Define a PATCH route with Elysia-style API.
|
|
242
|
+
*
|
|
243
|
+
* @example
|
|
244
|
+
* ```typescript
|
|
245
|
+
* const patchUser = patch('/api/v1/users/:id',
|
|
246
|
+
* async ({ params, body, reply }) => {
|
|
247
|
+
* const user = await User.findOrFail(params.id)
|
|
248
|
+
* user.merge(body)
|
|
249
|
+
* await user.save()
|
|
250
|
+
* return reply.ok(user)
|
|
251
|
+
* },
|
|
252
|
+
* {
|
|
253
|
+
* summary: 'Partially update a user',
|
|
254
|
+
* params: IdParams,
|
|
255
|
+
* body: PatchUserRequest,
|
|
256
|
+
* responses: { 200: { schema: UserResponse } },
|
|
257
|
+
* }
|
|
258
|
+
* )
|
|
259
|
+
* ```
|
|
260
|
+
*/
|
|
261
|
+
export declare function patch<TPath extends string, TBody extends TSchema | undefined = undefined, TQuery extends TSchema | undefined = undefined, TParams extends TSchema | undefined = undefined, TResponses extends ResponsesConfig = ResponsesConfig>(path: TPath, handler: AdonisRouteHandler<TPath, TBody, TQuery, TParams, TResponses>, options: BodyRouteOptions<TBody, TQuery, TParams, TResponses>): AdonisRouteDefinition<TPath, TBody, TQuery, TParams>;
|
|
262
|
+
/**
|
|
263
|
+
* Define a DELETE route with Elysia-style API.
|
|
264
|
+
*
|
|
265
|
+
* @example
|
|
266
|
+
* ```typescript
|
|
267
|
+
* const deleteUser = del('/api/v1/users/:id',
|
|
268
|
+
* async ({ params, reply }) => {
|
|
269
|
+
* const user = await User.findOrFail(params.id)
|
|
270
|
+
* await user.delete()
|
|
271
|
+
* return reply.noContent()
|
|
272
|
+
* },
|
|
273
|
+
* {
|
|
274
|
+
* summary: 'Delete a user',
|
|
275
|
+
* params: IdParams,
|
|
276
|
+
* responses: { 204: null },
|
|
277
|
+
* }
|
|
278
|
+
* )
|
|
279
|
+
* ```
|
|
280
|
+
*/
|
|
281
|
+
export declare function del<TPath extends string, TQuery extends TSchema | undefined = undefined, TParams extends TSchema | undefined = undefined, TResponses extends ResponsesConfig = ResponsesConfig>(path: TPath, handler: AdonisRouteHandler<TPath, undefined, TQuery, TParams, TResponses>, options: GetRouteOptions<TQuery, TParams, TResponses>): AdonisRouteDefinition<TPath, undefined, TQuery, TParams>;
|
|
282
|
+
/**
|
|
283
|
+
* Register all routes from a controller definition with AdonisJS.
|
|
284
|
+
*
|
|
285
|
+
* Uses the function-based `defineRoute`/`defineController` API.
|
|
286
|
+
*
|
|
287
|
+
* @example
|
|
288
|
+
* ```typescript
|
|
289
|
+
* // start/routes.ts
|
|
290
|
+
* import router from '@adonisjs/core/services/router'
|
|
291
|
+
* import app from '@adonisjs/core/services/app'
|
|
292
|
+
* import { registerController } from '@kontract/adonis'
|
|
293
|
+
* import { usersController } from '#controllers/users'
|
|
294
|
+
*
|
|
295
|
+
* // Register controller routes (options parameter is optional)
|
|
296
|
+
* registerController(router, usersController)
|
|
297
|
+
* ```
|
|
298
|
+
*/
|
|
299
|
+
export declare function registerController(router: Router, controller: ControllerDefinition, options?: RegisterControllerOptions): void;
|
|
300
|
+
/**
|
|
301
|
+
* Register multiple controllers at once.
|
|
302
|
+
*
|
|
303
|
+
* @example
|
|
304
|
+
* ```typescript
|
|
305
|
+
* registerControllers(router, [
|
|
306
|
+
* usersController,
|
|
307
|
+
* postsController,
|
|
308
|
+
* commentsController,
|
|
309
|
+
* ], options)
|
|
310
|
+
* ```
|
|
311
|
+
*/
|
|
312
|
+
export declare function registerControllers(router: Router, controllers: ControllerDefinition[], options?: RegisterControllerOptions): void;
|
|
313
|
+
//# sourceMappingURL=controller-registrar.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"controller-registrar.d.ts","sourceRoot":"","sources":["../../src/adapters/controller-registrar.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAA;AAC9D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAA;AAC9D,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAA;AAExD,OAAO,EACL,KAAK,oBAAoB,EACzB,KAAK,eAAe,EAEpB,KAAK,WAAW,EAEhB,KAAK,WAAW,EAChB,KAAK,WAAW,EAEhB,KAAK,WAAW,EAChB,KAAK,eAAe,EAGpB,KAAK,cAAc,EAMnB,SAAS,EACV,MAAM,UAAU,CAAA;AAGjB,OAAO,EAAE,SAAS,EAAE,CAAA;AAEpB;;;GAGG;AACH,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,SAAS,OAAO,EAAE,MAAM,EAAE,CAAC,EAAE,IAAI,EAAE,OAAO,KAAK,MAAM,CAAC,CAAC,CAAC,CAAA;AAEnF;;GAEG;AACH,MAAM,WAAW,yBAAyB;IACxC;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,UAAU,CAAA;IAErB;;;OAGG;IACH,SAAS,CAAC,EAAE,kBAAkB,CAAC,WAAW,CAAC,CAAA;CAC5C;AAGD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAA;AAMjD;;GAEG;AACH,KAAK,WAAW,CAAC,UAAU,EAAE,MAAM,SAAS,MAAM,IAC9C,iBAAiB,CAAC,UAAU,EAAE,MAAM,CAAC,SAAS,OAAO,GACnD,CAAC,IAAI,EAAE,MAAM,CAAC,iBAAiB,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC,KAAK,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,iBAAiB,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC,GAC3H,KAAK,CAAA;AAEX;;;;;GAKG;AACH,KAAK,gBAAgB,CAAC,UAAU,EAAE,MAAM,SAAS,MAAM,IACnD,iBAAiB,CAAC,UAAU,EAAE,MAAM,CAAC,SAAS,OAAO,GACnD,CAAC,aAAa,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,iBAAiB,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC,KAC/E,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,iBAAiB,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC,GACnE,KAAK,CAAA;AAEX;;;GAGG;AACH,MAAM,MAAM,YAAY,CAAC,UAAU,SAAS,eAAe,IACrD,CAAC,GAAG,SAAS,MAAM,UAAU,GAAG;IAAE,EAAE,EAAE,WAAW,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;IAAC,IAAI,EAAE,WAAW,CAAC,UAAU,EAAE,GAAG,CAAC,CAAA;CAAE,GAAG,OAAO,CAAC,GACnH,CAAC,GAAG,SAAS,MAAM,UAAU,GAAG;IAAE,OAAO,EAAE,WAAW,CAAC,UAAU,EAAE,GAAG,CAAC,CAAA;CAAE,GAAG,OAAO,CAAC,GACpF,CAAC,GAAG,SAAS,MAAM,UAAU,GAAG;IAAE,QAAQ,EAAE,WAAW,CAAC,UAAU,EAAE,GAAG,CAAC,CAAA;CAAE,GAAG,OAAO,CAAC,GACrF,CAAC,GAAG,SAAS,MAAM,UAAU,GAAG;IAAE,SAAS,EAAE,MAAM,WAAW,CAAC,GAAG,EAAE,IAAI,CAAC,CAAA;CAAE,GAAG,OAAO,CAAC,CAAA;AAE5F;;;;;;;;;;GAUG;AACH,MAAM,MAAM,YAAY,CAAC,UAAU,SAAS,eAAe,IACrD,CAAC,GAAG,SAAS,MAAM,UAAU,GAAG;IAAE,UAAU,EAAE,gBAAgB,CAAC,UAAU,EAAE,GAAG,CAAC,CAAA;CAAE,GAAG,OAAO,CAAC,GAC5F,CAAC,GAAG,SAAS,MAAM,UAAU,GAAG;IAAE,YAAY,EAAE,gBAAgB,CAAC,UAAU,EAAE,GAAG,CAAC,CAAA;CAAE,GAAG,OAAO,CAAC,GAC9F,CAAC,GAAG,SAAS,MAAM,UAAU,GAAG;IAAE,SAAS,EAAE,gBAAgB,CAAC,UAAU,EAAE,GAAG,CAAC,CAAA;CAAE,GAAG,OAAO,CAAC,GAC3F,CAAC,GAAG,SAAS,MAAM,UAAU,GAAG;IAAE,QAAQ,EAAE,gBAAgB,CAAC,UAAU,EAAE,GAAG,CAAC,CAAA;CAAE,GAAG,OAAO,CAAC,GAC1F,CAAC,GAAG,SAAS,MAAM,UAAU,GAAG;IAAE,QAAQ,EAAE,gBAAgB,CAAC,UAAU,EAAE,GAAG,CAAC,CAAA;CAAE,GAAG,OAAO,CAAC,GAC1F,CAAC,GAAG,SAAS,MAAM,UAAU,GAAG;IAAE,eAAe,EAAE,gBAAgB,CAAC,UAAU,EAAE,GAAG,CAAC,CAAA;CAAE,GAAG,OAAO,CAAC,GACjG,CAAC,GAAG,SAAS,MAAM,UAAU,GAAG;IAAE,eAAe,EAAE,gBAAgB,CAAC,UAAU,EAAE,GAAG,CAAC,CAAA;CAAE,GAAG,OAAO,CAAC,GACjG,CAAC,GAAG,SAAS,MAAM,UAAU,GAAG;IAAE,QAAQ,EAAE,gBAAgB,CAAC,UAAU,EAAE,GAAG,CAAC,CAAA;CAAE,GAAG,OAAO,CAAC,GAC1F,CAAC,GAAG,SAAS,MAAM,UAAU,GAAG;IAAE,kBAAkB,EAAE,gBAAgB,CAAC,UAAU,EAAE,GAAG,CAAC,CAAA;CAAE,GAAG,OAAO,CAAC,CAAA;AAM1G;;;;;;GAMG;AACH,MAAM,WAAW,oBAAoB,CACnC,KAAK,SAAS,MAAM,GAAG,MAAM,EAC7B,KAAK,SAAS,OAAO,GAAG,SAAS,GAAG,SAAS,EAC7C,MAAM,SAAS,OAAO,GAAG,SAAS,GAAG,SAAS,EAC9C,OAAO,SAAS,OAAO,GAAG,SAAS,GAAG,SAAS,EAC/C,UAAU,SAAS,eAAe,GAAG,eAAe;IAEpD,sDAAsD;IACtD,IAAI,EAAE,KAAK,SAAS,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,SAAS,CAAA;IACvD,2DAA2D;IAC3D,KAAK,EAAE,MAAM,SAAS,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,GAAG,SAAS,CAAA;IAC1D,+EAA+E;IAC/E,MAAM,EAAE,OAAO,SAAS,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,cAAc,CAAC,KAAK,CAAC,CAAA;IACzE,2EAA2E;IAC3E,IAAI,EAAE,OAAO,CAAA;IACb,gCAAgC;IAChC,GAAG,EAAE,WAAW,CAAA;IAChB,iFAAiF;IACjF,GAAG,EAAE,WAAW,CAAA;IAChB,gDAAgD;IAChD,SAAS,CAAC,EAAE,kBAAkB,CAAC,WAAW,CAAC,CAAA;IAE3C,2EAA2E;IAC3E,KAAK,EAAE,YAAY,CAAC,UAAU,CAAC,CAAA;IAC/B,6EAA6E;IAC7E,KAAK,EAAE,YAAY,CAAC,UAAU,CAAC,CAAA;CAChC;AAED;;;GAGG;AACH,MAAM,MAAM,kBAAkB,CAC5B,KAAK,SAAS,MAAM,GAAG,MAAM,EAC7B,KAAK,SAAS,OAAO,GAAG,SAAS,GAAG,SAAS,EAC7C,MAAM,SAAS,OAAO,GAAG,SAAS,GAAG,SAAS,EAC9C,OAAO,SAAS,OAAO,GAAG,SAAS,GAAG,SAAS,EAC/C,UAAU,SAAS,eAAe,GAAG,eAAe,IAClD,CAAC,GAAG,EAAE,oBAAoB,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,CAAC,KAAK,OAAO,CAAC,WAAW,CAAC,GAAG,WAAW,CAAA;AAEhH;;GAEG;AAEH,KAAK,UAAU,GAAG,GAAG,CAAA;AAErB;;GAEG;AACH,MAAM,WAAW,iBAAiB,CAChC,KAAK,SAAS,OAAO,GAAG,SAAS,GAAG,SAAS,EAC7C,MAAM,SAAS,OAAO,GAAG,SAAS,GAAG,SAAS,EAC9C,OAAO,SAAS,OAAO,GAAG,SAAS,GAAG,SAAS,EAC/C,UAAU,SAAS,eAAe,GAAG,eAAe,CACpD,SAAQ,WAAW,CAAC,WAAW,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC;IACxD,iDAAiD;IACjD,UAAU,CAAC,EAAE,UAAU,EAAE,CAAA;IACzB,0CAA0C;IAC1C,SAAS,EAAE,UAAU,CAAA;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,qBAAqB,CACpC,KAAK,SAAS,MAAM,GAAG,MAAM,EAC7B,KAAK,SAAS,OAAO,GAAG,SAAS,GAAG,SAAS,EAC7C,MAAM,SAAS,OAAO,GAAG,SAAS,GAAG,SAAS,EAC9C,OAAO,SAAS,OAAO,GAAG,SAAS,GAAG,SAAS,CAC/C,SAAQ,eAAe,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC;IACtD,iDAAiD;IACjD,UAAU,CAAC,EAAE,UAAU,EAAE,CAAA;CAC1B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,SAAS,MAAM,GAAG,MAAM,EAC7B,KAAK,SAAS,OAAO,GAAG,SAAS,GAAG,SAAS,EAC7C,MAAM,SAAS,OAAO,GAAG,SAAS,GAAG,SAAS,EAC9C,OAAO,SAAS,OAAO,GAAG,SAAS,GAAG,SAAS,EAC/C,UAAU,SAAS,eAAe,GAAG,eAAe,EAEpD,MAAM,EAAE,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,CAAC,EAC7D,OAAO,EAAE,kBAAkB,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,CAAC,GACrE,qBAAqB,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,CActD;AAMD;;GAEG;AACH,MAAM,MAAM,eAAe,CACzB,MAAM,SAAS,OAAO,GAAG,SAAS,GAAG,SAAS,EAC9C,OAAO,SAAS,OAAO,GAAG,SAAS,GAAG,SAAS,EAC/C,UAAU,SAAS,eAAe,GAAG,eAAe,IAClD,IAAI,CAAC,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC,CAAA;AAErF;;GAEG;AACH,MAAM,MAAM,gBAAgB,CAC1B,KAAK,SAAS,OAAO,GAAG,SAAS,GAAG,SAAS,EAC7C,MAAM,SAAS,OAAO,GAAG,SAAS,GAAG,SAAS,EAC9C,OAAO,SAAS,OAAO,GAAG,SAAS,GAAG,SAAS,EAC/C,UAAU,SAAS,eAAe,GAAG,eAAe,IAClD,IAAI,CAAC,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,CAAC,EAAE,OAAO,CAAC,CAAA;AAExE;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,GAAG,CACjB,KAAK,SAAS,MAAM,EACpB,MAAM,SAAS,OAAO,GAAG,SAAS,GAAG,SAAS,EAC9C,OAAO,SAAS,OAAO,GAAG,SAAS,GAAG,SAAS,EAC/C,UAAU,SAAS,eAAe,GAAG,eAAe,EAEpD,IAAI,EAAE,KAAK,EACX,OAAO,EAAE,kBAAkB,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,CAAC,EAC1E,OAAO,EAAE,eAAe,CAAC,MAAM,EAAE,OAAO,EAAE,UAAU,CAAC,GACpD,qBAAqB,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,CAK1D;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,IAAI,CAClB,KAAK,SAAS,MAAM,EACpB,KAAK,SAAS,OAAO,GAAG,SAAS,GAAG,SAAS,EAC7C,MAAM,SAAS,OAAO,GAAG,SAAS,GAAG,SAAS,EAC9C,OAAO,SAAS,OAAO,GAAG,SAAS,GAAG,SAAS,EAC/C,UAAU,SAAS,eAAe,GAAG,eAAe,EAEpD,IAAI,EAAE,KAAK,EACX,OAAO,EAAE,kBAAkB,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,CAAC,EACtE,OAAO,EAAE,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,CAAC,GAC5D,qBAAqB,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,CAKtD;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,GAAG,CACjB,KAAK,SAAS,MAAM,EACpB,KAAK,SAAS,OAAO,GAAG,SAAS,GAAG,SAAS,EAC7C,MAAM,SAAS,OAAO,GAAG,SAAS,GAAG,SAAS,EAC9C,OAAO,SAAS,OAAO,GAAG,SAAS,GAAG,SAAS,EAC/C,UAAU,SAAS,eAAe,GAAG,eAAe,EAEpD,IAAI,EAAE,KAAK,EACX,OAAO,EAAE,kBAAkB,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,CAAC,EACtE,OAAO,EAAE,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,CAAC,GAC5D,qBAAqB,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,CAKtD;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,KAAK,CACnB,KAAK,SAAS,MAAM,EACpB,KAAK,SAAS,OAAO,GAAG,SAAS,GAAG,SAAS,EAC7C,MAAM,SAAS,OAAO,GAAG,SAAS,GAAG,SAAS,EAC9C,OAAO,SAAS,OAAO,GAAG,SAAS,GAAG,SAAS,EAC/C,UAAU,SAAS,eAAe,GAAG,eAAe,EAEpD,IAAI,EAAE,KAAK,EACX,OAAO,EAAE,kBAAkB,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,CAAC,EACtE,OAAO,EAAE,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,CAAC,GAC5D,qBAAqB,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,CAKtD;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,GAAG,CACjB,KAAK,SAAS,MAAM,EACpB,MAAM,SAAS,OAAO,GAAG,SAAS,GAAG,SAAS,EAC9C,OAAO,SAAS,OAAO,GAAG,SAAS,GAAG,SAAS,EAC/C,UAAU,SAAS,eAAe,GAAG,eAAe,EAEpD,IAAI,EAAE,KAAK,EACX,OAAO,EAAE,kBAAkB,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,CAAC,EAC1E,OAAO,EAAE,eAAe,CAAC,MAAM,EAAE,OAAO,EAAE,UAAU,CAAC,GACpD,qBAAqB,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,CAK1D;AAyJD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,oBAAoB,EAChC,OAAO,GAAE,yBAA8B,GACtC,IAAI,CAMN;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,oBAAoB,EAAE,EACnC,OAAO,GAAE,yBAA8B,GACtC,IAAI,CAIN"}
|
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
import { validate as defaultValidate } from '@kontract/ajv';
|
|
2
|
+
import { getControllerRoutes, isBinaryResponse, getParamsSchema, parseRouteString, normalizeResponses, createResponseHelpers, isApiResponse, noContent, } from 'kontract';
|
|
3
|
+
// Re-export noContent for convenience
|
|
4
|
+
export { noContent };
|
|
5
|
+
/**
|
|
6
|
+
* Define an AdonisJS route with properly typed context and response helpers.
|
|
7
|
+
*
|
|
8
|
+
* This is a wrapper around `defineRoute` that provides AdonisJS-specific
|
|
9
|
+
* typed context including `ctx` (HttpContext), `container`, and pre-typed
|
|
10
|
+
* namespaced response helpers based on the responses config.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```typescript
|
|
14
|
+
* import { defineAdonisRoute, defineController } from '@kontract/adonis'
|
|
15
|
+
* import StatsService from '#services/stats_service'
|
|
16
|
+
*
|
|
17
|
+
* const getStats = defineAdonisRoute({
|
|
18
|
+
* route: 'GET /api/v1/stats',
|
|
19
|
+
* responses: {
|
|
20
|
+
* 200: { schema: StatsResponse },
|
|
21
|
+
* 401: { schema: ApiError },
|
|
22
|
+
* },
|
|
23
|
+
* }, async ({ ctx, reply, error }) => {
|
|
24
|
+
* // ctx is typed as HttpContext
|
|
25
|
+
* // reply.ok() and error.unauthorized() are pre-typed from responses config
|
|
26
|
+
* const statsService = await ctx.containerResolver.make(StatsService)
|
|
27
|
+
* return reply.ok(await statsService.getOverview())
|
|
28
|
+
* })
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
export function defineAdonisRoute(config, handler) {
|
|
32
|
+
const [method, path] = parseRouteString(config.route);
|
|
33
|
+
return {
|
|
34
|
+
__type: 'route',
|
|
35
|
+
method: method,
|
|
36
|
+
path: path,
|
|
37
|
+
config,
|
|
38
|
+
responses: normalizeResponses(config.responses),
|
|
39
|
+
// Cast handler to the generic RouteHandler type
|
|
40
|
+
// The actual context will be AdonisHandlerContext at runtime
|
|
41
|
+
handler: handler,
|
|
42
|
+
middleware: config.middleware,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Define a GET route with Elysia-style API.
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* ```typescript
|
|
50
|
+
* const listUsers = get('/api/v1/users',
|
|
51
|
+
* async ({ query, reply }) => {
|
|
52
|
+
* const users = await User.query().paginate(query.page, query.perPage)
|
|
53
|
+
* return reply.list(users)
|
|
54
|
+
* },
|
|
55
|
+
* {
|
|
56
|
+
* summary: 'List users',
|
|
57
|
+
* query: UserQueryParams,
|
|
58
|
+
* responses: { 200: { schema: UserListResponse } },
|
|
59
|
+
* }
|
|
60
|
+
* )
|
|
61
|
+
* ```
|
|
62
|
+
*/
|
|
63
|
+
export function get(path, handler, options) {
|
|
64
|
+
return defineAdonisRoute({ ...options, route: `GET ${path}` }, handler);
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Define a POST route with Elysia-style API.
|
|
68
|
+
*
|
|
69
|
+
* @example
|
|
70
|
+
* ```typescript
|
|
71
|
+
* const createUser = post('/api/v1/users',
|
|
72
|
+
* async ({ body, reply }) => {
|
|
73
|
+
* const user = await User.create(body)
|
|
74
|
+
* return reply.created(user)
|
|
75
|
+
* },
|
|
76
|
+
* {
|
|
77
|
+
* summary: 'Create a user',
|
|
78
|
+
* body: CreateUserRequest,
|
|
79
|
+
* responses: {
|
|
80
|
+
* 201: { schema: UserResponse },
|
|
81
|
+
* 400: { schema: ApiError },
|
|
82
|
+
* },
|
|
83
|
+
* }
|
|
84
|
+
* )
|
|
85
|
+
* ```
|
|
86
|
+
*/
|
|
87
|
+
export function post(path, handler, options) {
|
|
88
|
+
return defineAdonisRoute({ ...options, route: `POST ${path}` }, handler);
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Define a PUT route with Elysia-style API.
|
|
92
|
+
*
|
|
93
|
+
* @example
|
|
94
|
+
* ```typescript
|
|
95
|
+
* const updateUser = put('/api/v1/users/:id',
|
|
96
|
+
* async ({ params, body, reply }) => {
|
|
97
|
+
* const user = await User.findOrFail(params.id)
|
|
98
|
+
* user.merge(body)
|
|
99
|
+
* await user.save()
|
|
100
|
+
* return reply.ok(user)
|
|
101
|
+
* },
|
|
102
|
+
* {
|
|
103
|
+
* summary: 'Update a user',
|
|
104
|
+
* params: IdParams,
|
|
105
|
+
* body: UpdateUserRequest,
|
|
106
|
+
* responses: { 200: { schema: UserResponse } },
|
|
107
|
+
* }
|
|
108
|
+
* )
|
|
109
|
+
* ```
|
|
110
|
+
*/
|
|
111
|
+
export function put(path, handler, options) {
|
|
112
|
+
return defineAdonisRoute({ ...options, route: `PUT ${path}` }, handler);
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Define a PATCH route with Elysia-style API.
|
|
116
|
+
*
|
|
117
|
+
* @example
|
|
118
|
+
* ```typescript
|
|
119
|
+
* const patchUser = patch('/api/v1/users/:id',
|
|
120
|
+
* async ({ params, body, reply }) => {
|
|
121
|
+
* const user = await User.findOrFail(params.id)
|
|
122
|
+
* user.merge(body)
|
|
123
|
+
* await user.save()
|
|
124
|
+
* return reply.ok(user)
|
|
125
|
+
* },
|
|
126
|
+
* {
|
|
127
|
+
* summary: 'Partially update a user',
|
|
128
|
+
* params: IdParams,
|
|
129
|
+
* body: PatchUserRequest,
|
|
130
|
+
* responses: { 200: { schema: UserResponse } },
|
|
131
|
+
* }
|
|
132
|
+
* )
|
|
133
|
+
* ```
|
|
134
|
+
*/
|
|
135
|
+
export function patch(path, handler, options) {
|
|
136
|
+
return defineAdonisRoute({ ...options, route: `PATCH ${path}` }, handler);
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Define a DELETE route with Elysia-style API.
|
|
140
|
+
*
|
|
141
|
+
* @example
|
|
142
|
+
* ```typescript
|
|
143
|
+
* const deleteUser = del('/api/v1/users/:id',
|
|
144
|
+
* async ({ params, reply }) => {
|
|
145
|
+
* const user = await User.findOrFail(params.id)
|
|
146
|
+
* await user.delete()
|
|
147
|
+
* return reply.noContent()
|
|
148
|
+
* },
|
|
149
|
+
* {
|
|
150
|
+
* summary: 'Delete a user',
|
|
151
|
+
* params: IdParams,
|
|
152
|
+
* responses: { 204: null },
|
|
153
|
+
* }
|
|
154
|
+
* )
|
|
155
|
+
* ```
|
|
156
|
+
*/
|
|
157
|
+
export function del(path, handler, options) {
|
|
158
|
+
return defineAdonisRoute({ ...options, route: `DELETE ${path}` }, handler);
|
|
159
|
+
}
|
|
160
|
+
// ============================================================================
|
|
161
|
+
// Response Handling
|
|
162
|
+
// ============================================================================
|
|
163
|
+
/**
|
|
164
|
+
* Handle the response from a route handler.
|
|
165
|
+
*/
|
|
166
|
+
function handleResponse(ctx, result) {
|
|
167
|
+
// Binary response (file downloads)
|
|
168
|
+
if (isBinaryResponse(result)) {
|
|
169
|
+
ctx.response.header('Content-Type', result.contentType);
|
|
170
|
+
if (result.filename) {
|
|
171
|
+
ctx.response.header('Content-Disposition', `attachment; filename="${result.filename}"`);
|
|
172
|
+
}
|
|
173
|
+
return ctx.response.status(result.status).send(result.data);
|
|
174
|
+
}
|
|
175
|
+
// Structured API response
|
|
176
|
+
if (isApiResponse(result)) {
|
|
177
|
+
if (result.status === 204) {
|
|
178
|
+
return ctx.response.noContent();
|
|
179
|
+
}
|
|
180
|
+
return ctx.response.status(result.status).json(result.data);
|
|
181
|
+
}
|
|
182
|
+
// Raw result (fallback)
|
|
183
|
+
return result;
|
|
184
|
+
}
|
|
185
|
+
// ============================================================================
|
|
186
|
+
// Route Registration
|
|
187
|
+
// ============================================================================
|
|
188
|
+
/**
|
|
189
|
+
* Create an AdonisJS request handler for a route definition.
|
|
190
|
+
*/
|
|
191
|
+
function createHandler(route, options) {
|
|
192
|
+
const validate = options.validate ?? defaultValidate;
|
|
193
|
+
const { container } = options;
|
|
194
|
+
return async (ctx) => {
|
|
195
|
+
// 1. Authentication
|
|
196
|
+
// Auth is added by AdonisJS auth package, so we need to cast
|
|
197
|
+
const authCtx = ctx;
|
|
198
|
+
let user;
|
|
199
|
+
if (route.config.auth === 'required') {
|
|
200
|
+
await authCtx.auth.authenticate();
|
|
201
|
+
user = authCtx.auth.user;
|
|
202
|
+
}
|
|
203
|
+
else if (route.config.auth === 'optional') {
|
|
204
|
+
try {
|
|
205
|
+
await authCtx.auth.authenticate();
|
|
206
|
+
user = authCtx.auth.user;
|
|
207
|
+
}
|
|
208
|
+
catch {
|
|
209
|
+
// Ignore auth errors for optional auth
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
// 2. Validation
|
|
213
|
+
let body;
|
|
214
|
+
let query;
|
|
215
|
+
let params;
|
|
216
|
+
if (route.config.body) {
|
|
217
|
+
body = validate(route.config.body, ctx.request.body());
|
|
218
|
+
}
|
|
219
|
+
if (route.config.query) {
|
|
220
|
+
query = validate(route.config.query, ctx.request.qs());
|
|
221
|
+
}
|
|
222
|
+
// Use explicit params schema or auto-generate from path
|
|
223
|
+
const paramsSchema = getParamsSchema(route.path, route.config.params);
|
|
224
|
+
if (paramsSchema) {
|
|
225
|
+
params = validate(paramsSchema, ctx.params);
|
|
226
|
+
}
|
|
227
|
+
// 3. Create namespaced response helpers
|
|
228
|
+
const { reply, error } = createResponseHelpers(route.responses);
|
|
229
|
+
// 4. Build handler context with AdonisJS extensions and response helpers
|
|
230
|
+
const handlerCtx = {
|
|
231
|
+
body: body,
|
|
232
|
+
query: query,
|
|
233
|
+
params: params,
|
|
234
|
+
user,
|
|
235
|
+
raw: ctx,
|
|
236
|
+
ctx,
|
|
237
|
+
container,
|
|
238
|
+
// Namespaced response helpers
|
|
239
|
+
reply: reply,
|
|
240
|
+
error: error,
|
|
241
|
+
};
|
|
242
|
+
// 5. Execute handler
|
|
243
|
+
if (!route.handler) {
|
|
244
|
+
throw new Error(`Route ${route.method.toUpperCase()} ${route.path} has no handler. `
|
|
245
|
+
+ 'Contract-only routes cannot be registered with a server adapter.');
|
|
246
|
+
}
|
|
247
|
+
const result = await route.handler(handlerCtx);
|
|
248
|
+
// 6. Handle response
|
|
249
|
+
return handleResponse(ctx, result);
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Register a single route definition with AdonisJS router.
|
|
254
|
+
*/
|
|
255
|
+
function registerRoute(router, route, path, options) {
|
|
256
|
+
const handler = createHandler(route, options);
|
|
257
|
+
// Cast to get middleware property from AdonisRouteDefinition
|
|
258
|
+
const adonisRoute = route;
|
|
259
|
+
let registeredRoute;
|
|
260
|
+
switch (route.method) {
|
|
261
|
+
case 'get':
|
|
262
|
+
registeredRoute = router.get(path, handler);
|
|
263
|
+
break;
|
|
264
|
+
case 'post':
|
|
265
|
+
registeredRoute = router.post(path, handler);
|
|
266
|
+
break;
|
|
267
|
+
case 'put':
|
|
268
|
+
registeredRoute = router.put(path, handler);
|
|
269
|
+
break;
|
|
270
|
+
case 'patch':
|
|
271
|
+
registeredRoute = router.patch(path, handler);
|
|
272
|
+
break;
|
|
273
|
+
case 'delete':
|
|
274
|
+
registeredRoute = router.delete(path, handler);
|
|
275
|
+
break;
|
|
276
|
+
default:
|
|
277
|
+
throw new Error(`Unsupported HTTP method: ${route.method}`);
|
|
278
|
+
}
|
|
279
|
+
// Apply middleware if specified
|
|
280
|
+
if (adonisRoute.middleware && adonisRoute.middleware.length > 0) {
|
|
281
|
+
registeredRoute.use(adonisRoute.middleware);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* Register all routes from a controller definition with AdonisJS.
|
|
286
|
+
*
|
|
287
|
+
* Uses the function-based `defineRoute`/`defineController` API.
|
|
288
|
+
*
|
|
289
|
+
* @example
|
|
290
|
+
* ```typescript
|
|
291
|
+
* // start/routes.ts
|
|
292
|
+
* import router from '@adonisjs/core/services/router'
|
|
293
|
+
* import app from '@adonisjs/core/services/app'
|
|
294
|
+
* import { registerController } from '@kontract/adonis'
|
|
295
|
+
* import { usersController } from '#controllers/users'
|
|
296
|
+
*
|
|
297
|
+
* // Register controller routes (options parameter is optional)
|
|
298
|
+
* registerController(router, usersController)
|
|
299
|
+
* ```
|
|
300
|
+
*/
|
|
301
|
+
export function registerController(router, controller, options = {}) {
|
|
302
|
+
const routes = getControllerRoutes(controller);
|
|
303
|
+
for (const { route, fullPath } of routes) {
|
|
304
|
+
registerRoute(router, route, fullPath, options);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
/**
|
|
308
|
+
* Register multiple controllers at once.
|
|
309
|
+
*
|
|
310
|
+
* @example
|
|
311
|
+
* ```typescript
|
|
312
|
+
* registerControllers(router, [
|
|
313
|
+
* usersController,
|
|
314
|
+
* postsController,
|
|
315
|
+
* commentsController,
|
|
316
|
+
* ], options)
|
|
317
|
+
* ```
|
|
318
|
+
*/
|
|
319
|
+
export function registerControllers(router, controllers, options = {}) {
|
|
320
|
+
for (const controller of controllers) {
|
|
321
|
+
registerController(router, controller, options);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
//# sourceMappingURL=controller-registrar.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"controller-registrar.js","sourceRoot":"","sources":["../../src/adapters/controller-registrar.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export { registerController, registerControllers, defineAdonisRoute, noContent, type RegisterControllerOptions, type AdonisHandlerContext, type AdonisRouteHandler, type AdonisRouteConfig, type AdonisRouteDefinition, } from './controller-registrar.js';
|
|
2
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/adapters/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAClB,mBAAmB,EACnB,iBAAiB,EACjB,SAAS,EACT,KAAK,yBAAyB,EAC9B,KAAK,oBAAoB,EACzB,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,KAAK,qBAAqB,GAC3B,MAAM,2BAA2B,CAAA"}
|