@jsango/openapi 1.0.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/LICENSE +21 -0
- package/README.md +29 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/public/admin-adapter.d.ts +26 -0
- package/dist/public/admin-adapter.d.ts.map +1 -0
- package/dist/public/admin-adapter.js +120 -0
- package/dist/public/admin-adapter.js.map +1 -0
- package/dist/public/endpoint.d.ts +13 -0
- package/dist/public/endpoint.d.ts.map +1 -0
- package/dist/public/endpoint.js +38 -0
- package/dist/public/endpoint.js.map +1 -0
- package/dist/public/errors.d.ts +15 -0
- package/dist/public/errors.d.ts.map +1 -0
- package/dist/public/errors.js +32 -0
- package/dist/public/errors.js.map +1 -0
- package/dist/public/formatter.d.ts +13 -0
- package/dist/public/formatter.d.ts.map +1 -0
- package/dist/public/formatter.js +77 -0
- package/dist/public/formatter.js.map +1 -0
- package/dist/public/generator.d.ts +37 -0
- package/dist/public/generator.d.ts.map +1 -0
- package/dist/public/generator.js +217 -0
- package/dist/public/generator.js.map +1 -0
- package/dist/public/index.d.ts +12 -0
- package/dist/public/index.d.ts.map +1 -0
- package/dist/public/index.js +11 -0
- package/dist/public/index.js.map +1 -0
- package/dist/public/orm-adapter.d.ts +28 -0
- package/dist/public/orm-adapter.d.ts.map +1 -0
- package/dist/public/orm-adapter.js +97 -0
- package/dist/public/orm-adapter.js.map +1 -0
- package/dist/public/registry.d.ts +51 -0
- package/dist/public/registry.d.ts.map +1 -0
- package/dist/public/registry.js +106 -0
- package/dist/public/registry.js.map +1 -0
- package/dist/public/schema-builder.d.ts +29 -0
- package/dist/public/schema-builder.d.ts.map +1 -0
- package/dist/public/schema-builder.js +117 -0
- package/dist/public/schema-builder.js.map +1 -0
- package/dist/public/types.d.ts +198 -0
- package/dist/public/types.d.ts.map +1 -0
- package/dist/public/types.js +2 -0
- package/dist/public/types.js.map +1 -0
- package/dist/public/validation-adapter.d.ts +24 -0
- package/dist/public/validation-adapter.d.ts.map +1 -0
- package/dist/public/validation-adapter.js +57 -0
- package/dist/public/validation-adapter.js.map +1 -0
- package/dist/public/validator.d.ts +14 -0
- package/dist/public/validator.d.ts.map +1 -0
- package/dist/public/validator.js +107 -0
- package/dist/public/validator.js.map +1 -0
- package/package.json +37 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 JSango contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# @jsango/openapi
|
|
2
|
+
|
|
3
|
+
> Deterministic, zero-reflection OpenAPI 3.1.0 document generator and schema adapters for router, validation, ORM, and Admin.
|
|
4
|
+
|
|
5
|
+
Part of the **[jsango](https://github.com/jsango/jsango)** backend framework for TypeScript.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pnpm add @jsango/openapi
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Usage
|
|
14
|
+
|
|
15
|
+
```typescript
|
|
16
|
+
import { OpenApiRegistry, OpenApiFormatter } from '@jsango/openapi';
|
|
17
|
+
|
|
18
|
+
const registry = new OpenApiRegistry({ title: 'My API', version: '1.0.0' });
|
|
19
|
+
const spec = registry.generateDocument();
|
|
20
|
+
const json = OpenApiFormatter.toJson(spec);
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Documentation
|
|
24
|
+
|
|
25
|
+
For full architecture documentation and guides, visit the [jsango documentation](https://github.com/jsango/jsango/tree/main/docs).
|
|
26
|
+
|
|
27
|
+
## License
|
|
28
|
+
|
|
29
|
+
MIT © jsango contributors
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { OpenApiPaths } from './types.js';
|
|
2
|
+
export interface AdminFieldDescriptor {
|
|
3
|
+
readonly name: string;
|
|
4
|
+
readonly type: string;
|
|
5
|
+
readonly label?: string | undefined;
|
|
6
|
+
readonly readonly?: boolean | undefined;
|
|
7
|
+
readonly required?: boolean | undefined;
|
|
8
|
+
}
|
|
9
|
+
export interface AdminResourceDescriptor {
|
|
10
|
+
readonly id: string;
|
|
11
|
+
readonly label: string;
|
|
12
|
+
readonly pluralLabel?: string | undefined;
|
|
13
|
+
readonly primaryKey?: string | undefined;
|
|
14
|
+
readonly listFields?: readonly string[] | undefined;
|
|
15
|
+
readonly createFields?: readonly string[] | undefined;
|
|
16
|
+
readonly editFields?: readonly string[] | undefined;
|
|
17
|
+
readonly searchFields?: readonly string[] | undefined;
|
|
18
|
+
readonly fields: readonly AdminFieldDescriptor[];
|
|
19
|
+
}
|
|
20
|
+
export declare class AdminAdapter {
|
|
21
|
+
/**
|
|
22
|
+
* Generates OpenAPI paths for an Admin resource with explicit 'Admin: <Resource>' tagging.
|
|
23
|
+
*/
|
|
24
|
+
static generateResourcePaths(resource: AdminResourceDescriptor, prefix?: string): OpenApiPaths;
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=admin-adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"admin-adapter.d.ts","sourceRoot":"","sources":["../../src/public/admin-adapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAmC,MAAM,YAAY,CAAC;AAGhF,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACxC,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CACzC;AAED,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1C,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACzC,QAAQ,CAAC,UAAU,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,CAAC;IACpD,QAAQ,CAAC,YAAY,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,CAAC;IACtD,QAAQ,CAAC,UAAU,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,CAAC;IACpD,QAAQ,CAAC,YAAY,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,CAAC;IACtD,QAAQ,CAAC,MAAM,EAAE,SAAS,oBAAoB,EAAE,CAAC;CAClD;AAED,qBAAa,YAAY;IACvB;;OAEG;WACW,qBAAqB,CACjC,QAAQ,EAAE,uBAAuB,EACjC,MAAM,SAAkB,GACvB,YAAY;CAyHhB"}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { SchemaBuilder } from './schema-builder.js';
|
|
2
|
+
export class AdminAdapter {
|
|
3
|
+
/**
|
|
4
|
+
* Generates OpenAPI paths for an Admin resource with explicit 'Admin: <Resource>' tagging.
|
|
5
|
+
*/
|
|
6
|
+
static generateResourcePaths(resource, prefix = '/admin/api/v1') {
|
|
7
|
+
const paths = {};
|
|
8
|
+
const tag = `Admin: ${resource.pluralLabel ?? resource.label}`;
|
|
9
|
+
const pk = resource.primaryKey ?? 'id';
|
|
10
|
+
const basePath = `${prefix}/resources/${resource.id}`;
|
|
11
|
+
const itemPath = `${basePath}/{${pk}}`;
|
|
12
|
+
const modelSchema = {
|
|
13
|
+
type: 'object',
|
|
14
|
+
properties: Object.fromEntries(resource.fields.map((f) => [f.name, { type: 'string', description: f.label ?? f.name }])),
|
|
15
|
+
};
|
|
16
|
+
const queryParams = [
|
|
17
|
+
{ name: 'page', in: 'query', schema: { type: 'integer', default: 1 } },
|
|
18
|
+
{ name: 'pageSize', in: 'query', schema: { type: 'integer', default: 25 } },
|
|
19
|
+
{ name: 'search', in: 'query', schema: { type: 'string' } },
|
|
20
|
+
{ name: 'sort', in: 'query', schema: { type: 'string' } },
|
|
21
|
+
{ name: 'sortDirection', in: 'query', schema: { type: 'string', enum: ['asc', 'desc'] } },
|
|
22
|
+
];
|
|
23
|
+
// List & Create Path
|
|
24
|
+
paths[basePath] = {
|
|
25
|
+
get: {
|
|
26
|
+
tags: [tag],
|
|
27
|
+
summary: `List ${resource.pluralLabel ?? resource.label}`,
|
|
28
|
+
operationId: `admin_list_${resource.id}`,
|
|
29
|
+
parameters: queryParams,
|
|
30
|
+
responses: {
|
|
31
|
+
'200': {
|
|
32
|
+
description: 'Paginated list of records',
|
|
33
|
+
content: {
|
|
34
|
+
'application/json': {
|
|
35
|
+
schema: SchemaBuilder.paginated(modelSchema),
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
'403': { description: 'Forbidden — Staff access required' },
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
post: {
|
|
43
|
+
tags: [tag],
|
|
44
|
+
summary: `Create a ${resource.label}`,
|
|
45
|
+
operationId: `admin_create_${resource.id}`,
|
|
46
|
+
requestBody: {
|
|
47
|
+
required: true,
|
|
48
|
+
content: {
|
|
49
|
+
'application/json': {
|
|
50
|
+
schema: modelSchema,
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
responses: {
|
|
55
|
+
'201': {
|
|
56
|
+
description: `${resource.label} created successfully`,
|
|
57
|
+
content: { 'application/json': { schema: modelSchema } },
|
|
58
|
+
},
|
|
59
|
+
'403': { description: 'Forbidden — Create permission required' },
|
|
60
|
+
'422': { description: 'Validation error' },
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
// Detail, Update, Delete Path
|
|
65
|
+
const pkParam = {
|
|
66
|
+
name: pk,
|
|
67
|
+
in: 'path',
|
|
68
|
+
required: true,
|
|
69
|
+
schema: { type: 'string' },
|
|
70
|
+
description: `Primary key of the ${resource.label}`,
|
|
71
|
+
};
|
|
72
|
+
paths[itemPath] = {
|
|
73
|
+
get: {
|
|
74
|
+
tags: [tag],
|
|
75
|
+
summary: `Get ${resource.label} by ID`,
|
|
76
|
+
operationId: `admin_get_${resource.id}`,
|
|
77
|
+
parameters: [pkParam],
|
|
78
|
+
responses: {
|
|
79
|
+
'200': {
|
|
80
|
+
description: `${resource.label} details`,
|
|
81
|
+
content: { 'application/json': { schema: modelSchema } },
|
|
82
|
+
},
|
|
83
|
+
'404': { description: 'Record not found' },
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
patch: {
|
|
87
|
+
tags: [tag],
|
|
88
|
+
summary: `Update ${resource.label}`,
|
|
89
|
+
operationId: `admin_update_${resource.id}`,
|
|
90
|
+
parameters: [pkParam],
|
|
91
|
+
requestBody: {
|
|
92
|
+
required: true,
|
|
93
|
+
content: {
|
|
94
|
+
'application/json': { schema: modelSchema },
|
|
95
|
+
},
|
|
96
|
+
},
|
|
97
|
+
responses: {
|
|
98
|
+
'200': {
|
|
99
|
+
description: `${resource.label} updated successfully`,
|
|
100
|
+
content: { 'application/json': { schema: modelSchema } },
|
|
101
|
+
},
|
|
102
|
+
'404': { description: 'Record not found' },
|
|
103
|
+
'422': { description: 'Validation error' },
|
|
104
|
+
},
|
|
105
|
+
},
|
|
106
|
+
delete: {
|
|
107
|
+
tags: [tag],
|
|
108
|
+
summary: `Delete ${resource.label}`,
|
|
109
|
+
operationId: `admin_delete_${resource.id}`,
|
|
110
|
+
parameters: [pkParam],
|
|
111
|
+
responses: {
|
|
112
|
+
'204': { description: `${resource.label} deleted successfully` },
|
|
113
|
+
'404': { description: 'Record not found' },
|
|
114
|
+
},
|
|
115
|
+
},
|
|
116
|
+
};
|
|
117
|
+
return paths;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
//# sourceMappingURL=admin-adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"admin-adapter.js","sourceRoot":"","sources":["../../src/public/admin-adapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { RouteHandler } from '@jsango/router';
|
|
2
|
+
import type { IRouter } from '@jsango/router';
|
|
3
|
+
import { OpenApiGenerator } from './generator.js';
|
|
4
|
+
export interface OpenApiEndpointOptions {
|
|
5
|
+
readonly router?: IRouter | undefined;
|
|
6
|
+
readonly format?: 'json' | 'yaml' | 'auto' | undefined;
|
|
7
|
+
readonly cacheDocument?: boolean | undefined;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Creates an HTTP RouteHandler that serves the OpenAPI specification document.
|
|
11
|
+
*/
|
|
12
|
+
export declare function createOpenApiHandler(generator: OpenApiGenerator, options?: OpenApiEndpointOptions): RouteHandler;
|
|
13
|
+
//# sourceMappingURL=endpoint.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"endpoint.d.ts","sourceRoot":"","sources":["../../src/public/endpoint.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAI9C,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAGlD,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACtC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;IACvD,QAAQ,CAAC,aAAa,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CAC9C;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,gBAAgB,EAC3B,OAAO,GAAE,sBAA2B,GACnC,YAAY,CAqCd"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { HttpResponse, HttpStatus, ContentType } from '@jsango/http';
|
|
2
|
+
import { OpenApiFormatter } from './formatter.js';
|
|
3
|
+
/**
|
|
4
|
+
* Creates an HTTP RouteHandler that serves the OpenAPI specification document.
|
|
5
|
+
*/
|
|
6
|
+
export function createOpenApiHandler(generator, options = {}) {
|
|
7
|
+
let cachedJson;
|
|
8
|
+
let cachedYaml;
|
|
9
|
+
return (ctx) => {
|
|
10
|
+
const targetRouter = options.router;
|
|
11
|
+
const reqFormat = ctx.request.query.get('format')?.toLowerCase();
|
|
12
|
+
const accept = ctx.request.headers.get('accept')?.toLowerCase() ?? '';
|
|
13
|
+
const isYaml = reqFormat === 'yaml' ||
|
|
14
|
+
options.format === 'yaml' ||
|
|
15
|
+
(options.format === 'auto' &&
|
|
16
|
+
(accept.includes('application/yaml') || accept.includes('text/yaml')));
|
|
17
|
+
if (isYaml) {
|
|
18
|
+
if (!cachedYaml || !options.cacheDocument) {
|
|
19
|
+
const doc = generator.generate(targetRouter);
|
|
20
|
+
cachedYaml = OpenApiFormatter.toYaml(doc);
|
|
21
|
+
}
|
|
22
|
+
return new HttpResponse(cachedYaml, {
|
|
23
|
+
status: HttpStatus.OK,
|
|
24
|
+
headers: { 'content-type': 'application/yaml; charset=utf-8' },
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
// Default JSON
|
|
28
|
+
if (!cachedJson || !options.cacheDocument) {
|
|
29
|
+
const doc = generator.generate(targetRouter);
|
|
30
|
+
cachedJson = OpenApiFormatter.toJson(doc, true);
|
|
31
|
+
}
|
|
32
|
+
return new HttpResponse(cachedJson, {
|
|
33
|
+
status: HttpStatus.OK,
|
|
34
|
+
headers: { 'content-type': `${ContentType.JSON}; charset=utf-8` },
|
|
35
|
+
});
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=endpoint.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"endpoint.js","sourceRoot":"","sources":["../../src/public/endpoint.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAGrE,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAQlD;;GAEG;AACH,MAAM,UAAU,oBAAoB,CAClC,SAA2B,EAC3B,UAAkC,EAAE;IAEpC,IAAI,UAA8B,CAAC;IACnC,IAAI,UAA8B,CAAC;IAEnC,OAAO,CAAC,GAAmB,EAAE,EAAE;QAC7B,MAAM,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC;QACpC,MAAM,SAAS,GAAG,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,WAAW,EAAE,CAAC;QACjE,MAAM,MAAM,GAAG,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC;QAEtE,MAAM,MAAM,GACV,SAAS,KAAK,MAAM;YACpB,OAAO,CAAC,MAAM,KAAK,MAAM;YACzB,CAAC,OAAO,CAAC,MAAM,KAAK,MAAM;gBACxB,CAAC,MAAM,CAAC,QAAQ,CAAC,kBAAkB,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;QAE3E,IAAI,MAAM,EAAE,CAAC;YACX,IAAI,CAAC,UAAU,IAAI,CAAC,OAAO,CAAC,aAAa,EAAE,CAAC;gBAC1C,MAAM,GAAG,GAAoB,SAAS,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;gBAC9D,UAAU,GAAG,gBAAgB,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAC5C,CAAC;YACD,OAAO,IAAI,YAAY,CAAC,UAAU,EAAE;gBAClC,MAAM,EAAE,UAAU,CAAC,EAAE;gBACrB,OAAO,EAAE,EAAE,cAAc,EAAE,iCAAiC,EAAE;aAC/D,CAAC,CAAC;QACL,CAAC;QAED,eAAe;QACf,IAAI,CAAC,UAAU,IAAI,CAAC,OAAO,CAAC,aAAa,EAAE,CAAC;YAC1C,MAAM,GAAG,GAAoB,SAAS,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;YAC9D,UAAU,GAAG,gBAAgB,CAAC,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QAClD,CAAC;QAED,OAAO,IAAI,YAAY,CAAC,UAAU,EAAE;YAClC,MAAM,EAAE,UAAU,CAAC,EAAE;YACrB,OAAO,EAAE,EAAE,cAAc,EAAE,GAAG,WAAW,CAAC,IAAI,iBAAiB,EAAE;SAClE,CAAC,CAAC;IACL,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { JsangoError } from '@jsango/core';
|
|
2
|
+
export declare class OpenApiError extends JsangoError {
|
|
3
|
+
constructor(message: string, code?: string, meta?: Record<string, unknown>);
|
|
4
|
+
}
|
|
5
|
+
export declare class DuplicateOperationIdError extends OpenApiError {
|
|
6
|
+
constructor(operationId: string, pathA: string, methodA: string, pathB: string, methodB: string);
|
|
7
|
+
}
|
|
8
|
+
export declare class ConflictingSchemaError extends OpenApiError {
|
|
9
|
+
constructor(name: string, reason: string);
|
|
10
|
+
}
|
|
11
|
+
export declare class InvalidOpenApiDocumentError extends OpenApiError {
|
|
12
|
+
readonly validationErrors: readonly string[];
|
|
13
|
+
constructor(errors: readonly string[]);
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/public/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAE3C,qBAAa,YAAa,SAAQ,WAAW;gBAC/B,OAAO,EAAE,MAAM,EAAE,IAAI,SAAwB,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;CAI1F;AAED,qBAAa,yBAA0B,SAAQ,YAAY;gBAC7C,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;CAYhG;AAED,qBAAa,sBAAuB,SAAQ,YAAY;gBAC1C,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;CAQzC;AAED,qBAAa,2BAA4B,SAAQ,YAAY;IAC3D,SAAgB,gBAAgB,EAAE,SAAS,MAAM,EAAE,CAAC;gBAExC,MAAM,EAAE,SAAS,MAAM,EAAE;CAStC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { JsangoError } from '@jsango/core';
|
|
2
|
+
export class OpenApiError extends JsangoError {
|
|
3
|
+
constructor(message, code = 'ERR_OPENAPI_GENERAL', meta) {
|
|
4
|
+
super({ code, message, metadata: meta });
|
|
5
|
+
this.name = 'OpenApiError';
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
export class DuplicateOperationIdError extends OpenApiError {
|
|
9
|
+
constructor(operationId, pathA, methodA, pathB, methodB) {
|
|
10
|
+
super(`Duplicate operationId "${operationId}" detected across ${methodA} ${pathA} and ${methodB} ${pathB}.`, 'ERR_OPENAPI_DUPLICATE_OPERATION_ID', {
|
|
11
|
+
operationId,
|
|
12
|
+
first: { path: pathA, method: methodA },
|
|
13
|
+
second: { path: pathB, method: methodB },
|
|
14
|
+
});
|
|
15
|
+
this.name = 'DuplicateOperationIdError';
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
export class ConflictingSchemaError extends OpenApiError {
|
|
19
|
+
constructor(name, reason) {
|
|
20
|
+
super(`Incompatible schema definition registered for component schema "${name}": ${reason}`, 'ERR_OPENAPI_CONFLICTING_SCHEMA', { schemaName: name, reason });
|
|
21
|
+
this.name = 'ConflictingSchemaError';
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
export class InvalidOpenApiDocumentError extends OpenApiError {
|
|
25
|
+
validationErrors;
|
|
26
|
+
constructor(errors) {
|
|
27
|
+
super(`OpenAPI Document validation failed:\n - ${errors.join('\n - ')}`, 'ERR_OPENAPI_INVALID_DOCUMENT', { errors });
|
|
28
|
+
this.name = 'InvalidOpenApiDocumentError';
|
|
29
|
+
this.validationErrors = errors;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/public/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAE3C,MAAM,OAAO,YAAa,SAAQ,WAAW;IAC3C,YAAY,OAAe,EAAE,IAAI,GAAG,qBAAqB,EAAE,IAA8B;QACvF,KAAK,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;QACzC,IAAI,CAAC,IAAI,GAAG,cAAc,CAAC;IAC7B,CAAC;CACF;AAED,MAAM,OAAO,yBAA0B,SAAQ,YAAY;IACzD,YAAY,WAAmB,EAAE,KAAa,EAAE,OAAe,EAAE,KAAa,EAAE,OAAe;QAC7F,KAAK,CACH,0BAA0B,WAAW,qBAAqB,OAAO,IAAI,KAAK,QAAQ,OAAO,IAAI,KAAK,GAAG,EACrG,oCAAoC,EACpC;YACE,WAAW;YACX,KAAK,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE;YACvC,MAAM,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE;SACzC,CACF,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,2BAA2B,CAAC;IAC1C,CAAC;CACF;AAED,MAAM,OAAO,sBAAuB,SAAQ,YAAY;IACtD,YAAY,IAAY,EAAE,MAAc;QACtC,KAAK,CACH,mEAAmE,IAAI,MAAM,MAAM,EAAE,EACrF,gCAAgC,EAChC,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,EAAE,CAC7B,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,wBAAwB,CAAC;IACvC,CAAC;CACF;AAED,MAAM,OAAO,2BAA4B,SAAQ,YAAY;IAC3C,gBAAgB,CAAoB;IAEpD,YAAY,MAAyB;QACnC,KAAK,CACH,2CAA2C,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,EACjE,8BAA8B,EAC9B,EAAE,MAAM,EAAE,CACX,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,6BAA6B,CAAC;QAC1C,IAAI,CAAC,gBAAgB,GAAG,MAAM,CAAC;IACjC,CAAC;CACF"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { OpenApiDocument } from './types.js';
|
|
2
|
+
export declare class OpenApiFormatter {
|
|
3
|
+
/**
|
|
4
|
+
* Formats the document as JSON string.
|
|
5
|
+
*/
|
|
6
|
+
static toJson(doc: OpenApiDocument, pretty?: boolean): string;
|
|
7
|
+
/**
|
|
8
|
+
* Formats the document as a clean YAML string with zero external dependencies.
|
|
9
|
+
*/
|
|
10
|
+
static toYaml(doc: OpenApiDocument): string;
|
|
11
|
+
private static serializeYamlValue;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=formatter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"formatter.d.ts","sourceRoot":"","sources":["../../src/public/formatter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAElD,qBAAa,gBAAgB;IAC3B;;OAEG;WACW,MAAM,CAAC,GAAG,EAAE,eAAe,EAAE,MAAM,UAAO,GAAG,MAAM;IAIjE;;OAEG;WACW,MAAM,CAAC,GAAG,EAAE,eAAe,GAAG,MAAM;IAIlD,OAAO,CAAC,MAAM,CAAC,kBAAkB;CAqElC"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
export class OpenApiFormatter {
|
|
2
|
+
/**
|
|
3
|
+
* Formats the document as JSON string.
|
|
4
|
+
*/
|
|
5
|
+
static toJson(doc, pretty = true) {
|
|
6
|
+
return JSON.stringify(doc, null, pretty ? 2 : undefined);
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Formats the document as a clean YAML string with zero external dependencies.
|
|
10
|
+
*/
|
|
11
|
+
static toYaml(doc) {
|
|
12
|
+
return this.serializeYamlValue(doc, 0);
|
|
13
|
+
}
|
|
14
|
+
static serializeYamlValue(value, indentLevel) {
|
|
15
|
+
const indent = ' '.repeat(indentLevel);
|
|
16
|
+
if (value === null || value === undefined) {
|
|
17
|
+
return 'null';
|
|
18
|
+
}
|
|
19
|
+
if (typeof value === 'boolean' || typeof value === 'number') {
|
|
20
|
+
return String(value);
|
|
21
|
+
}
|
|
22
|
+
if (typeof value === 'string') {
|
|
23
|
+
// Escape or quote strings with special characters or newlines
|
|
24
|
+
if (value.includes('\n')) {
|
|
25
|
+
const lines = value
|
|
26
|
+
.split('\n')
|
|
27
|
+
.map((l) => `${indent} ${l}`)
|
|
28
|
+
.join('\n');
|
|
29
|
+
return `|\n${lines}`;
|
|
30
|
+
}
|
|
31
|
+
if (value === '' ||
|
|
32
|
+
/[:#[\]{},&*?|<>=!%@`]/.test(value) ||
|
|
33
|
+
value === 'true' ||
|
|
34
|
+
value === 'false' ||
|
|
35
|
+
value === 'null' ||
|
|
36
|
+
!isNaN(Number(value))) {
|
|
37
|
+
return JSON.stringify(value);
|
|
38
|
+
}
|
|
39
|
+
return value;
|
|
40
|
+
}
|
|
41
|
+
if (Array.isArray(value)) {
|
|
42
|
+
if (value.length === 0)
|
|
43
|
+
return '[]';
|
|
44
|
+
const lines = [];
|
|
45
|
+
for (const item of value) {
|
|
46
|
+
if (typeof item === 'object' && item !== null && !Array.isArray(item)) {
|
|
47
|
+
const itemYaml = this.serializeYamlValue(item, indentLevel + 1).trimStart();
|
|
48
|
+
lines.push(`${indent}- ${itemYaml}`);
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
lines.push(`${indent}- ${this.serializeYamlValue(item, indentLevel + 1)}`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return lines.join('\n');
|
|
55
|
+
}
|
|
56
|
+
if (typeof value === 'object') {
|
|
57
|
+
const entries = Object.entries(value).filter(([, v]) => v !== undefined);
|
|
58
|
+
if (entries.length === 0)
|
|
59
|
+
return '{}';
|
|
60
|
+
const lines = [];
|
|
61
|
+
for (const [k, v] of entries) {
|
|
62
|
+
const key = /[:#[\]{},&*?|<>=!%@`]/.test(k) ? JSON.stringify(k) : k;
|
|
63
|
+
if (typeof v === 'object' &&
|
|
64
|
+
v !== null &&
|
|
65
|
+
(Array.isArray(v) ? v.length > 0 : Object.keys(v).length > 0)) {
|
|
66
|
+
lines.push(`${indent}${key}:\n${this.serializeYamlValue(v, indentLevel + 1)}`);
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
lines.push(`${indent}${key}: ${this.serializeYamlValue(v, indentLevel + 1)}`);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return lines.join('\n');
|
|
73
|
+
}
|
|
74
|
+
return String(value);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=formatter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"formatter.js","sourceRoot":"","sources":["../../src/public/formatter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { IRouter } from '@jsango/router';
|
|
2
|
+
import type { OpenApiDocument, OpenApiInfo, OpenApiVersion, OpenApiServer, OpenApiSecurityRequirement, OpenApiTag } from './types.js';
|
|
3
|
+
import { OpenApiRegistry } from './registry.js';
|
|
4
|
+
export interface OpenApiGeneratorOptions {
|
|
5
|
+
readonly info: OpenApiInfo;
|
|
6
|
+
readonly openapi?: OpenApiVersion | undefined;
|
|
7
|
+
readonly servers?: readonly OpenApiServer[] | undefined;
|
|
8
|
+
readonly registry?: OpenApiRegistry | undefined;
|
|
9
|
+
readonly includeAdmin?: boolean | undefined;
|
|
10
|
+
readonly defaultSecurity?: readonly OpenApiSecurityRequirement[] | undefined;
|
|
11
|
+
readonly tags?: readonly OpenApiTag[] | undefined;
|
|
12
|
+
}
|
|
13
|
+
export declare class OpenApiGenerator {
|
|
14
|
+
private readonly info;
|
|
15
|
+
private readonly version;
|
|
16
|
+
private readonly servers;
|
|
17
|
+
private readonly registry;
|
|
18
|
+
private readonly includeAdmin;
|
|
19
|
+
private readonly defaultSecurity?;
|
|
20
|
+
private readonly tags;
|
|
21
|
+
constructor(options: OpenApiGeneratorOptions);
|
|
22
|
+
getRegistry(): OpenApiRegistry;
|
|
23
|
+
/**
|
|
24
|
+
* Generates a deterministic OpenApiDocument from the router and registry.
|
|
25
|
+
*/
|
|
26
|
+
generate(router?: IRouter): OpenApiDocument;
|
|
27
|
+
private shouldSkipRoute;
|
|
28
|
+
/**
|
|
29
|
+
* Normalizes router path syntax (`/users/:id<number>`) to OpenAPI syntax (`/users/{id}`)
|
|
30
|
+
* and derives path parameter definitions from constraints.
|
|
31
|
+
*/
|
|
32
|
+
private normalizePathAndParams;
|
|
33
|
+
private generateOperationId;
|
|
34
|
+
private defaultResponses;
|
|
35
|
+
private buildComponents;
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=generator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generator.d.ts","sourceRoot":"","sources":["../../src/public/generator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAS,MAAM,gBAAgB,CAAC;AACrD,OAAO,KAAK,EACV,eAAe,EACf,WAAW,EACX,cAAc,EACd,aAAa,EAMb,0BAA0B,EAC1B,UAAU,EAEX,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAIhD,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAC3B,QAAQ,CAAC,OAAO,CAAC,EAAE,cAAc,GAAG,SAAS,CAAC;IAC9C,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,aAAa,EAAE,GAAG,SAAS,CAAC;IACxD,QAAQ,CAAC,QAAQ,CAAC,EAAE,eAAe,GAAG,SAAS,CAAC;IAChD,QAAQ,CAAC,YAAY,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC5C,QAAQ,CAAC,eAAe,CAAC,EAAE,SAAS,0BAA0B,EAAE,GAAG,SAAS,CAAC;IAC7E,QAAQ,CAAC,IAAI,CAAC,EAAE,SAAS,UAAU,EAAE,GAAG,SAAS,CAAC;CACnD;AAED,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAc;IACnC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAiB;IACzC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA2B;IACnD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAkB;IAC3C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAU;IACvC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAoD;IACrF,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAwB;gBAEjC,OAAO,EAAE,uBAAuB;IAqBrC,WAAW,IAAI,eAAe;IAIrC;;OAEG;IACI,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,GAAG,eAAe;IAyGlD,OAAO,CAAC,eAAe;IAiBvB;;;OAGG;IACH,OAAO,CAAC,sBAAsB;IAoC9B,OAAO,CAAC,mBAAmB;IAK3B,OAAO,CAAC,gBAAgB;IAexB,OAAO,CAAC,eAAe;CA+CxB"}
|