kontract 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 +435 -0
- package/dist/builder/define-controller.d.ts +115 -0
- package/dist/builder/define-controller.d.ts.map +1 -0
- package/dist/builder/define-controller.js +80 -0
- package/dist/builder/define-controller.js.map +1 -0
- package/dist/builder/define-endpoint.d.ts +157 -0
- package/dist/builder/define-endpoint.d.ts.map +1 -0
- package/dist/builder/define-endpoint.js +103 -0
- package/dist/builder/define-endpoint.js.map +1 -0
- package/dist/builder/define-route.d.ts +191 -0
- package/dist/builder/define-route.d.ts.map +1 -0
- package/dist/builder/define-route.js +124 -0
- package/dist/builder/define-route.js.map +1 -0
- package/dist/builder/index.d.ts +5 -0
- package/dist/builder/index.d.ts.map +1 -0
- package/dist/builder/index.js +7 -0
- package/dist/builder/index.js.map +1 -0
- package/dist/builder/openapi-builder.d.ts +120 -0
- package/dist/builder/openapi-builder.d.ts.map +1 -0
- package/dist/builder/openapi-builder.js +349 -0
- package/dist/builder/openapi-builder.js.map +1 -0
- package/dist/builder/path-params.d.ts +129 -0
- package/dist/builder/path-params.d.ts.map +1 -0
- package/dist/builder/path-params.js +85 -0
- package/dist/builder/path-params.js.map +1 -0
- package/dist/builder/types.d.ts +149 -0
- package/dist/builder/types.d.ts.map +1 -0
- package/dist/builder/types.js +6 -0
- package/dist/builder/types.js.map +1 -0
- package/dist/config/defaults.d.ts +10 -0
- package/dist/config/defaults.d.ts.map +1 -0
- package/dist/config/defaults.js +28 -0
- package/dist/config/defaults.js.map +1 -0
- package/dist/config/define-config.d.ts +50 -0
- package/dist/config/define-config.d.ts.map +1 -0
- package/dist/config/define-config.js +80 -0
- package/dist/config/define-config.js.map +1 -0
- package/dist/config/index.d.ts +4 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +5 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/types.d.ts +103 -0
- package/dist/config/types.d.ts.map +1 -0
- package/dist/config/types.js +2 -0
- package/dist/config/types.js.map +1 -0
- package/dist/decorators/api.d.ts +35 -0
- package/dist/decorators/api.d.ts.map +1 -0
- package/dist/decorators/api.js +34 -0
- package/dist/decorators/api.js.map +1 -0
- package/dist/decorators/controller.d.ts +35 -0
- package/dist/decorators/controller.d.ts.map +1 -0
- package/dist/decorators/controller.js +34 -0
- package/dist/decorators/controller.js.map +1 -0
- package/dist/decorators/endpoint.d.ts +93 -0
- package/dist/decorators/endpoint.d.ts.map +1 -0
- package/dist/decorators/endpoint.js +108 -0
- package/dist/decorators/endpoint.js.map +1 -0
- package/dist/decorators/index.d.ts +5 -0
- package/dist/decorators/index.d.ts.map +1 -0
- package/dist/decorators/index.js +6 -0
- package/dist/decorators/index.js.map +1 -0
- package/dist/decorators/route.d.ts +93 -0
- package/dist/decorators/route.d.ts.map +1 -0
- package/dist/decorators/route.js +108 -0
- package/dist/decorators/route.js.map +1 -0
- package/dist/errors/base.d.ts +8 -0
- package/dist/errors/base.d.ts.map +1 -0
- package/dist/errors/base.js +13 -0
- package/dist/errors/base.js.map +1 -0
- package/dist/errors/configuration.d.ts +22 -0
- package/dist/errors/configuration.d.ts.map +1 -0
- package/dist/errors/configuration.js +33 -0
- package/dist/errors/configuration.js.map +1 -0
- package/dist/errors/index.d.ts +4 -0
- package/dist/errors/index.d.ts.map +1 -0
- package/dist/errors/index.js +4 -0
- package/dist/errors/index.js.map +1 -0
- package/dist/errors/validation.d.ts +46 -0
- package/dist/errors/validation.d.ts.map +1 -0
- package/dist/errors/validation.js +52 -0
- package/dist/errors/validation.js.map +1 -0
- package/dist/index.d.ts +48 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +44 -0
- package/dist/index.js.map +1 -0
- package/dist/metadata/index.d.ts +2 -0
- package/dist/metadata/index.d.ts.map +1 -0
- package/dist/metadata/index.js +2 -0
- package/dist/metadata/index.js.map +1 -0
- package/dist/metadata/storage.d.ts +50 -0
- package/dist/metadata/storage.d.ts.map +1 -0
- package/dist/metadata/storage.js +100 -0
- package/dist/metadata/storage.js.map +1 -0
- package/dist/metadata/types.d.ts +142 -0
- package/dist/metadata/types.d.ts.map +1 -0
- package/dist/metadata/types.js +2 -0
- package/dist/metadata/types.js.map +1 -0
- package/dist/response/helpers.d.ts +132 -0
- package/dist/response/helpers.d.ts.map +1 -0
- package/dist/response/helpers.js +197 -0
- package/dist/response/helpers.js.map +1 -0
- package/dist/response/index.d.ts +4 -0
- package/dist/response/index.d.ts.map +1 -0
- package/dist/response/index.js +4 -0
- package/dist/response/index.js.map +1 -0
- package/dist/response/types.d.ts +59 -0
- package/dist/response/types.d.ts.map +1 -0
- package/dist/response/types.js +26 -0
- package/dist/response/types.js.map +1 -0
- package/dist/runtime/adapter-types.d.ts +119 -0
- package/dist/runtime/adapter-types.d.ts.map +1 -0
- package/dist/runtime/adapter-types.js +2 -0
- package/dist/runtime/adapter-types.js.map +1 -0
- package/dist/runtime/index.d.ts +12 -0
- package/dist/runtime/index.d.ts.map +1 -0
- package/dist/runtime/index.js +10 -0
- package/dist/runtime/index.js.map +1 -0
- package/dist/runtime/response-helpers.d.ts +138 -0
- package/dist/runtime/response-helpers.d.ts.map +1 -0
- package/dist/runtime/response-helpers.js +105 -0
- package/dist/runtime/response-helpers.js.map +1 -0
- package/dist/runtime/route-utils.d.ts +22 -0
- package/dist/runtime/route-utils.d.ts.map +1 -0
- package/dist/runtime/route-utils.js +47 -0
- package/dist/runtime/route-utils.js.map +1 -0
- package/dist/runtime/types.d.ts +125 -0
- package/dist/runtime/types.d.ts.map +1 -0
- package/dist/runtime/types.js +2 -0
- package/dist/runtime/types.js.map +1 -0
- package/dist/validation/index.d.ts +3 -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/dist/validation/types.d.ts +55 -0
- package/dist/validation/types.d.ts.map +1 -0
- package/dist/validation/types.js +2 -0
- package/dist/validation/types.js.map +1 -0
- package/package.json +93 -0
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Options for the @Controller class decorator.
|
|
3
|
+
*/
|
|
4
|
+
export interface ControllerOptions {
|
|
5
|
+
/** OpenAPI tag for grouping routes */
|
|
6
|
+
tag: string;
|
|
7
|
+
/** Description of the controller/API group */
|
|
8
|
+
description?: string;
|
|
9
|
+
/** Optional path prefix for all routes in this controller */
|
|
10
|
+
prefix?: string;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Class decorator that marks a controller for OpenAPI documentation.
|
|
14
|
+
*
|
|
15
|
+
* The tag is used to group routes in the OpenAPI spec.
|
|
16
|
+
* The optional prefix is prepended to all route paths in this controller.
|
|
17
|
+
*
|
|
18
|
+
* @example Basic usage
|
|
19
|
+
* ```typescript
|
|
20
|
+
* @Controller({ tag: 'Users', description: 'User management routes' })
|
|
21
|
+
* export class UsersController {
|
|
22
|
+
* // routes...
|
|
23
|
+
* }
|
|
24
|
+
* ```
|
|
25
|
+
*
|
|
26
|
+
* @example With prefix
|
|
27
|
+
* ```typescript
|
|
28
|
+
* @Controller({ tag: 'Admin', description: 'Admin routes', prefix: '/admin' })
|
|
29
|
+
* export class AdminController {
|
|
30
|
+
* // All routes in this controller will be prefixed with /admin
|
|
31
|
+
* }
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
export declare function Controller(options: ControllerOptions): ClassDecorator;
|
|
35
|
+
//# sourceMappingURL=controller.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"controller.d.ts","sourceRoot":"","sources":["../../src/decorators/controller.ts"],"names":[],"mappings":"AAGA;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,sCAAsC;IACtC,GAAG,EAAE,MAAM,CAAA;IACX,8CAA8C;IAC9C,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,6DAA6D;IAC7D,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,iBAAiB,GAAG,cAAc,CASrE"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { setApiMetadata } from '../metadata/storage.js';
|
|
2
|
+
/**
|
|
3
|
+
* Class decorator that marks a controller for OpenAPI documentation.
|
|
4
|
+
*
|
|
5
|
+
* The tag is used to group routes in the OpenAPI spec.
|
|
6
|
+
* The optional prefix is prepended to all route paths in this controller.
|
|
7
|
+
*
|
|
8
|
+
* @example Basic usage
|
|
9
|
+
* ```typescript
|
|
10
|
+
* @Controller({ tag: 'Users', description: 'User management routes' })
|
|
11
|
+
* export class UsersController {
|
|
12
|
+
* // routes...
|
|
13
|
+
* }
|
|
14
|
+
* ```
|
|
15
|
+
*
|
|
16
|
+
* @example With prefix
|
|
17
|
+
* ```typescript
|
|
18
|
+
* @Controller({ tag: 'Admin', description: 'Admin routes', prefix: '/admin' })
|
|
19
|
+
* export class AdminController {
|
|
20
|
+
* // All routes in this controller will be prefixed with /admin
|
|
21
|
+
* }
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
export function Controller(options) {
|
|
25
|
+
return function (target) {
|
|
26
|
+
const metadata = {
|
|
27
|
+
tag: options.tag,
|
|
28
|
+
description: options.description,
|
|
29
|
+
prefix: options.prefix,
|
|
30
|
+
};
|
|
31
|
+
setApiMetadata(target, metadata);
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=controller.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"controller.js","sourceRoot":"","sources":["../../src/decorators/controller.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAA;AAevD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,UAAU,UAAU,CAAC,OAA0B;IACnD,OAAO,UAAU,MAAM;QACrB,MAAM,QAAQ,GAAgB;YAC5B,GAAG,EAAE,OAAO,CAAC,GAAG;YAChB,WAAW,EAAE,OAAO,CAAC,WAAW;YAChC,MAAM,EAAE,OAAO,CAAC,MAAM;SACvB,CAAA;QACD,cAAc,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAA;IAClC,CAAC,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import type { TSchema } from '@sinclair/typebox';
|
|
2
|
+
import type { RouteString, FileUploadConfig } from '../metadata/types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Options for the @Endpoint method decorator.
|
|
5
|
+
*/
|
|
6
|
+
export interface EndpointOptions {
|
|
7
|
+
/** Short summary for OpenAPI docs */
|
|
8
|
+
summary?: string;
|
|
9
|
+
/** Detailed description for OpenAPI docs */
|
|
10
|
+
description?: string;
|
|
11
|
+
/** Unique operation ID for OpenAPI (auto-generated if not provided) */
|
|
12
|
+
operationId?: string;
|
|
13
|
+
/** Mark endpoint as deprecated */
|
|
14
|
+
deprecated?: boolean;
|
|
15
|
+
/** Authentication requirement */
|
|
16
|
+
auth?: 'required' | 'optional' | 'none';
|
|
17
|
+
/** Request body schema (TypeBox) */
|
|
18
|
+
body?: TSchema;
|
|
19
|
+
/** Query parameters schema (TypeBox) */
|
|
20
|
+
query?: TSchema;
|
|
21
|
+
/** Path parameters schema (TypeBox) */
|
|
22
|
+
params?: TSchema;
|
|
23
|
+
/** File upload configuration for multipart/form-data */
|
|
24
|
+
file?: FileUploadConfig;
|
|
25
|
+
/**
|
|
26
|
+
* Response definitions by status code.
|
|
27
|
+
* Value can be:
|
|
28
|
+
* - A TypeBox schema
|
|
29
|
+
* - null (for no body, e.g., 204)
|
|
30
|
+
* - An object with schema and optional description
|
|
31
|
+
*/
|
|
32
|
+
responses: Record<number, TSchema | null | {
|
|
33
|
+
schema: TSchema | null;
|
|
34
|
+
description?: string;
|
|
35
|
+
}>;
|
|
36
|
+
/**
|
|
37
|
+
* Framework-specific middleware.
|
|
38
|
+
* This is opaque to the core library - adapters interpret it.
|
|
39
|
+
*/
|
|
40
|
+
middleware?: unknown[];
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Method decorator that defines an API endpoint with full OpenAPI metadata.
|
|
44
|
+
*
|
|
45
|
+
* This decorator captures all information needed to:
|
|
46
|
+
* 1. Register the route with a framework
|
|
47
|
+
* 2. Validate request body, query, and path parameters
|
|
48
|
+
* 3. Generate OpenAPI documentation
|
|
49
|
+
*
|
|
50
|
+
* @param route Route string in format "METHOD /path"
|
|
51
|
+
* @param options Endpoint configuration
|
|
52
|
+
*
|
|
53
|
+
* @example Basic GET endpoint
|
|
54
|
+
* ```typescript
|
|
55
|
+
* @Endpoint('GET /api/v1/users', {
|
|
56
|
+
* summary: 'List all users',
|
|
57
|
+
* responses: {
|
|
58
|
+
* 200: { schema: UserListResponse, description: 'List of users' },
|
|
59
|
+
* },
|
|
60
|
+
* })
|
|
61
|
+
* async index() { ... }
|
|
62
|
+
* ```
|
|
63
|
+
*
|
|
64
|
+
* @example POST with body and auth
|
|
65
|
+
* ```typescript
|
|
66
|
+
* @Endpoint('POST /api/v1/users', {
|
|
67
|
+
* summary: 'Create a user',
|
|
68
|
+
* auth: 'required',
|
|
69
|
+
* body: CreateUserRequest,
|
|
70
|
+
* responses: {
|
|
71
|
+
* 201: { schema: User, description: 'User created' },
|
|
72
|
+
* 422: { schema: ValidationError },
|
|
73
|
+
* },
|
|
74
|
+
* })
|
|
75
|
+
* async store(ctx: Context, body: Static<typeof CreateUserRequest>) { ... }
|
|
76
|
+
* ```
|
|
77
|
+
*
|
|
78
|
+
* @example DELETE with no response body
|
|
79
|
+
* ```typescript
|
|
80
|
+
* @Endpoint('DELETE /api/v1/users/:id', {
|
|
81
|
+
* summary: 'Delete a user',
|
|
82
|
+
* auth: 'required',
|
|
83
|
+
* params: UserIdParams,
|
|
84
|
+
* responses: {
|
|
85
|
+
* 204: null,
|
|
86
|
+
* 404: { schema: NotFoundError },
|
|
87
|
+
* },
|
|
88
|
+
* })
|
|
89
|
+
* async destroy(ctx: Context) { ... }
|
|
90
|
+
* ```
|
|
91
|
+
*/
|
|
92
|
+
export declare function Endpoint(route: RouteString, options: EndpointOptions): MethodDecorator;
|
|
93
|
+
//# sourceMappingURL=endpoint.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"endpoint.d.ts","sourceRoot":"","sources":["../../src/decorators/endpoint.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAA;AAEhD,OAAO,KAAK,EACV,WAAW,EAGX,gBAAgB,EAEjB,MAAM,sBAAsB,CAAA;AAE7B;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,qCAAqC;IACrC,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,4CAA4C;IAC5C,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,uEAAuE;IACvE,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,kCAAkC;IAClC,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,iCAAiC;IACjC,IAAI,CAAC,EAAE,UAAU,GAAG,UAAU,GAAG,MAAM,CAAA;IACvC,oCAAoC;IACpC,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,wCAAwC;IACxC,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,uCAAuC;IACvC,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,wDAAwD;IACxD,IAAI,CAAC,EAAE,gBAAgB,CAAA;IACvB;;;;;;OAMG;IACH,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI,GAAG;QAAE,MAAM,EAAE,OAAO,GAAG,IAAI,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IAC5F;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,EAAE,CAAA;CACvB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;AACH,wBAAgB,QAAQ,CACtB,KAAK,EAAE,WAAW,EAClB,OAAO,EAAE,eAAe,GACvB,eAAe,CAwCjB"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { addEndpointMetadata } from '../metadata/storage.js';
|
|
2
|
+
/**
|
|
3
|
+
* Method decorator that defines an API endpoint with full OpenAPI metadata.
|
|
4
|
+
*
|
|
5
|
+
* This decorator captures all information needed to:
|
|
6
|
+
* 1. Register the route with a framework
|
|
7
|
+
* 2. Validate request body, query, and path parameters
|
|
8
|
+
* 3. Generate OpenAPI documentation
|
|
9
|
+
*
|
|
10
|
+
* @param route Route string in format "METHOD /path"
|
|
11
|
+
* @param options Endpoint configuration
|
|
12
|
+
*
|
|
13
|
+
* @example Basic GET endpoint
|
|
14
|
+
* ```typescript
|
|
15
|
+
* @Endpoint('GET /api/v1/users', {
|
|
16
|
+
* summary: 'List all users',
|
|
17
|
+
* responses: {
|
|
18
|
+
* 200: { schema: UserListResponse, description: 'List of users' },
|
|
19
|
+
* },
|
|
20
|
+
* })
|
|
21
|
+
* async index() { ... }
|
|
22
|
+
* ```
|
|
23
|
+
*
|
|
24
|
+
* @example POST with body and auth
|
|
25
|
+
* ```typescript
|
|
26
|
+
* @Endpoint('POST /api/v1/users', {
|
|
27
|
+
* summary: 'Create a user',
|
|
28
|
+
* auth: 'required',
|
|
29
|
+
* body: CreateUserRequest,
|
|
30
|
+
* responses: {
|
|
31
|
+
* 201: { schema: User, description: 'User created' },
|
|
32
|
+
* 422: { schema: ValidationError },
|
|
33
|
+
* },
|
|
34
|
+
* })
|
|
35
|
+
* async store(ctx: Context, body: Static<typeof CreateUserRequest>) { ... }
|
|
36
|
+
* ```
|
|
37
|
+
*
|
|
38
|
+
* @example DELETE with no response body
|
|
39
|
+
* ```typescript
|
|
40
|
+
* @Endpoint('DELETE /api/v1/users/:id', {
|
|
41
|
+
* summary: 'Delete a user',
|
|
42
|
+
* auth: 'required',
|
|
43
|
+
* params: UserIdParams,
|
|
44
|
+
* responses: {
|
|
45
|
+
* 204: null,
|
|
46
|
+
* 404: { schema: NotFoundError },
|
|
47
|
+
* },
|
|
48
|
+
* })
|
|
49
|
+
* async destroy(ctx: Context) { ... }
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
export function Endpoint(route, options) {
|
|
53
|
+
return function (_target, propertyKey, descriptor) {
|
|
54
|
+
const [method, path] = parseRoute(route);
|
|
55
|
+
// Normalize responses to consistent format
|
|
56
|
+
const responses = {};
|
|
57
|
+
for (const [status, value] of Object.entries(options.responses)) {
|
|
58
|
+
if (value === null) {
|
|
59
|
+
responses[Number(status)] = { schema: null };
|
|
60
|
+
}
|
|
61
|
+
else if (typeof value === 'object' && 'schema' in value) {
|
|
62
|
+
responses[Number(status)] = value;
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
responses[Number(status)] = { schema: value };
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
const metadata = {
|
|
69
|
+
method,
|
|
70
|
+
path,
|
|
71
|
+
methodName: String(propertyKey),
|
|
72
|
+
summary: options.summary,
|
|
73
|
+
description: options.description,
|
|
74
|
+
operationId: options.operationId,
|
|
75
|
+
deprecated: options.deprecated,
|
|
76
|
+
auth: options.auth ?? 'none',
|
|
77
|
+
body: options.body,
|
|
78
|
+
query: options.query,
|
|
79
|
+
params: options.params,
|
|
80
|
+
file: options.file,
|
|
81
|
+
responses,
|
|
82
|
+
middleware: options.middleware,
|
|
83
|
+
};
|
|
84
|
+
// Store metadata on the constructor (class), not the prototype
|
|
85
|
+
// This allows us to retrieve it when scanning controllers
|
|
86
|
+
const constructor = _target.constructor;
|
|
87
|
+
addEndpointMetadata(constructor, metadata);
|
|
88
|
+
return descriptor;
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Parse a route string into method and path.
|
|
93
|
+
* @throws Error if route format is invalid
|
|
94
|
+
*/
|
|
95
|
+
function parseRoute(route) {
|
|
96
|
+
const spaceIndex = route.indexOf(' ');
|
|
97
|
+
if (spaceIndex === -1) {
|
|
98
|
+
throw new Error(`Invalid route format: "${route}". Expected "METHOD /path"`);
|
|
99
|
+
}
|
|
100
|
+
const methodStr = route.slice(0, spaceIndex).toLowerCase();
|
|
101
|
+
const path = route.slice(spaceIndex + 1);
|
|
102
|
+
const validMethods = ['get', 'post', 'put', 'patch', 'delete'];
|
|
103
|
+
if (!validMethods.includes(methodStr)) {
|
|
104
|
+
throw new Error(`Invalid HTTP method: "${methodStr}". Expected one of: ${validMethods.join(', ')}`);
|
|
105
|
+
}
|
|
106
|
+
return [methodStr, path];
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=endpoint.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"endpoint.js","sourceRoot":"","sources":["../../src/decorators/endpoint.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAA;AA8C5D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;AACH,MAAM,UAAU,QAAQ,CACtB,KAAkB,EAClB,OAAwB;IAExB,OAAO,UAAU,OAAO,EAAE,WAAW,EAAE,UAAU;QAC/C,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,GAAG,UAAU,CAAC,KAAK,CAAC,CAAA;QAExC,2CAA2C;QAC3C,MAAM,SAAS,GAAuC,EAAE,CAAA;QACxD,KAAK,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC;YAChE,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;gBACnB,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,CAAA;YAC9C,CAAC;iBAAM,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,QAAQ,IAAI,KAAK,EAAE,CAAC;gBAC1D,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,KAA2B,CAAA;YACzD,CAAC;iBAAM,CAAC;gBACN,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,MAAM,EAAE,KAAgB,EAAE,CAAA;YAC1D,CAAC;QACH,CAAC;QAED,MAAM,QAAQ,GAAqB;YACjC,MAAM;YACN,IAAI;YACJ,UAAU,EAAE,MAAM,CAAC,WAAW,CAAC;YAC/B,OAAO,EAAE,OAAO,CAAC,OAAO;YACxB,WAAW,EAAE,OAAO,CAAC,WAAW;YAChC,WAAW,EAAE,OAAO,CAAC,WAAW;YAChC,UAAU,EAAE,OAAO,CAAC,UAAU;YAC9B,IAAI,EAAE,OAAO,CAAC,IAAI,IAAI,MAAM;YAC5B,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,SAAS;YACT,UAAU,EAAE,OAAO,CAAC,UAAU;SAC/B,CAAA;QAED,+DAA+D;QAC/D,0DAA0D;QAC1D,MAAM,WAAW,GAAI,OAAkB,CAAC,WAAW,CAAA;QACnD,mBAAmB,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAA;QAE1C,OAAO,UAAU,CAAA;IACnB,CAAC,CAAA;AACH,CAAC;AAED;;;GAGG;AACH,SAAS,UAAU,CAAC,KAAkB;IACpC,MAAM,UAAU,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;IACrC,IAAI,UAAU,KAAK,CAAC,CAAC,EAAE,CAAC;QACtB,MAAM,IAAI,KAAK,CAAC,0BAA0B,KAAK,4BAA4B,CAAC,CAAA;IAC9E,CAAC;IAED,MAAM,SAAS,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,WAAW,EAAE,CAAA;IAC1D,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,UAAU,GAAG,CAAC,CAAC,CAAA;IAExC,MAAM,YAAY,GAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAA;IAC5E,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,SAAuB,CAAC,EAAE,CAAC;QACpD,MAAM,IAAI,KAAK,CAAC,yBAAyB,SAAS,uBAAuB,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;IACrG,CAAC;IAED,OAAO,CAAC,SAAuB,EAAE,IAAI,CAAC,CAAA;AACxC,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { Controller, type ControllerOptions } from './controller.js';
|
|
2
|
+
export { Route, type RouteOptions } from './route.js';
|
|
3
|
+
export type { HttpMethod, AuthLevel, RouteString, ResponseDefinition, FileUploadConfig, ApiMetadata, EndpointMetadata, } from '../metadata/types.js';
|
|
4
|
+
export { getApiMetadata, getEndpointMetadata, getRegisteredControllers, getControllerMetadata, getAllControllerMetadata, } from '../metadata/storage.js';
|
|
5
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/decorators/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,KAAK,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AACpE,OAAO,EAAE,KAAK,EAAE,KAAK,YAAY,EAAE,MAAM,YAAY,CAAA;AAGrD,YAAY,EACV,UAAU,EACV,SAAS,EACT,WAAW,EACX,kBAAkB,EAClB,gBAAgB,EAChB,WAAW,EACX,gBAAgB,GACjB,MAAM,sBAAsB,CAAA;AAG7B,OAAO,EACL,cAAc,EACd,mBAAmB,EACnB,wBAAwB,EACxB,qBAAqB,EACrB,wBAAwB,GACzB,MAAM,wBAAwB,CAAA"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
// Decorators
|
|
2
|
+
export { Controller } from './controller.js';
|
|
3
|
+
export { Route } from './route.js';
|
|
4
|
+
// Re-export metadata accessors
|
|
5
|
+
export { getApiMetadata, getEndpointMetadata, getRegisteredControllers, getControllerMetadata, getAllControllerMetadata, } from '../metadata/storage.js';
|
|
6
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/decorators/index.ts"],"names":[],"mappings":"AAAA,aAAa;AACb,OAAO,EAAE,UAAU,EAA0B,MAAM,iBAAiB,CAAA;AACpE,OAAO,EAAE,KAAK,EAAqB,MAAM,YAAY,CAAA;AAarD,+BAA+B;AAC/B,OAAO,EACL,cAAc,EACd,mBAAmB,EACnB,wBAAwB,EACxB,qBAAqB,EACrB,wBAAwB,GACzB,MAAM,wBAAwB,CAAA"}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import type { TSchema } from '@sinclair/typebox';
|
|
2
|
+
import type { RouteString, FileUploadConfig } from '../metadata/types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Options for the @Route method decorator.
|
|
5
|
+
*/
|
|
6
|
+
export interface RouteOptions {
|
|
7
|
+
/** Short summary for OpenAPI docs */
|
|
8
|
+
summary?: string;
|
|
9
|
+
/** Detailed description for OpenAPI docs */
|
|
10
|
+
description?: string;
|
|
11
|
+
/** Unique operation ID for OpenAPI (auto-generated if not provided) */
|
|
12
|
+
operationId?: string;
|
|
13
|
+
/** Mark route as deprecated */
|
|
14
|
+
deprecated?: boolean;
|
|
15
|
+
/** Authentication requirement */
|
|
16
|
+
auth?: 'required' | 'optional' | 'none';
|
|
17
|
+
/** Request body schema (TypeBox) */
|
|
18
|
+
body?: TSchema;
|
|
19
|
+
/** Query parameters schema (TypeBox) */
|
|
20
|
+
query?: TSchema;
|
|
21
|
+
/** Path parameters schema (TypeBox) */
|
|
22
|
+
params?: TSchema;
|
|
23
|
+
/** File upload configuration for multipart/form-data */
|
|
24
|
+
file?: FileUploadConfig;
|
|
25
|
+
/**
|
|
26
|
+
* Response definitions by status code.
|
|
27
|
+
* Value can be:
|
|
28
|
+
* - A TypeBox schema
|
|
29
|
+
* - null (for no body, e.g., 204)
|
|
30
|
+
* - An object with schema and optional description
|
|
31
|
+
*/
|
|
32
|
+
responses: Record<number, TSchema | null | {
|
|
33
|
+
schema: TSchema | null;
|
|
34
|
+
description?: string;
|
|
35
|
+
}>;
|
|
36
|
+
/**
|
|
37
|
+
* Framework-specific middleware.
|
|
38
|
+
* This is opaque to the core library - adapters interpret it.
|
|
39
|
+
*/
|
|
40
|
+
middleware?: unknown[];
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Method decorator that defines an API route with full OpenAPI metadata.
|
|
44
|
+
*
|
|
45
|
+
* This decorator captures all information needed to:
|
|
46
|
+
* 1. Register the route with a framework
|
|
47
|
+
* 2. Validate request body, query, and path parameters
|
|
48
|
+
* 3. Generate OpenAPI documentation
|
|
49
|
+
*
|
|
50
|
+
* @param route Route string in format "METHOD /path"
|
|
51
|
+
* @param options Route configuration
|
|
52
|
+
*
|
|
53
|
+
* @example Basic GET route
|
|
54
|
+
* ```typescript
|
|
55
|
+
* @Route('GET /api/v1/users', {
|
|
56
|
+
* summary: 'List all users',
|
|
57
|
+
* responses: {
|
|
58
|
+
* 200: { schema: UserListResponse, description: 'List of users' },
|
|
59
|
+
* },
|
|
60
|
+
* })
|
|
61
|
+
* async index() { ... }
|
|
62
|
+
* ```
|
|
63
|
+
*
|
|
64
|
+
* @example POST with body and auth
|
|
65
|
+
* ```typescript
|
|
66
|
+
* @Route('POST /api/v1/users', {
|
|
67
|
+
* summary: 'Create a user',
|
|
68
|
+
* auth: 'required',
|
|
69
|
+
* body: CreateUserRequest,
|
|
70
|
+
* responses: {
|
|
71
|
+
* 201: { schema: User, description: 'User created' },
|
|
72
|
+
* 422: { schema: ValidationError },
|
|
73
|
+
* },
|
|
74
|
+
* })
|
|
75
|
+
* async store(ctx: Context, body: Static<typeof CreateUserRequest>) { ... }
|
|
76
|
+
* ```
|
|
77
|
+
*
|
|
78
|
+
* @example DELETE with no response body
|
|
79
|
+
* ```typescript
|
|
80
|
+
* @Route('DELETE /api/v1/users/:id', {
|
|
81
|
+
* summary: 'Delete a user',
|
|
82
|
+
* auth: 'required',
|
|
83
|
+
* params: UserIdParams,
|
|
84
|
+
* responses: {
|
|
85
|
+
* 204: null,
|
|
86
|
+
* 404: { schema: NotFoundError },
|
|
87
|
+
* },
|
|
88
|
+
* })
|
|
89
|
+
* async destroy(ctx: Context) { ... }
|
|
90
|
+
* ```
|
|
91
|
+
*/
|
|
92
|
+
export declare function Route(route: RouteString, options: RouteOptions): MethodDecorator;
|
|
93
|
+
//# sourceMappingURL=route.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../../src/decorators/route.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAA;AAEhD,OAAO,KAAK,EACV,WAAW,EAGX,gBAAgB,EAEjB,MAAM,sBAAsB,CAAA;AAE7B;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,qCAAqC;IACrC,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,4CAA4C;IAC5C,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,uEAAuE;IACvE,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,+BAA+B;IAC/B,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,iCAAiC;IACjC,IAAI,CAAC,EAAE,UAAU,GAAG,UAAU,GAAG,MAAM,CAAA;IACvC,oCAAoC;IACpC,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,wCAAwC;IACxC,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,uCAAuC;IACvC,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,wDAAwD;IACxD,IAAI,CAAC,EAAE,gBAAgB,CAAA;IACvB;;;;;;OAMG;IACH,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI,GAAG;QAAE,MAAM,EAAE,OAAO,GAAG,IAAI,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IAC5F;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,EAAE,CAAA;CACvB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;AACH,wBAAgB,KAAK,CACnB,KAAK,EAAE,WAAW,EAClB,OAAO,EAAE,YAAY,GACpB,eAAe,CAwCjB"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { addEndpointMetadata } from '../metadata/storage.js';
|
|
2
|
+
/**
|
|
3
|
+
* Method decorator that defines an API route with full OpenAPI metadata.
|
|
4
|
+
*
|
|
5
|
+
* This decorator captures all information needed to:
|
|
6
|
+
* 1. Register the route with a framework
|
|
7
|
+
* 2. Validate request body, query, and path parameters
|
|
8
|
+
* 3. Generate OpenAPI documentation
|
|
9
|
+
*
|
|
10
|
+
* @param route Route string in format "METHOD /path"
|
|
11
|
+
* @param options Route configuration
|
|
12
|
+
*
|
|
13
|
+
* @example Basic GET route
|
|
14
|
+
* ```typescript
|
|
15
|
+
* @Route('GET /api/v1/users', {
|
|
16
|
+
* summary: 'List all users',
|
|
17
|
+
* responses: {
|
|
18
|
+
* 200: { schema: UserListResponse, description: 'List of users' },
|
|
19
|
+
* },
|
|
20
|
+
* })
|
|
21
|
+
* async index() { ... }
|
|
22
|
+
* ```
|
|
23
|
+
*
|
|
24
|
+
* @example POST with body and auth
|
|
25
|
+
* ```typescript
|
|
26
|
+
* @Route('POST /api/v1/users', {
|
|
27
|
+
* summary: 'Create a user',
|
|
28
|
+
* auth: 'required',
|
|
29
|
+
* body: CreateUserRequest,
|
|
30
|
+
* responses: {
|
|
31
|
+
* 201: { schema: User, description: 'User created' },
|
|
32
|
+
* 422: { schema: ValidationError },
|
|
33
|
+
* },
|
|
34
|
+
* })
|
|
35
|
+
* async store(ctx: Context, body: Static<typeof CreateUserRequest>) { ... }
|
|
36
|
+
* ```
|
|
37
|
+
*
|
|
38
|
+
* @example DELETE with no response body
|
|
39
|
+
* ```typescript
|
|
40
|
+
* @Route('DELETE /api/v1/users/:id', {
|
|
41
|
+
* summary: 'Delete a user',
|
|
42
|
+
* auth: 'required',
|
|
43
|
+
* params: UserIdParams,
|
|
44
|
+
* responses: {
|
|
45
|
+
* 204: null,
|
|
46
|
+
* 404: { schema: NotFoundError },
|
|
47
|
+
* },
|
|
48
|
+
* })
|
|
49
|
+
* async destroy(ctx: Context) { ... }
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
export function Route(route, options) {
|
|
53
|
+
return function (_target, propertyKey, descriptor) {
|
|
54
|
+
const [method, path] = parseRoute(route);
|
|
55
|
+
// Normalize responses to consistent format
|
|
56
|
+
const responses = {};
|
|
57
|
+
for (const [status, value] of Object.entries(options.responses)) {
|
|
58
|
+
if (value === null) {
|
|
59
|
+
responses[Number(status)] = { schema: null };
|
|
60
|
+
}
|
|
61
|
+
else if (typeof value === 'object' && 'schema' in value) {
|
|
62
|
+
responses[Number(status)] = value;
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
responses[Number(status)] = { schema: value };
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
const metadata = {
|
|
69
|
+
method,
|
|
70
|
+
path,
|
|
71
|
+
methodName: String(propertyKey),
|
|
72
|
+
summary: options.summary,
|
|
73
|
+
description: options.description,
|
|
74
|
+
operationId: options.operationId,
|
|
75
|
+
deprecated: options.deprecated,
|
|
76
|
+
auth: options.auth ?? 'none',
|
|
77
|
+
body: options.body,
|
|
78
|
+
query: options.query,
|
|
79
|
+
params: options.params,
|
|
80
|
+
file: options.file,
|
|
81
|
+
responses,
|
|
82
|
+
middleware: options.middleware,
|
|
83
|
+
};
|
|
84
|
+
// Store metadata on the constructor (class), not the prototype
|
|
85
|
+
// This allows us to retrieve it when scanning controllers
|
|
86
|
+
const constructor = _target.constructor;
|
|
87
|
+
addEndpointMetadata(constructor, metadata);
|
|
88
|
+
return descriptor;
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Parse a route string into method and path.
|
|
93
|
+
* @throws Error if route format is invalid
|
|
94
|
+
*/
|
|
95
|
+
function parseRoute(route) {
|
|
96
|
+
const spaceIndex = route.indexOf(' ');
|
|
97
|
+
if (spaceIndex === -1) {
|
|
98
|
+
throw new Error(`Invalid route format: "${route}". Expected "METHOD /path"`);
|
|
99
|
+
}
|
|
100
|
+
const methodStr = route.slice(0, spaceIndex).toLowerCase();
|
|
101
|
+
const path = route.slice(spaceIndex + 1);
|
|
102
|
+
const validMethods = ['get', 'post', 'put', 'patch', 'delete'];
|
|
103
|
+
if (!validMethods.includes(methodStr)) {
|
|
104
|
+
throw new Error(`Invalid HTTP method: "${methodStr}". Expected one of: ${validMethods.join(', ')}`);
|
|
105
|
+
}
|
|
106
|
+
return [methodStr, path];
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=route.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"route.js","sourceRoot":"","sources":["../../src/decorators/route.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAA;AA8C5D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;AACH,MAAM,UAAU,KAAK,CACnB,KAAkB,EAClB,OAAqB;IAErB,OAAO,UAAU,OAAO,EAAE,WAAW,EAAE,UAAU;QAC/C,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,GAAG,UAAU,CAAC,KAAK,CAAC,CAAA;QAExC,2CAA2C;QAC3C,MAAM,SAAS,GAAuC,EAAE,CAAA;QACxD,KAAK,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC;YAChE,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;gBACnB,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,CAAA;YAC9C,CAAC;iBAAM,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,QAAQ,IAAI,KAAK,EAAE,CAAC;gBAC1D,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,KAA2B,CAAA;YACzD,CAAC;iBAAM,CAAC;gBACN,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,MAAM,EAAE,KAAgB,EAAE,CAAA;YAC1D,CAAC;QACH,CAAC;QAED,MAAM,QAAQ,GAAqB;YACjC,MAAM;YACN,IAAI;YACJ,UAAU,EAAE,MAAM,CAAC,WAAW,CAAC;YAC/B,OAAO,EAAE,OAAO,CAAC,OAAO;YACxB,WAAW,EAAE,OAAO,CAAC,WAAW;YAChC,WAAW,EAAE,OAAO,CAAC,WAAW;YAChC,UAAU,EAAE,OAAO,CAAC,UAAU;YAC9B,IAAI,EAAE,OAAO,CAAC,IAAI,IAAI,MAAM;YAC5B,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,SAAS;YACT,UAAU,EAAE,OAAO,CAAC,UAAU;SAC/B,CAAA;QAED,+DAA+D;QAC/D,0DAA0D;QAC1D,MAAM,WAAW,GAAI,OAAkB,CAAC,WAAW,CAAA;QACnD,mBAAmB,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAA;QAE1C,OAAO,UAAU,CAAA;IACnB,CAAC,CAAA;AACH,CAAC;AAED;;;GAGG;AACH,SAAS,UAAU,CAAC,KAAkB;IACpC,MAAM,UAAU,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;IACrC,IAAI,UAAU,KAAK,CAAC,CAAC,EAAE,CAAC;QACtB,MAAM,IAAI,KAAK,CAAC,0BAA0B,KAAK,4BAA4B,CAAC,CAAA;IAC9E,CAAC;IAED,MAAM,SAAS,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,WAAW,EAAE,CAAA;IAC1D,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,UAAU,GAAG,CAAC,CAAC,CAAA;IAExC,MAAM,YAAY,GAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAA;IAC5E,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,SAAuB,CAAC,EAAE,CAAC;QACpD,MAAM,IAAI,KAAK,CAAC,yBAAyB,SAAS,uBAAuB,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;IACrG,CAAC;IAED,OAAO,CAAC,SAAuB,EAAE,IAAI,CAAC,CAAA;AACxC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../../src/errors/base.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,qBAAa,qBAAsB,SAAQ,KAAK;IAC9C,SAAgB,IAAI,EAAE,MAAM,CAAA;gBAEhB,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;CAM1C"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base error class for all kontract errors.
|
|
3
|
+
*/
|
|
4
|
+
export class OpenApiDecoratorError extends Error {
|
|
5
|
+
code;
|
|
6
|
+
constructor(code, message) {
|
|
7
|
+
super(message);
|
|
8
|
+
this.name = 'OpenApiDecoratorError';
|
|
9
|
+
this.code = code;
|
|
10
|
+
Error.captureStackTrace?.(this, this.constructor);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=base.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base.js","sourceRoot":"","sources":["../../src/errors/base.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,OAAO,qBAAsB,SAAQ,KAAK;IAC9B,IAAI,CAAQ;IAE5B,YAAY,IAAY,EAAE,OAAe;QACvC,KAAK,CAAC,OAAO,CAAC,CAAA;QACd,IAAI,CAAC,IAAI,GAAG,uBAAuB,CAAA;QACnC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAA;QAChB,KAAK,CAAC,iBAAiB,EAAE,CAAC,IAAI,EAAE,IAAI,CAAC,WAAW,CAAC,CAAA;IACnD,CAAC;CACF"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { OpenApiDecoratorError } from './base.js';
|
|
2
|
+
/**
|
|
3
|
+
* Error thrown when configuration is invalid or missing.
|
|
4
|
+
*/
|
|
5
|
+
export declare class ConfigurationError extends OpenApiDecoratorError {
|
|
6
|
+
constructor(message: string);
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Error thrown when a required adapter is not registered.
|
|
10
|
+
*/
|
|
11
|
+
export declare class AdapterNotFoundError extends OpenApiDecoratorError {
|
|
12
|
+
readonly adapterType: string;
|
|
13
|
+
constructor(adapterType: string);
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Error thrown when a serializer is not found for a type.
|
|
17
|
+
*/
|
|
18
|
+
export declare class SerializerNotFoundError extends OpenApiDecoratorError {
|
|
19
|
+
readonly typeName: string;
|
|
20
|
+
constructor(typeName: string);
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=configuration.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"configuration.d.ts","sourceRoot":"","sources":["../../src/errors/configuration.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,WAAW,CAAA;AAEjD;;GAEG;AACH,qBAAa,kBAAmB,SAAQ,qBAAqB;gBAC/C,OAAO,EAAE,MAAM;CAI5B;AAED;;GAEG;AACH,qBAAa,oBAAqB,SAAQ,qBAAqB;IAC7D,SAAgB,WAAW,EAAE,MAAM,CAAA;gBAEvB,WAAW,EAAE,MAAM;CAKhC;AAED;;GAEG;AACH,qBAAa,uBAAwB,SAAQ,qBAAqB;IAChE,SAAgB,QAAQ,EAAE,MAAM,CAAA;gBAEpB,QAAQ,EAAE,MAAM;CAK7B"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { OpenApiDecoratorError } from './base.js';
|
|
2
|
+
/**
|
|
3
|
+
* Error thrown when configuration is invalid or missing.
|
|
4
|
+
*/
|
|
5
|
+
export class ConfigurationError extends OpenApiDecoratorError {
|
|
6
|
+
constructor(message) {
|
|
7
|
+
super('E_CONFIGURATION', message);
|
|
8
|
+
this.name = 'ConfigurationError';
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Error thrown when a required adapter is not registered.
|
|
13
|
+
*/
|
|
14
|
+
export class AdapterNotFoundError extends OpenApiDecoratorError {
|
|
15
|
+
adapterType;
|
|
16
|
+
constructor(adapterType) {
|
|
17
|
+
super('E_ADAPTER_NOT_FOUND', `No ${adapterType} adapter registered. Did you forget to configure it?`);
|
|
18
|
+
this.name = 'AdapterNotFoundError';
|
|
19
|
+
this.adapterType = adapterType;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Error thrown when a serializer is not found for a type.
|
|
24
|
+
*/
|
|
25
|
+
export class SerializerNotFoundError extends OpenApiDecoratorError {
|
|
26
|
+
typeName;
|
|
27
|
+
constructor(typeName) {
|
|
28
|
+
super('E_SERIALIZER_NOT_FOUND', `No serializer registered for type: ${typeName}`);
|
|
29
|
+
this.name = 'SerializerNotFoundError';
|
|
30
|
+
this.typeName = typeName;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=configuration.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"configuration.js","sourceRoot":"","sources":["../../src/errors/configuration.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,WAAW,CAAA;AAEjD;;GAEG;AACH,MAAM,OAAO,kBAAmB,SAAQ,qBAAqB;IAC3D,YAAY,OAAe;QACzB,KAAK,CAAC,iBAAiB,EAAE,OAAO,CAAC,CAAA;QACjC,IAAI,CAAC,IAAI,GAAG,oBAAoB,CAAA;IAClC,CAAC;CACF;AAED;;GAEG;AACH,MAAM,OAAO,oBAAqB,SAAQ,qBAAqB;IAC7C,WAAW,CAAQ;IAEnC,YAAY,WAAmB;QAC7B,KAAK,CAAC,qBAAqB,EAAE,MAAM,WAAW,sDAAsD,CAAC,CAAA;QACrG,IAAI,CAAC,IAAI,GAAG,sBAAsB,CAAA;QAClC,IAAI,CAAC,WAAW,GAAG,WAAW,CAAA;IAChC,CAAC;CACF;AAED;;GAEG;AACH,MAAM,OAAO,uBAAwB,SAAQ,qBAAqB;IAChD,QAAQ,CAAQ;IAEhC,YAAY,QAAgB;QAC1B,KAAK,CAAC,wBAAwB,EAAE,sCAAsC,QAAQ,EAAE,CAAC,CAAA;QACjF,IAAI,CAAC,IAAI,GAAG,yBAAyB,CAAA;QACrC,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAA;IAC1B,CAAC;CACF"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { OpenApiDecoratorError } from './base.js';
|
|
2
|
+
export { RequestValidationError, ResponseValidationError, type ValidationErrorDetail, } from './validation.js';
|
|
3
|
+
export { ConfigurationError, AdapterNotFoundError, SerializerNotFoundError, } from './configuration.js';
|
|
4
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/errors/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,WAAW,CAAA;AAEjD,OAAO,EACL,sBAAsB,EACtB,uBAAuB,EACvB,KAAK,qBAAqB,GAC3B,MAAM,iBAAiB,CAAA;AAExB,OAAO,EACL,kBAAkB,EAClB,oBAAoB,EACpB,uBAAuB,GACxB,MAAM,oBAAoB,CAAA"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { OpenApiDecoratorError } from './base.js';
|
|
2
|
+
export { RequestValidationError, ResponseValidationError, } from './validation.js';
|
|
3
|
+
export { ConfigurationError, AdapterNotFoundError, SerializerNotFoundError, } from './configuration.js';
|
|
4
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/errors/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,WAAW,CAAA;AAEjD,OAAO,EACL,sBAAsB,EACtB,uBAAuB,GAExB,MAAM,iBAAiB,CAAA;AAExB,OAAO,EACL,kBAAkB,EAClB,oBAAoB,EACpB,uBAAuB,GACxB,MAAM,oBAAoB,CAAA"}
|