@zudojs/openapi 1.3.0 → 1.5.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 +83 -2
- package/dist/index.d.ts +10 -6
- package/dist/index.js +8 -4
- package/dist/openApiConstants/index.d.ts +1 -1
- package/dist/openApiConstants/index.js +1 -1
- package/dist/openApiConstants/openApiConstants.core.d.ts +5 -0
- package/dist/openApiConstants/openApiConstants.core.js +5 -0
- package/dist/openApiFromRoutes/index.d.ts +11 -0
- package/dist/openApiFromRoutes/index.js +10 -0
- package/dist/openApiFromRoutes/openApiFromRoutes.document.d.ts +43 -0
- package/dist/openApiFromRoutes/openApiFromRoutes.document.js +64 -0
- package/dist/openApiFromRoutes/openApiFromRoutes.type.d.ts +56 -0
- package/dist/openApiFromRoutes/openApiFromRoutes.type.js +5 -0
- package/dist/openApiHttp/openApiHttpAdapter.core.d.ts +28 -1
- package/dist/openApiHttp/openApiHttpAdapter.core.js +40 -1
- package/dist/openApiRouting/index.d.ts +3 -1
- package/dist/openApiRouting/index.js +2 -0
- package/dist/openApiRouting/routeContent.core.d.ts +22 -0
- package/dist/openApiRouting/routeContent.core.js +101 -0
- package/dist/openApiRouting/routeConverter.core.d.ts +11 -5
- package/dist/openApiRouting/routeConverter.core.js +23 -28
- package/dist/openApiRouting/routeMetadata.type.d.ts +36 -2
- package/dist/openApiRouting/routeScanner.core.d.ts +7 -3
- package/dist/openApiRouting/routeScanner.core.js +46 -10
- package/dist/openApiRouting/routeSchema.core.d.ts +19 -0
- package/dist/openApiRouting/routeSchema.core.js +93 -0
- package/dist/openApiSchema/index.d.ts +1 -0
- package/dist/openApiSchema/index.js +1 -0
- package/dist/openApiSchema/schemaConverter.core.d.ts +2 -0
- package/dist/openApiSchema/schemaConverter.core.js +9 -4
- package/dist/openApiSchema/schemaInput.core.d.ts +28 -0
- package/dist/openApiSchema/schemaInput.core.js +36 -0
- package/dist/openApiSchema/schemaInput.type.d.ts +48 -0
- package/dist/openApiSchema/schemaInput.type.js +5 -0
- package/package.json +7 -6
package/README.md
CHANGED
|
@@ -51,8 +51,12 @@ const yaml = manager.toYAML();
|
|
|
51
51
|
```
|
|
52
52
|
|
|
53
53
|
Every documented response reaches the document — `4xx`, `5xx` and `default`
|
|
54
|
-
included. `:id` becomes `{id}`,
|
|
55
|
-
|
|
54
|
+
included. `:id` becomes `{id}`, every template slot is documented as a
|
|
55
|
+
required path parameter (declared or not), and `params` / `query` /
|
|
56
|
+
`headers` / `body` / response `schema` fields accept `@zudojs/schema` schemas
|
|
57
|
+
— see [Generating from a route table](#generating-from-a-route-table). To
|
|
58
|
+
generate from an `@zudojs/http` router instead of adding routes by hand, use
|
|
59
|
+
that package's `generateOpenAPIDocument(router)` or `mountOpenAPI(router)`.
|
|
56
60
|
|
|
57
61
|
Generation is idempotent: call `generate()` as often as you like.
|
|
58
62
|
|
|
@@ -134,6 +138,83 @@ scheme is read after stripping the control characters browsers ignore, so
|
|
|
134
138
|
`customCss` containing `</style>` throws — that sequence ends the style block
|
|
135
139
|
and lets the rest be parsed as HTML.
|
|
136
140
|
|
|
141
|
+
## Generating from a route table
|
|
142
|
+
|
|
143
|
+
`createOpenAPIDocumentFromRoutes(routes, options)` builds a document from a
|
|
144
|
+
list of structural `OpenAPIRouteDescriptor`s, so any route source can be
|
|
145
|
+
documented from what it actually registers. `@zudojs/http`'s
|
|
146
|
+
`generateOpenAPIDocument(router)` and `mountOpenAPI(router)` feed it the
|
|
147
|
+
router's routes; other sources (such as `@zudojs/api` operations) build the
|
|
148
|
+
same descriptors.
|
|
149
|
+
|
|
150
|
+
```typescript
|
|
151
|
+
import { createOpenAPIDocumentFromRoutes } from "@zudojs/openapi";
|
|
152
|
+
import { objectSchema, stringSchema } from "@zudojs/schema";
|
|
153
|
+
|
|
154
|
+
const user = objectSchema({ id: stringSchema().uuid(), name: stringSchema() });
|
|
155
|
+
|
|
156
|
+
const document = createOpenAPIDocumentFromRoutes(
|
|
157
|
+
[
|
|
158
|
+
{ method: "GET", path: "/users/:id", summary: "Get a user", tags: ["users"],
|
|
159
|
+
responses: { "200": { schema: user }, "404": { description: "No such user" } } },
|
|
160
|
+
{ method: "POST", path: "/users", operationId: "users.create",
|
|
161
|
+
body: objectSchema({ name: stringSchema() }),
|
|
162
|
+
responses: { "201": { schema: user } } },
|
|
163
|
+
],
|
|
164
|
+
{
|
|
165
|
+
info: { title: "Users API", version: "1.0.0" },
|
|
166
|
+
securitySchemes: { bearer: { type: "http", scheme: "bearer" } },
|
|
167
|
+
security: [{ bearer: [] }],
|
|
168
|
+
schemas: { User: user }, // components; converted when they are @zudojs/schema schemas
|
|
169
|
+
validate: true,
|
|
170
|
+
},
|
|
171
|
+
);
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
An `OpenAPIRouteDescriptor` is `RouteOpenAPIMetadata` plus `method` and
|
|
175
|
+
`path`, flattened:
|
|
176
|
+
|
|
177
|
+
| Field | Meaning |
|
|
178
|
+
| --- | --- |
|
|
179
|
+
| `method` | Any case; must be `get put post delete options head patch trace` |
|
|
180
|
+
| `path` | `/users/:id` or `/users/{id}`; optional/regex/wildcard segments are resolved by the source |
|
|
181
|
+
| `summary`, `description`, `operationId`, `tags`, `deprecated`, `servers`, `externalDocs` | Copied to the operation |
|
|
182
|
+
| `security` | Operation security; `[]` marks it public (overrides document security) |
|
|
183
|
+
| `params`, `query`, `headers`, `cookies` | One object schema each; every property becomes a parameter (`required` from the schema; path parameters always required) |
|
|
184
|
+
| `body` | A schema (sent as `application/json`, required) or `{ schema, contentType?, required?, description?, example? }`; a raw `requestBody` wins |
|
|
185
|
+
| `responses` | Per status / `NXX` / `default`: a Response Object, or `{ schema, description?, contentType?, headers?, example? }` (description defaults to the reason phrase, e.g. "Not Found") |
|
|
186
|
+
| `parameters` | Explicit parameters, highest precedence |
|
|
187
|
+
| `inferredParameters` | Parameters the source derived itself (e.g. a regex constraint), lowest precedence |
|
|
188
|
+
| `hidden` | `true` leaves the operation out |
|
|
189
|
+
|
|
190
|
+
Every path template slot is documented as a required string parameter even
|
|
191
|
+
when nothing declares it, and a declared path parameter the template does
|
|
192
|
+
not contain is dropped with a warning rather than producing an invalid
|
|
193
|
+
document. The same metadata fields work in `manager.addRoute({ method, path,
|
|
194
|
+
metadata: { openapi } })`. Conversion warnings reach `onRouteWarning`
|
|
195
|
+
(one message at a time), `onSchemaWarning` under the name `"routes"`, and
|
|
196
|
+
`manager.routeWarnings()`, each prefixed with the route (`DELETE /users/:id: ...`).
|
|
197
|
+
|
|
198
|
+
No response status is invented. A route that documents no responses (or
|
|
199
|
+
`responses: {}`) gets a spec-valid `default` response described as
|
|
200
|
+
`"Undocumented response"` (`UNDOCUMENTED_RESPONSE_DESCRIPTION`) and a route
|
|
201
|
+
warning, so the omission shows up instead of a `204` DELETE being published
|
|
202
|
+
as `200`:
|
|
203
|
+
|
|
204
|
+
```typescript
|
|
205
|
+
const document = createOpenAPIDocumentFromRoutes(
|
|
206
|
+
[{ method: "DELETE", path: "/users/:id" }],
|
|
207
|
+
{ info, onRouteWarning: (message) => logger.warn(message) },
|
|
208
|
+
);
|
|
209
|
+
// paths["/users/{id}"].delete.responses → { default: { description: "Undocumented response" } }
|
|
210
|
+
// warned: "DELETE /users/:id: no responses are documented; ..."
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
`createOpenAPIManagerFromRoutes(routes, options)` returns the manager instead
|
|
214
|
+
(for `toResponse` / `toUIResponse`); `manager.setRoutes(routes)` replaces its
|
|
215
|
+
whole route set, rejecting duplicates before anything changes, and
|
|
216
|
+
`routeDescriptorToRouteInfo` converts a descriptor to `addRoute`'s shape.
|
|
217
|
+
|
|
137
218
|
## Branding
|
|
138
219
|
|
|
139
220
|
ReDoc, Scalar and several other viewers read a logo from the non-standard
|
package/dist/index.d.ts
CHANGED
|
@@ -4,7 +4,9 @@
|
|
|
4
4
|
* API contract and documentation engine for the Zudojs framework.
|
|
5
5
|
*
|
|
6
6
|
* Generates OpenAPI specifications from application routes, schemas,
|
|
7
|
-
* and metadata. Supports OpenAPI 3.0 and 3.1.
|
|
7
|
+
* and metadata. Supports OpenAPI 3.0 and 3.1. A route table from any source
|
|
8
|
+
* becomes a document through `createOpenAPIDocumentFromRoutes`;
|
|
9
|
+
* `@zudojs/http` uses it to document a router's registered routes.
|
|
8
10
|
*
|
|
9
11
|
* @example
|
|
10
12
|
* ```ts
|
|
@@ -42,11 +44,13 @@ export { OpenAPIDocumentBuilder, createOpenAPIDocumentBuilder, type OpenAPIDocum
|
|
|
42
44
|
export { OpenAPIRegistryImpl } from "./openApiRegistry/index.js";
|
|
43
45
|
export type { OpenAPIRegistry, OpenAPIRoute, OpenAPIComponentRegistration, } from "./openApiRegistry/index.js";
|
|
44
46
|
export { OpenAPIError, OpenAPIValidationError, OpenAPIDocumentError, OpenAPIComponentError, OpenAPIComponentConflictError, OpenAPIReferenceError, OpenAPIRouteError, OpenAPISchemaError, OpenAPISerializationError, OpenAPIVersionError, OpenAPIOperationError, createOpenAPIError, isOpenAPIError, formatIssuePath, type OpenAPIErrorOptions, type OpenAPIValidationIssue, } from "./openApiErrors/index.js";
|
|
45
|
-
export { DEFAULT_OPENAPI_VERSION, SUPPORTED_OPENAPI_VERSIONS, MAX_OPERATION_ID_LENGTH, COMPONENT_REF_PREFIX, DEFAULT_MEDIA_TYPE, STATUS_CODE_CATEGORIES, RESPONSE_KEY_PATTERN, PATH_TEMPLATE_PARAMETER, DEFAULT_SERVER_URL, DOCUMENT_CACHE_TTL_MS, } from "./openApiConstants/index.js";
|
|
46
|
-
export { toOpenAPIPath, extractPathParameters, convertRouteToOpenAPI, buildResponses, isOpenAPIMethod, ZUDOLIB_TO_OPENAPI_METHODS, OpenAPIRouteScannerImpl, } from "./openApiRouting/index.js";
|
|
47
|
-
export type { RouteMetadata, RouteOpenAPIMetadata, RouteParameterMetadata, RouteInfo, OpenAPIHttpMethod, } from "./openApiRouting/index.js";
|
|
48
|
-
export {
|
|
49
|
-
export type {
|
|
47
|
+
export { DEFAULT_OPENAPI_VERSION, SUPPORTED_OPENAPI_VERSIONS, MAX_OPERATION_ID_LENGTH, COMPONENT_REF_PREFIX, DEFAULT_MEDIA_TYPE, STATUS_CODE_CATEGORIES, RESPONSE_KEY_PATTERN, PATH_TEMPLATE_PARAMETER, DEFAULT_SERVER_URL, DOCUMENT_CACHE_TTL_MS, UNDOCUMENTED_RESPONSE_DESCRIPTION, } from "./openApiConstants/index.js";
|
|
48
|
+
export { toOpenAPIPath, extractPathParameters, convertRouteToOpenAPI, buildResponses, isOpenAPIMethod, ZUDOLIB_TO_OPENAPI_METHODS, OpenAPIRouteScannerImpl, buildOperationParameters, buildOperationRequestBody, buildOperationResponses, describeResponseKey, } from "./openApiRouting/index.js";
|
|
49
|
+
export type { RouteMetadata, RouteOpenAPIMetadata, RouteParameterMetadata, RouteInfo, OpenAPIHttpMethod, OpenAPISchemaInput, OpenAPIRouteBody, OpenAPIRouteResponse, RouteConversionOptions, } from "./openApiRouting/index.js";
|
|
50
|
+
export { createOpenAPIDocumentFromRoutes, createOpenAPIManagerFromRoutes, routeDescriptorToRouteInfo, } from "./openApiFromRoutes/index.js";
|
|
51
|
+
export type { OpenAPIRouteDescriptor, OpenAPIDocumentFromRoutesOptions, } from "./openApiFromRoutes/index.js";
|
|
52
|
+
export { convertSchema, createSchemaConverter, isVersion31, SchemaRegistryImpl, createComponentReference, escapeJsonPointerSegment, unescapeJsonPointerSegment, isSchemaDefinition, resolveSchemaInput, } from "./openApiSchema/index.js";
|
|
53
|
+
export type { SchemaInputOptions, SchemaConverter, SchemaConversionResult, SchemaConversionOptions, SchemaRegistry, SchemaRegistryOptions, ComponentSection, } from "./openApiSchema/index.js";
|
|
50
54
|
export { OpenAPIValidatorImpl, createOpenAPIValidator, } from "./openApiValidation/index.js";
|
|
51
55
|
export type { OpenAPIValidator, OpenAPIValidationResult, } from "./openApiValidation/index.js";
|
|
52
56
|
export { toOpenAPIJSON, toOpenAPIYAML, } from "./openApiSerialization/openApiSerializer.core.js";
|
package/dist/index.js
CHANGED
|
@@ -4,7 +4,9 @@
|
|
|
4
4
|
* API contract and documentation engine for the Zudojs framework.
|
|
5
5
|
*
|
|
6
6
|
* Generates OpenAPI specifications from application routes, schemas,
|
|
7
|
-
* and metadata. Supports OpenAPI 3.0 and 3.1.
|
|
7
|
+
* and metadata. Supports OpenAPI 3.0 and 3.1. A route table from any source
|
|
8
|
+
* becomes a document through `createOpenAPIDocumentFromRoutes`;
|
|
9
|
+
* `@zudojs/http` uses it to document a router's registered routes.
|
|
8
10
|
*
|
|
9
11
|
* @example
|
|
10
12
|
* ```ts
|
|
@@ -46,11 +48,13 @@ export { OpenAPIRegistryImpl } from "./openApiRegistry/index.js";
|
|
|
46
48
|
/* ─── Errors ────────────────────────────────────────────────────────────── */
|
|
47
49
|
export { OpenAPIError, OpenAPIValidationError, OpenAPIDocumentError, OpenAPIComponentError, OpenAPIComponentConflictError, OpenAPIReferenceError, OpenAPIRouteError, OpenAPISchemaError, OpenAPISerializationError, OpenAPIVersionError, OpenAPIOperationError, createOpenAPIError, isOpenAPIError, formatIssuePath, } from "./openApiErrors/index.js";
|
|
48
50
|
/* ─── Constants ─────────────────────────────────────────────────────────── */
|
|
49
|
-
export { DEFAULT_OPENAPI_VERSION, SUPPORTED_OPENAPI_VERSIONS, MAX_OPERATION_ID_LENGTH, COMPONENT_REF_PREFIX, DEFAULT_MEDIA_TYPE, STATUS_CODE_CATEGORIES, RESPONSE_KEY_PATTERN, PATH_TEMPLATE_PARAMETER, DEFAULT_SERVER_URL, DOCUMENT_CACHE_TTL_MS, } from "./openApiConstants/index.js";
|
|
51
|
+
export { DEFAULT_OPENAPI_VERSION, SUPPORTED_OPENAPI_VERSIONS, MAX_OPERATION_ID_LENGTH, COMPONENT_REF_PREFIX, DEFAULT_MEDIA_TYPE, STATUS_CODE_CATEGORIES, RESPONSE_KEY_PATTERN, PATH_TEMPLATE_PARAMETER, DEFAULT_SERVER_URL, DOCUMENT_CACHE_TTL_MS, UNDOCUMENTED_RESPONSE_DESCRIPTION, } from "./openApiConstants/index.js";
|
|
50
52
|
/* ─── Routing ───────────────────────────────────────────────────────────── */
|
|
51
|
-
export { toOpenAPIPath, extractPathParameters, convertRouteToOpenAPI, buildResponses, isOpenAPIMethod, ZUDOLIB_TO_OPENAPI_METHODS, OpenAPIRouteScannerImpl, } from "./openApiRouting/index.js";
|
|
53
|
+
export { toOpenAPIPath, extractPathParameters, convertRouteToOpenAPI, buildResponses, isOpenAPIMethod, ZUDOLIB_TO_OPENAPI_METHODS, OpenAPIRouteScannerImpl, buildOperationParameters, buildOperationRequestBody, buildOperationResponses, describeResponseKey, } from "./openApiRouting/index.js";
|
|
54
|
+
/* ─── Generation from a route table ────────────────────────────────────── */
|
|
55
|
+
export { createOpenAPIDocumentFromRoutes, createOpenAPIManagerFromRoutes, routeDescriptorToRouteInfo, } from "./openApiFromRoutes/index.js";
|
|
52
56
|
/* ─── Schema conversion ─────────────────────────────────────────────────── */
|
|
53
|
-
export { convertSchema, createSchemaConverter, isVersion31, SchemaRegistryImpl, createComponentReference, escapeJsonPointerSegment, unescapeJsonPointerSegment, } from "./openApiSchema/index.js";
|
|
57
|
+
export { convertSchema, createSchemaConverter, isVersion31, SchemaRegistryImpl, createComponentReference, escapeJsonPointerSegment, unescapeJsonPointerSegment, isSchemaDefinition, resolveSchemaInput, } from "./openApiSchema/index.js";
|
|
54
58
|
/* ─── Validation ────────────────────────────────────────────────────────── */
|
|
55
59
|
export { OpenAPIValidatorImpl, createOpenAPIValidator, } from "./openApiValidation/index.js";
|
|
56
60
|
/* ─── Serialization ─────────────────────────────────────────────────────── */
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @zudojs/openapi/openApiConstants
|
|
3
3
|
*/
|
|
4
|
-
export { DEFAULT_OPENAPI_VERSION, SUPPORTED_OPENAPI_VERSIONS, MAX_OPERATION_ID_LENGTH, COMPONENT_REF_PREFIX, DEFAULT_MEDIA_TYPE, STATUS_CODE_CATEGORIES, RESPONSE_KEY_PATTERN, PATH_TEMPLATE_PARAMETER, DEFAULT_SERVER_URL, DOCUMENT_CACHE_TTL_MS, } from "./openApiConstants.core.js";
|
|
4
|
+
export { DEFAULT_OPENAPI_VERSION, SUPPORTED_OPENAPI_VERSIONS, MAX_OPERATION_ID_LENGTH, COMPONENT_REF_PREFIX, DEFAULT_MEDIA_TYPE, STATUS_CODE_CATEGORIES, RESPONSE_KEY_PATTERN, PATH_TEMPLATE_PARAMETER, DEFAULT_SERVER_URL, DOCUMENT_CACHE_TTL_MS, UNDOCUMENTED_RESPONSE_DESCRIPTION, } from "./openApiConstants.core.js";
|
|
5
5
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @zudojs/openapi/openApiConstants
|
|
3
3
|
*/
|
|
4
|
-
export { DEFAULT_OPENAPI_VERSION, SUPPORTED_OPENAPI_VERSIONS, MAX_OPERATION_ID_LENGTH, COMPONENT_REF_PREFIX, DEFAULT_MEDIA_TYPE, STATUS_CODE_CATEGORIES, RESPONSE_KEY_PATTERN, PATH_TEMPLATE_PARAMETER, DEFAULT_SERVER_URL, DOCUMENT_CACHE_TTL_MS, } from "./openApiConstants.core.js";
|
|
4
|
+
export { DEFAULT_OPENAPI_VERSION, SUPPORTED_OPENAPI_VERSIONS, MAX_OPERATION_ID_LENGTH, COMPONENT_REF_PREFIX, DEFAULT_MEDIA_TYPE, STATUS_CODE_CATEGORIES, RESPONSE_KEY_PATTERN, PATH_TEMPLATE_PARAMETER, DEFAULT_SERVER_URL, DOCUMENT_CACHE_TTL_MS, UNDOCUMENTED_RESPONSE_DESCRIPTION, } from "./openApiConstants.core.js";
|
|
5
5
|
//# sourceMappingURL=index.js.map
|
|
@@ -39,6 +39,11 @@ export declare const STATUS_CODE_CATEGORIES: {
|
|
|
39
39
|
export declare const RESPONSE_KEY_PATTERN: RegExp;
|
|
40
40
|
/** OpenAPI path template parameter, e.g. `{orderId}`. */
|
|
41
41
|
export declare const PATH_TEMPLATE_PARAMETER: RegExp;
|
|
42
|
+
/**
|
|
43
|
+
* Description of the `default` response emitted for an operation that
|
|
44
|
+
* documents no responses. No status code is invented for it.
|
|
45
|
+
*/
|
|
46
|
+
export declare const UNDOCUMENTED_RESPONSE_DESCRIPTION = "Undocumented response";
|
|
42
47
|
/**
|
|
43
48
|
* Default server URL.
|
|
44
49
|
*/
|
|
@@ -46,6 +46,11 @@ export const STATUS_CODE_CATEGORIES = {
|
|
|
46
46
|
export const RESPONSE_KEY_PATTERN = /^(default|[1-5](XX|\d{2}))$/;
|
|
47
47
|
/** OpenAPI path template parameter, e.g. `{orderId}`. */
|
|
48
48
|
export const PATH_TEMPLATE_PARAMETER = /\{([^{}]+)\}/g;
|
|
49
|
+
/**
|
|
50
|
+
* Description of the `default` response emitted for an operation that
|
|
51
|
+
* documents no responses. No status code is invented for it.
|
|
52
|
+
*/
|
|
53
|
+
export const UNDOCUMENTED_RESPONSE_DESCRIPTION = "Undocumented response";
|
|
49
54
|
/**
|
|
50
55
|
* Default server URL.
|
|
51
56
|
*/
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @zudojs/openapi/openApiFromRoutes
|
|
3
|
+
*
|
|
4
|
+
* Generates a document from a route table described by transport-neutral
|
|
5
|
+
* {@link OpenAPIRouteDescriptor}s, so any route source — an `@zudojs/http`
|
|
6
|
+
* router, an `@zudojs/api` registry, a hand-written list — can be documented
|
|
7
|
+
* from what it actually registers.
|
|
8
|
+
*/
|
|
9
|
+
export type { OpenAPIRouteDescriptor, OpenAPIDocumentFromRoutesOptions, } from "./openApiFromRoutes.type.js";
|
|
10
|
+
export { createOpenAPIDocumentFromRoutes, createOpenAPIManagerFromRoutes, routeDescriptorToRouteInfo, } from "./openApiFromRoutes.document.js";
|
|
11
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @zudojs/openapi/openApiFromRoutes
|
|
3
|
+
*
|
|
4
|
+
* Generates a document from a route table described by transport-neutral
|
|
5
|
+
* {@link OpenAPIRouteDescriptor}s, so any route source — an `@zudojs/http`
|
|
6
|
+
* router, an `@zudojs/api` registry, a hand-written list — can be documented
|
|
7
|
+
* from what it actually registers.
|
|
8
|
+
*/
|
|
9
|
+
export { createOpenAPIDocumentFromRoutes, createOpenAPIManagerFromRoutes, routeDescriptorToRouteInfo, } from "./openApiFromRoutes.document.js";
|
|
10
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Document generation from a route table.
|
|
3
|
+
*/
|
|
4
|
+
import type { OpenAPIDocument } from "../openApiTypes/openApiTypes.core.js";
|
|
5
|
+
import type { RouteInfo } from "../openApiRouting/routeMetadata.type.js";
|
|
6
|
+
import { OpenAPIManager } from "../openApiHttp/openApiHttpAdapter.core.js";
|
|
7
|
+
import type { OpenAPIDocumentFromRoutesOptions, OpenAPIRouteDescriptor } from "./openApiFromRoutes.type.js";
|
|
8
|
+
/**
|
|
9
|
+
* Splits a descriptor into the manager's `{ method, path, metadata }` shape.
|
|
10
|
+
*
|
|
11
|
+
* @throws {OpenAPIRouteError} When the method has no OpenAPI path item field.
|
|
12
|
+
*/
|
|
13
|
+
export declare function routeDescriptorToRouteInfo(descriptor: OpenAPIRouteDescriptor): RouteInfo;
|
|
14
|
+
/**
|
|
15
|
+
* Creates an {@link OpenAPIManager} holding `routes`, ready to generate,
|
|
16
|
+
* serialize and serve (`toResponse`, `toUIResponse`). Refresh it later with
|
|
17
|
+
* `manager.setRoutes(descriptors.map(routeDescriptorToRouteInfo))`.
|
|
18
|
+
*
|
|
19
|
+
* @throws {OpenAPIRouteError} On an unsupported method or a duplicate route.
|
|
20
|
+
*/
|
|
21
|
+
export declare function createOpenAPIManagerFromRoutes(routes: readonly OpenAPIRouteDescriptor[], options: OpenAPIDocumentFromRoutesOptions): OpenAPIManager;
|
|
22
|
+
/**
|
|
23
|
+
* Generates an OpenAPI document from a list of route descriptors.
|
|
24
|
+
*
|
|
25
|
+
* This is the transport-neutral entry point: `@zudojs/http` feeds it the
|
|
26
|
+
* routes a router actually has registered, and any other source can feed it
|
|
27
|
+
* the same structural {@link OpenAPIRouteDescriptor}s.
|
|
28
|
+
*
|
|
29
|
+
* ```ts
|
|
30
|
+
* const document = createOpenAPIDocumentFromRoutes(
|
|
31
|
+
* [{ method: "GET", path: "/users/:id", summary: "Get a user",
|
|
32
|
+
* responses: { "200": { schema: userSchema } } }],
|
|
33
|
+
* { info: { title: "Users", version: "1.0.0" }, validate: true },
|
|
34
|
+
* );
|
|
35
|
+
* ```
|
|
36
|
+
*
|
|
37
|
+
* @throws {OpenAPIRouteError} On an unsupported method, an inexpressible
|
|
38
|
+
* path or a duplicate route.
|
|
39
|
+
* @throws {OpenAPIValidationError} When `validate` is set and the document
|
|
40
|
+
* is invalid.
|
|
41
|
+
*/
|
|
42
|
+
export declare function createOpenAPIDocumentFromRoutes(routes: readonly OpenAPIRouteDescriptor[], options: OpenAPIDocumentFromRoutesOptions): OpenAPIDocument;
|
|
43
|
+
//# sourceMappingURL=openApiFromRoutes.document.d.ts.map
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Document generation from a route table.
|
|
3
|
+
*/
|
|
4
|
+
import { isOpenAPIMethod } from "../openApiRouting/routeConverter.core.js";
|
|
5
|
+
import { isSchemaDefinition } from "../openApiSchema/schemaInput.core.js";
|
|
6
|
+
import { OpenAPIManager } from "../openApiHttp/openApiHttpAdapter.core.js";
|
|
7
|
+
import { OpenAPIRouteError } from "../openApiErrors/openApiError.types.js";
|
|
8
|
+
/**
|
|
9
|
+
* Splits a descriptor into the manager's `{ method, path, metadata }` shape.
|
|
10
|
+
*
|
|
11
|
+
* @throws {OpenAPIRouteError} When the method has no OpenAPI path item field.
|
|
12
|
+
*/
|
|
13
|
+
export function routeDescriptorToRouteInfo(descriptor) {
|
|
14
|
+
const { method, path, ...openapi } = descriptor;
|
|
15
|
+
if (typeof method !== "string" || !isOpenAPIMethod(method)) {
|
|
16
|
+
throw new OpenAPIRouteError(`HTTP method "${String(method)}" of route ${String(path)} has no OpenAPI path item field.`, { metadata: { method, path } });
|
|
17
|
+
}
|
|
18
|
+
return { method: method.toLowerCase(), path, metadata: { openapi } };
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Creates an {@link OpenAPIManager} holding `routes`, ready to generate,
|
|
22
|
+
* serialize and serve (`toResponse`, `toUIResponse`). Refresh it later with
|
|
23
|
+
* `manager.setRoutes(descriptors.map(routeDescriptorToRouteInfo))`.
|
|
24
|
+
*
|
|
25
|
+
* @throws {OpenAPIRouteError} On an unsupported method or a duplicate route.
|
|
26
|
+
*/
|
|
27
|
+
export function createOpenAPIManagerFromRoutes(routes, options) {
|
|
28
|
+
const { validate: _validate, securitySchemes, schemas, ...managerOptions } = options;
|
|
29
|
+
const manager = new OpenAPIManager({ ...managerOptions, cacheTtlMs: 0 });
|
|
30
|
+
for (const [name, scheme] of Object.entries(securitySchemes ?? {})) {
|
|
31
|
+
manager.addSecurityScheme(name, scheme);
|
|
32
|
+
}
|
|
33
|
+
for (const [name, schema] of Object.entries(schemas ?? {})) {
|
|
34
|
+
if (isSchemaDefinition(schema))
|
|
35
|
+
manager.addSchema(name, schema);
|
|
36
|
+
else
|
|
37
|
+
manager.addRawSchema(name, schema);
|
|
38
|
+
}
|
|
39
|
+
return manager.setRoutes(routes.map(routeDescriptorToRouteInfo));
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Generates an OpenAPI document from a list of route descriptors.
|
|
43
|
+
*
|
|
44
|
+
* This is the transport-neutral entry point: `@zudojs/http` feeds it the
|
|
45
|
+
* routes a router actually has registered, and any other source can feed it
|
|
46
|
+
* the same structural {@link OpenAPIRouteDescriptor}s.
|
|
47
|
+
*
|
|
48
|
+
* ```ts
|
|
49
|
+
* const document = createOpenAPIDocumentFromRoutes(
|
|
50
|
+
* [{ method: "GET", path: "/users/:id", summary: "Get a user",
|
|
51
|
+
* responses: { "200": { schema: userSchema } } }],
|
|
52
|
+
* { info: { title: "Users", version: "1.0.0" }, validate: true },
|
|
53
|
+
* );
|
|
54
|
+
* ```
|
|
55
|
+
*
|
|
56
|
+
* @throws {OpenAPIRouteError} On an unsupported method, an inexpressible
|
|
57
|
+
* path or a duplicate route.
|
|
58
|
+
* @throws {OpenAPIValidationError} When `validate` is set and the document
|
|
59
|
+
* is invalid.
|
|
60
|
+
*/
|
|
61
|
+
export function createOpenAPIDocumentFromRoutes(routes, options) {
|
|
62
|
+
return createOpenAPIManagerFromRoutes(routes, options).generate(options.validate ?? false);
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=openApiFromRoutes.document.js.map
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Transport-neutral input for generating a document from a route table.
|
|
3
|
+
*/
|
|
4
|
+
import type { OpenAPIInfo, OpenAPISecurityScheme } from "../openApiTypes/openApiTypes.core.js";
|
|
5
|
+
import type { RouteOpenAPIMetadata } from "../openApiRouting/routeMetadata.type.js";
|
|
6
|
+
import type { OpenAPIManagerOptions } from "../openApiHttp/openApiHttpAdapter.core.js";
|
|
7
|
+
/**
|
|
8
|
+
* One operation, described structurally so that any route source can feed
|
|
9
|
+
* {@link createOpenAPIDocumentFromRoutes}: an `@zudojs/http` router, an
|
|
10
|
+
* `@zudojs/api` operation registry, or a hand-written list.
|
|
11
|
+
*
|
|
12
|
+
* It is {@link RouteOpenAPIMetadata} plus the operation's method and path,
|
|
13
|
+
* flattened into one object:
|
|
14
|
+
*
|
|
15
|
+
* - `method` — any case (`"GET"`, `"post"`); it must be one an OpenAPI path
|
|
16
|
+
* item can carry (`get put post delete options head patch trace`).
|
|
17
|
+
* - `path` — `/users/:id` or `/users/{id}`. Optional segments, typed or
|
|
18
|
+
* regex-constrained `:name(...)` segments and wildcards have no OpenAPI
|
|
19
|
+
* spelling; the source resolves them (see `inferredParameters`) before
|
|
20
|
+
* handing the path over.
|
|
21
|
+
* - `summary`, `description`, `operationId`, `tags`, `deprecated`,
|
|
22
|
+
* `security` (`[]` marks a public operation), `servers`, `externalDocs`.
|
|
23
|
+
* - `params`, `query`, `headers`, `cookies` — one object schema each; every
|
|
24
|
+
* property becomes a parameter. A `@zudojs/schema` schema is converted, any
|
|
25
|
+
* other object is used as an OpenAPI schema.
|
|
26
|
+
* - `body` — a schema, or `{ schema, contentType?, required?, description? }`.
|
|
27
|
+
* - `responses` — keyed by status, `NXX` range or `default`; each entry is a
|
|
28
|
+
* Response Object or `{ schema, description?, contentType?, headers? }`.
|
|
29
|
+
* - `parameters` — explicit parameters, highest precedence.
|
|
30
|
+
* - `inferredParameters` — parameters the source derived itself, lowest
|
|
31
|
+
* precedence.
|
|
32
|
+
* - `hidden: true` — leave the operation out of the document.
|
|
33
|
+
*
|
|
34
|
+
* Every path template slot is documented even when nothing declares it.
|
|
35
|
+
*/
|
|
36
|
+
export interface OpenAPIRouteDescriptor extends RouteOpenAPIMetadata {
|
|
37
|
+
/** HTTP method, any case. */
|
|
38
|
+
readonly method: string;
|
|
39
|
+
/** Route path, `/users/:id` or `/users/{id}`. */
|
|
40
|
+
readonly path: string;
|
|
41
|
+
}
|
|
42
|
+
/** Options for {@link createOpenAPIDocumentFromRoutes}. */
|
|
43
|
+
export interface OpenAPIDocumentFromRoutesOptions extends Omit<OpenAPIManagerOptions, "info" | "cacheTtlMs" | "now"> {
|
|
44
|
+
/** Document metadata (title and version are required by the spec). */
|
|
45
|
+
readonly info: OpenAPIInfo;
|
|
46
|
+
/** Validate the result and throw `OpenAPIValidationError` if invalid. */
|
|
47
|
+
readonly validate?: boolean;
|
|
48
|
+
/** Registered under `components.securitySchemes`. */
|
|
49
|
+
readonly securitySchemes?: Readonly<Record<string, OpenAPISecurityScheme>>;
|
|
50
|
+
/**
|
|
51
|
+
* Component schemas, registered under `components.schemas`. A
|
|
52
|
+
* `@zudojs/schema` schema is converted; any other object is used as-is.
|
|
53
|
+
*/
|
|
54
|
+
readonly schemas?: Readonly<Record<string, unknown>>;
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=openApiFromRoutes.type.d.ts.map
|
|
@@ -17,8 +17,20 @@ export interface OpenAPIManagerOptions {
|
|
|
17
17
|
* invalidates the cache regardless.
|
|
18
18
|
*/
|
|
19
19
|
readonly cacheTtlMs?: number;
|
|
20
|
-
/**
|
|
20
|
+
/**
|
|
21
|
+
* Reports what a schema conversion could not express: component schemas
|
|
22
|
+
* under their component name, route-declared schemas and parameters under
|
|
23
|
+
* `"routes"` once per generation.
|
|
24
|
+
*/
|
|
21
25
|
readonly onSchemaWarning?: (name: string, warnings: readonly string[]) => void;
|
|
26
|
+
/**
|
|
27
|
+
* Receives each route warning of a generation as it is produced, each
|
|
28
|
+
* prefixed with the route (`DELETE /users/:id: ...`): route-declared
|
|
29
|
+
* schemas or parameters that could not be expressed, and operations that
|
|
30
|
+
* document no responses. The same messages are returned by
|
|
31
|
+
* {@link OpenAPIManager.routeWarnings}.
|
|
32
|
+
*/
|
|
33
|
+
readonly onRouteWarning?: (message: string) => void;
|
|
22
34
|
/** Supplies the clock, for tests. */
|
|
23
35
|
readonly now?: () => number;
|
|
24
36
|
/**
|
|
@@ -59,6 +71,9 @@ export declare class OpenAPIManager {
|
|
|
59
71
|
private readonly logo;
|
|
60
72
|
/** True when `branding` was a caller-supplied logo rather than the default. */
|
|
61
73
|
private readonly customLogo;
|
|
74
|
+
private readonly onSchemaWarning;
|
|
75
|
+
private readonly onRouteWarning;
|
|
76
|
+
private lastRouteWarnings;
|
|
62
77
|
private cachedDocument?;
|
|
63
78
|
private cachedAt;
|
|
64
79
|
/** Whether the cached document was produced by a validating generate. */
|
|
@@ -76,6 +91,12 @@ export declare class OpenAPIManager {
|
|
|
76
91
|
addRoute(route: RouteInfo): this;
|
|
77
92
|
/** Registers a route, replacing any existing one for the same method+path. */
|
|
78
93
|
setRoute(route: RouteInfo): this;
|
|
94
|
+
/**
|
|
95
|
+
* Replaces every registered route with `routes`, for keeping the document
|
|
96
|
+
* in step with a live route table. Duplicates are rejected before anything
|
|
97
|
+
* is replaced, so a failed call leaves the previous routes in place.
|
|
98
|
+
*/
|
|
99
|
+
setRoutes(routes: readonly RouteInfo[]): this;
|
|
79
100
|
/** Removes a route. Returns whether one was removed. */
|
|
80
101
|
removeRoute(method: OpenAPIHttpMethod, path: string): boolean;
|
|
81
102
|
/**
|
|
@@ -89,6 +110,12 @@ export declare class OpenAPIManager {
|
|
|
89
110
|
addRawSchema(name: string, schema: OpenAPISchema): this;
|
|
90
111
|
/** Conversion warnings, keyed by component name. */
|
|
91
112
|
schemaWarnings(): ReadonlyMap<string, readonly string[]>;
|
|
113
|
+
/**
|
|
114
|
+
* The route warnings of the last generation, each prefixed with the route
|
|
115
|
+
* (`GET /users/:id: ...`): what could not be expressed for route-declared
|
|
116
|
+
* schemas and parameters, and operations that document no responses.
|
|
117
|
+
*/
|
|
118
|
+
routeWarnings(): readonly string[];
|
|
92
119
|
/**
|
|
93
120
|
* Builds the document from the registered routes and components.
|
|
94
121
|
*
|
|
@@ -24,6 +24,9 @@ export class OpenAPIManager {
|
|
|
24
24
|
logo;
|
|
25
25
|
/** True when `branding` was a caller-supplied logo rather than the default. */
|
|
26
26
|
customLogo;
|
|
27
|
+
onSchemaWarning;
|
|
28
|
+
onRouteWarning;
|
|
29
|
+
lastRouteWarnings = [];
|
|
27
30
|
cachedDocument;
|
|
28
31
|
cachedAt = 0;
|
|
29
32
|
/** Whether the cached document was produced by a validating generate. */
|
|
@@ -39,6 +42,8 @@ export class OpenAPIManager {
|
|
|
39
42
|
version: options.version ?? DEFAULT_OPENAPI_VERSION,
|
|
40
43
|
onWarning: options.onSchemaWarning,
|
|
41
44
|
});
|
|
45
|
+
this.onSchemaWarning = options.onSchemaWarning;
|
|
46
|
+
this.onRouteWarning = options.onRouteWarning;
|
|
42
47
|
this.cacheTtlMs = options.cacheTtlMs ?? DOCUMENT_CACHE_TTL_MS;
|
|
43
48
|
this.now = options.now ?? (() => Date.now());
|
|
44
49
|
this.logo =
|
|
@@ -95,6 +100,20 @@ export class OpenAPIManager {
|
|
|
95
100
|
this.scanner.setRoute(route);
|
|
96
101
|
return this.invalidateCache();
|
|
97
102
|
}
|
|
103
|
+
/**
|
|
104
|
+
* Replaces every registered route with `routes`, for keeping the document
|
|
105
|
+
* in step with a live route table. Duplicates are rejected before anything
|
|
106
|
+
* is replaced, so a failed call leaves the previous routes in place.
|
|
107
|
+
*/
|
|
108
|
+
setRoutes(routes) {
|
|
109
|
+
const next = new OpenAPIRouteScannerImpl();
|
|
110
|
+
for (const route of routes)
|
|
111
|
+
next.addRoute(route);
|
|
112
|
+
this.scanner.clear();
|
|
113
|
+
for (const route of routes)
|
|
114
|
+
this.scanner.addRoute(route);
|
|
115
|
+
return this.invalidateCache();
|
|
116
|
+
}
|
|
98
117
|
/** Removes a route. Returns whether one was removed. */
|
|
99
118
|
removeRoute(method, path) {
|
|
100
119
|
const removed = this.scanner.removeRoute(method, path);
|
|
@@ -122,6 +141,14 @@ export class OpenAPIManager {
|
|
|
122
141
|
schemaWarnings() {
|
|
123
142
|
return this.schemas.warnings();
|
|
124
143
|
}
|
|
144
|
+
/**
|
|
145
|
+
* The route warnings of the last generation, each prefixed with the route
|
|
146
|
+
* (`GET /users/:id: ...`): what could not be expressed for route-declared
|
|
147
|
+
* schemas and parameters, and operations that document no responses.
|
|
148
|
+
*/
|
|
149
|
+
routeWarnings() {
|
|
150
|
+
return this.lastRouteWarnings;
|
|
151
|
+
}
|
|
125
152
|
/* ── Generation ──────────────────────────────────────────────────────── */
|
|
126
153
|
/**
|
|
127
154
|
* Builds the document from the registered routes and components.
|
|
@@ -134,9 +161,21 @@ export class OpenAPIManager {
|
|
|
134
161
|
// hidden, so `removeRoute()` had no effect once a document had been
|
|
135
162
|
// generated.
|
|
136
163
|
this.registry.clearRoutes();
|
|
137
|
-
|
|
164
|
+
const routeWarnings = [];
|
|
165
|
+
const scanned = this.scanner.scan({
|
|
166
|
+
version: this.registry.version,
|
|
167
|
+
onWarning: (message) => {
|
|
168
|
+
routeWarnings.push(message);
|
|
169
|
+
this.onRouteWarning?.(message);
|
|
170
|
+
},
|
|
171
|
+
});
|
|
172
|
+
for (const route of scanned) {
|
|
138
173
|
this.registry.setRoute(route);
|
|
139
174
|
}
|
|
175
|
+
this.lastRouteWarnings = Object.freeze(routeWarnings);
|
|
176
|
+
if (routeWarnings.length > 0) {
|
|
177
|
+
this.onSchemaWarning?.("routes", this.lastRouteWarnings);
|
|
178
|
+
}
|
|
140
179
|
// Brand the document unless the caller supplied a logo or opted out.
|
|
141
180
|
const info = this.registry.getInfo();
|
|
142
181
|
if (this.logo && !info["x-logo"]) {
|
|
@@ -3,7 +3,9 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Route metadata, conversion, and scanning for OpenAPI generation.
|
|
5
5
|
*/
|
|
6
|
-
export type { RouteMetadata, RouteOpenAPIMetadata, RouteParameterMetadata, RouteInfo, OpenAPIHttpMethod, } from "./routeMetadata.type.js";
|
|
6
|
+
export type { RouteMetadata, RouteOpenAPIMetadata, RouteParameterMetadata, RouteInfo, OpenAPIHttpMethod, OpenAPISchemaInput, OpenAPIRouteBody, OpenAPIRouteResponse, RouteConversionOptions, } from "./routeMetadata.type.js";
|
|
7
7
|
export { toOpenAPIPath, extractPathParameters, convertRouteToOpenAPI, buildResponses, isOpenAPIMethod, ZUDOLIB_TO_OPENAPI_METHODS, } from "./routeConverter.core.js";
|
|
8
8
|
export { OpenAPIRouteScannerImpl } from "./routeScanner.core.js";
|
|
9
|
+
export { buildOperationParameters } from "./routeSchema.core.js";
|
|
10
|
+
export { buildOperationRequestBody, buildOperationResponses, describeResponseKey, } from "./routeContent.core.js";
|
|
9
11
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -5,4 +5,6 @@
|
|
|
5
5
|
*/
|
|
6
6
|
export { toOpenAPIPath, extractPathParameters, convertRouteToOpenAPI, buildResponses, isOpenAPIMethod, ZUDOLIB_TO_OPENAPI_METHODS, } from "./routeConverter.core.js";
|
|
7
7
|
export { OpenAPIRouteScannerImpl } from "./routeScanner.core.js";
|
|
8
|
+
export { buildOperationParameters } from "./routeSchema.core.js";
|
|
9
|
+
export { buildOperationRequestBody, buildOperationResponses, describeResponseKey, } from "./routeContent.core.js";
|
|
8
10
|
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Request body and response construction for route conversion.
|
|
3
|
+
*
|
|
4
|
+
* Both accept schemas as well as raw OpenAPI objects, so a route that
|
|
5
|
+
* declares `body: userSchema` documents exactly the payload it parses.
|
|
6
|
+
*/
|
|
7
|
+
import type { OpenAPIRequestBody, OpenAPIResponses } from "../openApiTypes/openApiTypes.core.js";
|
|
8
|
+
import type { RouteConversionOptions, RouteOpenAPIMetadata } from "./routeMetadata.type.js";
|
|
9
|
+
/** A default description for a response key: `404` → "Not Found". */
|
|
10
|
+
export declare function describeResponseKey(key: string): string;
|
|
11
|
+
/** Builds the Request Body Object from `requestBody` or `body`. */
|
|
12
|
+
export declare function buildOperationRequestBody(meta: RouteOpenAPIMetadata | undefined, context: string, options?: RouteConversionOptions): OpenAPIRequestBody | undefined;
|
|
13
|
+
/**
|
|
14
|
+
* Builds the `responses` object for an operation.
|
|
15
|
+
*
|
|
16
|
+
* Every documented response is carried through; an entry with a `schema` is
|
|
17
|
+
* expanded into a Response Object. A route that documents none gets a
|
|
18
|
+
* `default` "Undocumented response" (`responses` is required) and a warning
|
|
19
|
+
* through `options.onWarning`. No status is invented.
|
|
20
|
+
*/
|
|
21
|
+
export declare function buildOperationResponses(meta: RouteOpenAPIMetadata | undefined, context: string, options?: RouteConversionOptions): OpenAPIResponses;
|
|
22
|
+
//# sourceMappingURL=routeContent.core.d.ts.map
|