@kizunajs/openapi 2.0.0-beta.10 → 2.0.0-beta.12
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/dist/index.cjs +157 -67
- package/dist/index.d.cts +181 -170
- package/dist/index.d.mts +180 -169
- package/dist/index.mjs +152 -68
- package/package.json +4 -4
package/dist/index.d.mts
CHANGED
|
@@ -1,67 +1,10 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import
|
|
2
|
+
import * as _$kizunajs_plugin0 from "kizunajs/plugin";
|
|
3
|
+
import { RoutePath } from "kizunajs/plugin";
|
|
3
4
|
import { RouteDefinition } from "kizunajs/generator";
|
|
4
5
|
import * as _$kizunajs from "kizunajs";
|
|
5
|
-
import { ApiDefinition
|
|
6
|
+
import { ApiDefinition } from "kizunajs";
|
|
6
7
|
|
|
7
|
-
//#region src/docs-html.d.ts
|
|
8
|
-
/**
|
|
9
|
-
* The API reference UI rendered by the docs endpoint.
|
|
10
|
-
*/
|
|
11
|
-
type DocsProvider = 'scalar' | 'swagger';
|
|
12
|
-
interface DocsHtmlOptions {
|
|
13
|
-
/**
|
|
14
|
-
* URL the UI fetches the OpenAPI document from. Omit it and pass
|
|
15
|
-
* {@link DocsHtmlOptions.specContent} instead.
|
|
16
|
-
*/
|
|
17
|
-
specUrl?: string;
|
|
18
|
-
/**
|
|
19
|
-
* The document itself, embedded in the page rather than fetched.
|
|
20
|
-
*/
|
|
21
|
-
specContent?: unknown;
|
|
22
|
-
/**
|
|
23
|
-
* Which API reference UI to render.
|
|
24
|
-
*
|
|
25
|
-
* @default 'scalar'
|
|
26
|
-
*/
|
|
27
|
-
provider?: DocsProvider;
|
|
28
|
-
/**
|
|
29
|
-
* The page's `<title>`.
|
|
30
|
-
*
|
|
31
|
-
* @default 'API Reference'
|
|
32
|
-
*/
|
|
33
|
-
pageTitle?: string;
|
|
34
|
-
/**
|
|
35
|
-
* Where to load the UI's assets from. Point this at a self-hosted copy for
|
|
36
|
-
* air-gapped deployments or a strict CSP.
|
|
37
|
-
*
|
|
38
|
-
* For `'scalar'` this is the script URL. For `'swagger'` it is the
|
|
39
|
-
* directory holding `swagger-ui.css` and `swagger-ui-bundle.js`.
|
|
40
|
-
*
|
|
41
|
-
* @default 'https://cdn.jsdelivr.net/npm/@scalar/api-reference@1' | 'https://cdn.jsdelivr.net/npm/swagger-ui-dist@5'
|
|
42
|
-
*/
|
|
43
|
-
cdnUrl?: string;
|
|
44
|
-
/**
|
|
45
|
-
* Merged into `Scalar.createApiReference` or `SwaggerUIBundle`. See the
|
|
46
|
-
* provider's own documentation for the available keys.
|
|
47
|
-
*/
|
|
48
|
-
configuration?: Record<string, unknown>;
|
|
49
|
-
}
|
|
50
|
-
/**
|
|
51
|
-
* Render a self-contained page that loads an API reference UI over your OpenAPI
|
|
52
|
-
* document. `openApiPlugin` calls this, so reach for it directly only when
|
|
53
|
-
* kizuna has no adapter for your framework.
|
|
54
|
-
*
|
|
55
|
-
* @example
|
|
56
|
-
* ```ts
|
|
57
|
-
* const html = renderDocsHtml({
|
|
58
|
-
* specUrl: '/openapi.json',
|
|
59
|
-
* pageTitle: 'My API',
|
|
60
|
-
* });
|
|
61
|
-
* ```
|
|
62
|
-
*/
|
|
63
|
-
declare const renderDocsHtml: (options: DocsHtmlOptions) => string;
|
|
64
|
-
//#endregion
|
|
65
8
|
//#region src/types.d.ts
|
|
66
9
|
/**
|
|
67
10
|
* The OpenAPI Specification version declared in the document's `openapi` field.
|
|
@@ -145,126 +88,216 @@ interface OpenApiDocument {
|
|
|
145
88
|
schemas?: Record<string, unknown>;
|
|
146
89
|
};
|
|
147
90
|
}
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
91
|
+
declare const GenerateOpenApiOptionsSchema: z.ZodObject<{
|
|
92
|
+
openApiVersion: z.ZodOptional<z.ZodLiteral<"3.1.0">>;
|
|
93
|
+
info: z.ZodObject<{
|
|
94
|
+
title: z.ZodString;
|
|
95
|
+
version: z.ZodString;
|
|
96
|
+
description: z.ZodOptional<z.ZodString>;
|
|
97
|
+
}, z.core.$strip>;
|
|
98
|
+
servers: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
99
|
+
url: z.ZodString;
|
|
100
|
+
description: z.ZodOptional<z.ZodString>;
|
|
101
|
+
}, z.core.$strip>>>;
|
|
102
|
+
externalDocs: z.ZodOptional<z.ZodObject<{
|
|
103
|
+
url: z.ZodString;
|
|
104
|
+
description: z.ZodOptional<z.ZodString>;
|
|
105
|
+
}, z.core.$strip>>;
|
|
106
|
+
setOperationId: z.ZodOptional<z.ZodUnion<readonly [z.ZodBoolean, z.ZodLiteral<"concatenated-path">]>>;
|
|
107
|
+
includeHidden: z.ZodOptional<z.ZodBoolean>;
|
|
108
|
+
operationMapper: z.ZodOptional<z.ZodCustom<(operation: OpenApiOperation, route: RouteDefinition, operationId: string) => OpenApiOperation, (operation: OpenApiOperation, route: RouteDefinition, operationId: string) => OpenApiOperation>>;
|
|
109
|
+
derivedHead: z.ZodOptional<z.ZodBoolean>;
|
|
110
|
+
}, z.core.$strip>;
|
|
111
|
+
type GenerateOpenApiOptions = z.output<typeof GenerateOpenApiOptionsSchema>;
|
|
167
112
|
interface OpenApiRenderer {
|
|
168
113
|
(format: 'json'): OpenApiDocument;
|
|
169
114
|
(format: 'yaml'): string;
|
|
170
115
|
}
|
|
171
116
|
//#endregion
|
|
172
117
|
//#region src/plugin.d.ts
|
|
173
|
-
declare const OPENAPI_PLUGIN_SLUG = "openApi";
|
|
174
118
|
type JsonDocumentPath = `${RoutePath}.json`;
|
|
175
119
|
type YamlDocumentPath = `${RoutePath}.yaml`;
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
120
|
+
declare const OpenApiPluginOptionsSchema: z.ZodObject<{
|
|
121
|
+
openApiVersion: z.ZodOptional<z.ZodLiteral<"3.1.0">>;
|
|
122
|
+
info: z.ZodObject<{
|
|
123
|
+
title: z.ZodString;
|
|
124
|
+
version: z.ZodString;
|
|
125
|
+
description: z.ZodOptional<z.ZodString>;
|
|
126
|
+
}, z.core.$strip>;
|
|
127
|
+
servers: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
128
|
+
url: z.ZodString;
|
|
129
|
+
description: z.ZodOptional<z.ZodString>;
|
|
130
|
+
}, z.core.$strip>>>;
|
|
131
|
+
externalDocs: z.ZodOptional<z.ZodObject<{
|
|
132
|
+
url: z.ZodString;
|
|
133
|
+
description: z.ZodOptional<z.ZodString>;
|
|
134
|
+
}, z.core.$strip>>;
|
|
135
|
+
setOperationId: z.ZodOptional<z.ZodUnion<readonly [z.ZodBoolean, z.ZodLiteral<"concatenated-path">]>>;
|
|
136
|
+
includeHidden: z.ZodOptional<z.ZodBoolean>;
|
|
137
|
+
operationMapper: z.ZodOptional<z.ZodCustom<(operation: OpenApiOperation, route: _$kizunajs.RouteDefinition, operationId: string) => OpenApiOperation, (operation: OpenApiOperation, route: _$kizunajs.RouteDefinition, operationId: string) => OpenApiOperation>>;
|
|
138
|
+
derivedHead: z.ZodOptional<z.ZodBoolean>;
|
|
139
|
+
output: z.ZodOptional<z.ZodString>;
|
|
140
|
+
docsPath: z.ZodOptional<z.ZodCustom<`/${string}`, `/${string}`>>;
|
|
141
|
+
jsonPath: z.ZodOptional<z.ZodCustom<`/${string}.json`, `/${string}.json`>>;
|
|
142
|
+
yamlPath: z.ZodOptional<z.ZodCustom<`/${string}.yaml`, `/${string}.yaml`>>;
|
|
143
|
+
provider: z.ZodOptional<z.ZodEnum<{
|
|
144
|
+
scalar: "scalar";
|
|
145
|
+
swagger: "swagger";
|
|
146
|
+
}>>;
|
|
147
|
+
cdnUrl: z.ZodOptional<z.ZodString>;
|
|
148
|
+
pageTitle: z.ZodOptional<z.ZodString>;
|
|
149
|
+
configuration: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
150
|
+
}, z.core.$strip>;
|
|
151
|
+
type OpenApiPluginProps = z.output<typeof OpenApiPluginOptionsSchema>;
|
|
152
|
+
/**
|
|
153
|
+
* Serve an API reference UI for the OpenAPI document, and the document itself
|
|
154
|
+
* if you publish it.
|
|
155
|
+
*
|
|
156
|
+
* The routes are public. Gate them with your framework's own middleware if that
|
|
157
|
+
* is not what you want.
|
|
158
|
+
*
|
|
159
|
+
* @example
|
|
160
|
+
* ```ts
|
|
161
|
+
* export default defineConfig({
|
|
162
|
+
* routes,
|
|
163
|
+
* plugins: [
|
|
164
|
+
* openApiPlugin({
|
|
165
|
+
* info: {
|
|
166
|
+
* title: 'My API',
|
|
167
|
+
* version: '1.0.0',
|
|
168
|
+
* },
|
|
169
|
+
* docsPath: '/docs',
|
|
170
|
+
* }),
|
|
171
|
+
* ],
|
|
172
|
+
* });
|
|
173
|
+
* ```
|
|
174
|
+
*/
|
|
175
|
+
declare const openApiPlugin: {
|
|
176
|
+
<const Slug extends string>(options: {
|
|
177
|
+
info: {
|
|
178
|
+
title: string;
|
|
179
|
+
version: string;
|
|
180
|
+
description?: string | undefined;
|
|
181
|
+
};
|
|
182
|
+
openApiVersion?: "3.1.0" | undefined;
|
|
183
|
+
servers?: {
|
|
184
|
+
url: string;
|
|
185
|
+
description?: string | undefined;
|
|
186
|
+
}[] | undefined;
|
|
187
|
+
externalDocs?: {
|
|
188
|
+
url: string;
|
|
189
|
+
description?: string | undefined;
|
|
190
|
+
} | undefined;
|
|
191
|
+
setOperationId?: boolean | "concatenated-path" | undefined;
|
|
192
|
+
includeHidden?: boolean | undefined;
|
|
193
|
+
operationMapper?: ((operation: OpenApiOperation, route: _$kizunajs.RouteDefinition, operationId: string) => OpenApiOperation) | undefined;
|
|
194
|
+
derivedHead?: boolean | undefined;
|
|
195
|
+
output?: string | undefined;
|
|
196
|
+
docsPath?: `/${string}` | undefined;
|
|
197
|
+
jsonPath?: `/${string}.json` | undefined;
|
|
198
|
+
yamlPath?: `/${string}.yaml` | undefined;
|
|
199
|
+
provider?: "scalar" | "swagger" | undefined;
|
|
200
|
+
cdnUrl?: string | undefined;
|
|
201
|
+
pageTitle?: string | undefined;
|
|
202
|
+
configuration?: Record<string, unknown> | undefined;
|
|
203
|
+
} & {
|
|
204
|
+
basePath?: never;
|
|
205
|
+
} & _$kizunajs_plugin0.SlugOption<Slug>): _$kizunajs.PluginDeclaration<Slug, {
|
|
206
|
+
routes: _$kizunajs.PluginRoutes;
|
|
207
|
+
generators: _$kizunajs.GeneratedFile[];
|
|
208
|
+
}>;
|
|
209
|
+
(options: {
|
|
210
|
+
info: {
|
|
211
|
+
title: string;
|
|
212
|
+
version: string;
|
|
213
|
+
description?: string | undefined;
|
|
214
|
+
};
|
|
215
|
+
openApiVersion?: "3.1.0" | undefined;
|
|
216
|
+
servers?: {
|
|
217
|
+
url: string;
|
|
218
|
+
description?: string | undefined;
|
|
219
|
+
}[] | undefined;
|
|
220
|
+
externalDocs?: {
|
|
221
|
+
url: string;
|
|
222
|
+
description?: string | undefined;
|
|
223
|
+
} | undefined;
|
|
224
|
+
setOperationId?: boolean | "concatenated-path" | undefined;
|
|
225
|
+
includeHidden?: boolean | undefined;
|
|
226
|
+
operationMapper?: ((operation: OpenApiOperation, route: _$kizunajs.RouteDefinition, operationId: string) => OpenApiOperation) | undefined;
|
|
227
|
+
derivedHead?: boolean | undefined;
|
|
228
|
+
output?: string | undefined;
|
|
229
|
+
docsPath?: `/${string}` | undefined;
|
|
230
|
+
jsonPath?: `/${string}.json` | undefined;
|
|
231
|
+
yamlPath?: `/${string}.yaml` | undefined;
|
|
232
|
+
provider?: "scalar" | "swagger" | undefined;
|
|
233
|
+
cdnUrl?: string | undefined;
|
|
234
|
+
pageTitle?: string | undefined;
|
|
235
|
+
configuration?: Record<string, unknown> | undefined;
|
|
236
|
+
} & {
|
|
237
|
+
basePath?: never;
|
|
238
|
+
}): _$kizunajs.PluginDeclaration<"openApi", {
|
|
239
|
+
routes: _$kizunajs.PluginRoutes;
|
|
240
|
+
generators: _$kizunajs.GeneratedFile[];
|
|
241
|
+
}>;
|
|
242
|
+
};
|
|
243
|
+
//#endregion
|
|
244
|
+
//#region src/docs-html.d.ts
|
|
245
|
+
/**
|
|
246
|
+
* The API reference UI rendered by the docs endpoint.
|
|
247
|
+
*/
|
|
248
|
+
type DocsProvider = 'scalar' | 'swagger';
|
|
249
|
+
interface DocsHtmlOptions {
|
|
187
250
|
/**
|
|
188
|
-
*
|
|
189
|
-
*
|
|
251
|
+
* URL the UI fetches the OpenAPI document from. Omit it and pass
|
|
252
|
+
* {@link DocsHtmlOptions.specContent} instead.
|
|
190
253
|
*/
|
|
191
|
-
|
|
254
|
+
specUrl?: string;
|
|
192
255
|
/**
|
|
193
|
-
*
|
|
256
|
+
* The document itself, embedded in the page rather than fetched.
|
|
194
257
|
*/
|
|
195
|
-
|
|
258
|
+
specContent?: unknown;
|
|
196
259
|
/**
|
|
197
260
|
* Which API reference UI to render.
|
|
198
261
|
*
|
|
199
262
|
* @default 'scalar'
|
|
200
263
|
*/
|
|
201
264
|
provider?: DocsProvider;
|
|
202
|
-
/**
|
|
203
|
-
* Where to load the UI's assets from, for a self-hosted copy. The script
|
|
204
|
-
* URL for `'scalar'`; the directory holding `swagger-ui.css` and
|
|
205
|
-
* `swagger-ui-bundle.js` for `'swagger'`.
|
|
206
|
-
*/
|
|
207
|
-
cdnUrl?: string;
|
|
208
265
|
/**
|
|
209
266
|
* The page's `<title>`.
|
|
210
267
|
*
|
|
211
|
-
* @default
|
|
268
|
+
* @default 'API Reference'
|
|
212
269
|
*/
|
|
213
270
|
pageTitle?: string;
|
|
214
271
|
/**
|
|
215
|
-
*
|
|
272
|
+
* Where to load the UI's assets from. Point this at a self-hosted copy for
|
|
273
|
+
* air-gapped deployments or a strict CSP.
|
|
274
|
+
*
|
|
275
|
+
* For `'scalar'` this is the script URL. For `'swagger'` it is the
|
|
276
|
+
* directory holding `swagger-ui.css` and `swagger-ui-bundle.js`.
|
|
277
|
+
*
|
|
278
|
+
* @default 'https://cdn.jsdelivr.net/npm/@scalar/api-reference@1' | 'https://cdn.jsdelivr.net/npm/swagger-ui-dist@5'
|
|
279
|
+
*/
|
|
280
|
+
cdnUrl?: string;
|
|
281
|
+
/**
|
|
282
|
+
* Merged into `Scalar.createApiReference` or `SwaggerUIBundle`. See the
|
|
283
|
+
* provider's own documentation for the available keys.
|
|
216
284
|
*/
|
|
217
285
|
configuration?: Record<string, unknown>;
|
|
218
286
|
}
|
|
219
287
|
/**
|
|
220
|
-
*
|
|
221
|
-
*
|
|
222
|
-
*
|
|
223
|
-
* The routes are public. Gate them with your framework's own middleware if that
|
|
224
|
-
* is not what you want.
|
|
288
|
+
* Render a self-contained page that loads an API reference UI over your OpenAPI
|
|
289
|
+
* document. `openApiPlugin` calls this, so reach for it directly only when
|
|
290
|
+
* kizuna has no adapter for your framework.
|
|
225
291
|
*
|
|
226
292
|
* @example
|
|
227
293
|
* ```ts
|
|
228
|
-
*
|
|
229
|
-
*
|
|
230
|
-
*
|
|
231
|
-
* openApiPlugin({
|
|
232
|
-
* info: {
|
|
233
|
-
* title: 'My API',
|
|
234
|
-
* version: '1.0.0',
|
|
235
|
-
* },
|
|
236
|
-
* }),
|
|
237
|
-
* ],
|
|
294
|
+
* const html = renderDocsHtml({
|
|
295
|
+
* specUrl: '/openapi.json',
|
|
296
|
+
* pageTitle: 'My API',
|
|
238
297
|
* });
|
|
239
298
|
* ```
|
|
240
299
|
*/
|
|
241
|
-
declare const
|
|
242
|
-
readonly yaml?: {
|
|
243
|
-
readonly method: "GET";
|
|
244
|
-
readonly path: `/${string}.yaml`;
|
|
245
|
-
readonly summary: "OpenAPI document, as YAML";
|
|
246
|
-
readonly responses: {
|
|
247
|
-
readonly 200: z.ZodString;
|
|
248
|
-
};
|
|
249
|
-
} | undefined;
|
|
250
|
-
readonly json?: {
|
|
251
|
-
readonly method: "GET";
|
|
252
|
-
readonly path: `/${string}.json`;
|
|
253
|
-
readonly summary: "OpenAPI document";
|
|
254
|
-
readonly responses: {
|
|
255
|
-
readonly 200: z.ZodUnknown;
|
|
256
|
-
};
|
|
257
|
-
} | undefined;
|
|
258
|
-
readonly page?: {
|
|
259
|
-
readonly method: "GET";
|
|
260
|
-
readonly path: `/${string}`;
|
|
261
|
-
readonly summary: "API reference";
|
|
262
|
-
readonly responses: {
|
|
263
|
-
readonly 200: z.ZodString;
|
|
264
|
-
};
|
|
265
|
-
} | undefined;
|
|
266
|
-
}, OpenApiPluginProps<string>, undefined, string, unknown>;
|
|
267
|
-
declare function openApiPlugin<const Slug extends string = typeof OPENAPI_PLUGIN_SLUG>(props: OpenApiPluginProps<Slug>): WithSlug<ReturnType<typeof declare>, Slug>;
|
|
300
|
+
declare const renderDocsHtml: (options: DocsHtmlOptions) => string;
|
|
268
301
|
//#endregion
|
|
269
302
|
//#region src/generator.d.ts
|
|
270
303
|
/**
|
|
@@ -281,26 +314,4 @@ declare function renderOpenApi(api: ApiDefinition, options: GenerateOpenApiOptio
|
|
|
281
314
|
*/
|
|
282
315
|
declare function generateOpenApi(api: ApiDefinition, overrides?: Partial<GenerateOpenApiOptions>): OpenApiRenderer;
|
|
283
316
|
//#endregion
|
|
284
|
-
|
|
285
|
-
/**
|
|
286
|
-
* Where the generated OpenAPI document is written. The format follows the
|
|
287
|
-
* output extension: `.json` renders JSON, anything else renders YAML.
|
|
288
|
-
*/
|
|
289
|
-
interface OpenApiDocumentOptions extends Partial<GenerateOpenApiOptions> {
|
|
290
|
-
/**
|
|
291
|
-
* Path the generated document is written to.
|
|
292
|
-
*/
|
|
293
|
-
output: string;
|
|
294
|
-
}
|
|
295
|
-
/**
|
|
296
|
-
* An OpenAPI document target for `kizuna.config.ts`.
|
|
297
|
-
*
|
|
298
|
-
* @example
|
|
299
|
-
* openApiDocument({ output: './openapi.yaml' });
|
|
300
|
-
*/
|
|
301
|
-
declare const openApiDocument: ({
|
|
302
|
-
output,
|
|
303
|
-
...overrides
|
|
304
|
-
}: OpenApiDocumentOptions) => ClientTarget;
|
|
305
|
-
//#endregion
|
|
306
|
-
export { type DocsHtmlOptions, type DocsProvider, type GenerateOpenApiOptions, type JsonDocumentPath, type OpenApiDocument, type OpenApiDocumentOptions, type OpenApiInfo, type OpenApiOperation, type OpenApiParameter, type OpenApiPluginProps, type OpenApiRenderer, type OpenApiResponseObject, type OpenApiServer, type OpenApiTag, type OpenApiVersion, type YamlDocumentPath, generateOpenApi, openApiDocument, openApiPlugin, renderDocsHtml, renderOpenApi };
|
|
317
|
+
export { type DocsHtmlOptions, type DocsProvider, type GenerateOpenApiOptions, type JsonDocumentPath, type OpenApiDocument, type OpenApiInfo, type OpenApiOperation, type OpenApiParameter, type OpenApiPluginProps, type OpenApiRenderer, type OpenApiResponseObject, type OpenApiServer, type OpenApiTag, type OpenApiVersion, type YamlDocumentPath, generateOpenApi, openApiPlugin, renderDocsHtml, renderOpenApi };
|
package/dist/index.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import {
|
|
2
|
+
import { RoutePathSchema, definePlugin, route } from "kizunajs/plugin";
|
|
3
|
+
import { cacheHeaders, defineGenerator, deprecationHeaders, globalRegistrySchemas, isBinarySchema, isFileSchema, isNamedStream, isStreamResponse, isVoidSchema, parsePath, readDef, readDiscriminatedUnion, readDiscriminatorLiteral, readMeta, readMetaId, readObjectShape, resolveResponseBody, resolveResponseCache, resolveResponseContentType, resolveResponseEtag, resolveResponseHeaders, streamContentType, streamMode, walkApi } from "kizunajs/generator";
|
|
3
4
|
import { contractOf, rawResponse } from "kizunajs/adapter";
|
|
4
5
|
import { stringify } from "yaml";
|
|
5
|
-
import { cacheHeaders, createGenerator, deprecationHeaders, globalRegistrySchemas, isBinarySchema, isFileSchema, isNamedStream, isStreamResponse, isVoidSchema, parsePath, readDef, readDiscriminatedUnion, readDiscriminatorLiteral, readMeta, readMetaId, readObjectShape, resolveResponseBody, resolveResponseCache, resolveResponseContentType, resolveResponseEtag, resolveResponseHeaders, streamContentType, streamMode } from "kizunajs/generator";
|
|
6
6
|
import { getStatusText } from "kizunajs";
|
|
7
7
|
//#region src/generator.ts
|
|
8
8
|
const streamJsonSchema = (response, toJsonSchema) => {
|
|
@@ -161,10 +161,11 @@ const deriveHeadOperation = (getOperation) => {
|
|
|
161
161
|
for (const response of Object.values(operation.responses)) delete response.content;
|
|
162
162
|
return operation;
|
|
163
163
|
};
|
|
164
|
-
const
|
|
164
|
+
const openApiWalk = (options, api) => {
|
|
165
165
|
const paths = {};
|
|
166
166
|
return {
|
|
167
|
-
processRoute({ routeKey, route, routeTags, deprecated }) {
|
|
167
|
+
processRoute({ routeKey, route, routeTags, deprecated, hidden }) {
|
|
168
|
+
if (hidden && options.includeHidden !== true) return;
|
|
168
169
|
const openApiPath = convertPath(route.path);
|
|
169
170
|
const method = route.method.toLowerCase();
|
|
170
171
|
let operation = {
|
|
@@ -378,7 +379,7 @@ const openApiGenerator = createGenerator((options, api) => {
|
|
|
378
379
|
return renderer;
|
|
379
380
|
}
|
|
380
381
|
};
|
|
381
|
-
}
|
|
382
|
+
};
|
|
382
383
|
/**
|
|
383
384
|
* The permissions a route requires, as `x-kizuna-requires`: what is acted on,
|
|
384
385
|
* mapped to the verbs the caller has to hold.
|
|
@@ -458,17 +459,17 @@ const tagsFromApi = (api) => {
|
|
|
458
459
|
* So a build step does not restate the options and drift from what is served.
|
|
459
460
|
*/
|
|
460
461
|
const optionsFromInstalledPlugin = (api) => {
|
|
461
|
-
for (const
|
|
462
|
+
for (const plugin of Object.values(api.plugins ?? {})) if (plugin.definedSlug === "openApi") return plugin.options;
|
|
462
463
|
throw new Error("generateOpenApi reads its options from the config. Name `openApiPlugin` under `plugins` with the API's `info`.");
|
|
463
464
|
};
|
|
464
465
|
/**
|
|
465
466
|
* Render from options held directly, for the plugin's own routes.
|
|
466
467
|
*/
|
|
467
468
|
function renderOpenApi(api, options) {
|
|
468
|
-
const renderer =
|
|
469
|
+
const renderer = walkApi(api, openApiWalk({
|
|
469
470
|
...options,
|
|
470
471
|
tagLookup: buildTagLookup(api)
|
|
471
|
-
});
|
|
472
|
+
}, api));
|
|
472
473
|
const tags = tagsFromApi(api);
|
|
473
474
|
if (tags.length > 0) renderer("json").tags = tags;
|
|
474
475
|
return renderer;
|
|
@@ -560,22 +561,6 @@ const renderDocsHtml = (options) => {
|
|
|
560
561
|
});
|
|
561
562
|
};
|
|
562
563
|
//#endregion
|
|
563
|
-
//#region src/document-target.ts
|
|
564
|
-
/**
|
|
565
|
-
* An OpenAPI document target for `kizuna.config.ts`.
|
|
566
|
-
*
|
|
567
|
-
* @example
|
|
568
|
-
* openApiDocument({ output: './openapi.yaml' });
|
|
569
|
-
*/
|
|
570
|
-
const openApiDocument = ({ output, ...overrides }) => ({
|
|
571
|
-
kind: "openapi",
|
|
572
|
-
output,
|
|
573
|
-
generate: (contract) => {
|
|
574
|
-
const render = generateOpenApi(contract, overrides);
|
|
575
|
-
return output.endsWith(".json") ? `${JSON.stringify(render("json"), null, 4)}\n` : render("yaml");
|
|
576
|
-
}
|
|
577
|
-
});
|
|
578
|
-
//#endregion
|
|
579
564
|
//#region src/server.ts
|
|
580
565
|
const HTML = "text/html; charset=utf-8";
|
|
581
566
|
const JSON_TYPE = "application/json";
|
|
@@ -585,23 +570,43 @@ const sent = (body, contentType) => new Response(body, {
|
|
|
585
570
|
headers: { "content-type": contentType }
|
|
586
571
|
});
|
|
587
572
|
/**
|
|
588
|
-
*
|
|
589
|
-
*
|
|
573
|
+
* The routes `openApiPlugin` serves: the reference UI, and the document itself
|
|
574
|
+
* where the options publish it. The document is rendered on the first request,
|
|
575
|
+
* once the api it describes has assembled.
|
|
590
576
|
*/
|
|
591
|
-
const
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
577
|
+
const openApiRoutes = (props, api) => {
|
|
578
|
+
let renderer;
|
|
579
|
+
const spec = ((format) => {
|
|
580
|
+
renderer ??= renderOpenApi(contractOf(api), props);
|
|
581
|
+
return renderer(format);
|
|
582
|
+
});
|
|
583
|
+
const routes = {};
|
|
584
|
+
if (props.docsPath !== void 0) routes.page = route({
|
|
585
|
+
method: "GET",
|
|
586
|
+
path: props.docsPath,
|
|
587
|
+
summary: "API reference",
|
|
588
|
+
responses: { 200: z.string() }
|
|
589
|
+
}).handler(() => rawResponse(sent(renderDocsHtml({
|
|
590
|
+
specUrl: props.jsonPath,
|
|
591
|
+
specContent: props.jsonPath === void 0 ? spec("json") : void 0,
|
|
592
|
+
provider: props.provider,
|
|
593
|
+
pageTitle: props.pageTitle ?? spec("json").info.title,
|
|
594
|
+
cdnUrl: props.cdnUrl,
|
|
595
|
+
configuration: props.configuration
|
|
596
|
+
}), HTML)));
|
|
597
|
+
if (props.jsonPath !== void 0) routes.json = route({
|
|
598
|
+
method: "GET",
|
|
599
|
+
path: props.jsonPath,
|
|
600
|
+
summary: "OpenAPI document",
|
|
601
|
+
responses: { 200: z.unknown() }
|
|
602
|
+
}).handler(() => rawResponse(sent(JSON.stringify(spec("json")), JSON_TYPE)));
|
|
603
|
+
if (props.yamlPath !== void 0) routes.yaml = route({
|
|
604
|
+
method: "GET",
|
|
605
|
+
path: props.yamlPath,
|
|
606
|
+
summary: "OpenAPI document, as YAML",
|
|
607
|
+
responses: { 200: z.string() }
|
|
608
|
+
}).handler(() => rawResponse(sent(spec("yaml"), YAML)));
|
|
609
|
+
return routes;
|
|
605
610
|
};
|
|
606
611
|
/**
|
|
607
612
|
* Serve an API reference UI for the OpenAPI document, and the document itself
|
|
@@ -620,38 +625,117 @@ const openApiServe = (props, api) => {
|
|
|
620
625
|
* title: 'My API',
|
|
621
626
|
* version: '1.0.0',
|
|
622
627
|
* },
|
|
628
|
+
* docsPath: '/docs',
|
|
623
629
|
* }),
|
|
624
630
|
* ],
|
|
625
631
|
* });
|
|
626
632
|
* ```
|
|
627
633
|
*/
|
|
628
|
-
const
|
|
629
|
-
slug,
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
634
|
+
const openApiPlugin = definePlugin({
|
|
635
|
+
slug: "openApi",
|
|
636
|
+
options: z.object({
|
|
637
|
+
/**
|
|
638
|
+
* The OpenAPI Specification version to declare in the document's `openapi` field.
|
|
639
|
+
*
|
|
640
|
+
* Defaults to `'3.1.0'`.
|
|
641
|
+
*/
|
|
642
|
+
openApiVersion: z.literal("3.1.0").optional(),
|
|
643
|
+
info: z.object({
|
|
644
|
+
title: z.string(),
|
|
645
|
+
version: z.string(),
|
|
646
|
+
description: z.string().optional()
|
|
647
|
+
}),
|
|
648
|
+
servers: z.array(z.object({
|
|
649
|
+
url: z.string(),
|
|
650
|
+
description: z.string().optional()
|
|
651
|
+
})).optional(),
|
|
652
|
+
externalDocs: z.object({
|
|
653
|
+
url: z.string(),
|
|
654
|
+
description: z.string().optional()
|
|
655
|
+
}).optional(),
|
|
656
|
+
setOperationId: z.union([z.boolean(), z.literal("concatenated-path")]).optional(),
|
|
657
|
+
/**
|
|
658
|
+
* Document `hidden` routes too, for a document your own team reads.
|
|
659
|
+
*
|
|
660
|
+
* @default false
|
|
661
|
+
*/
|
|
662
|
+
includeHidden: z.boolean().optional(),
|
|
663
|
+
operationMapper: z.custom((value) => typeof value === "function", { error: "must be a function" }).optional(),
|
|
664
|
+
/**
|
|
665
|
+
* Document the derived `head` operation on every `GET` path without a declared one.
|
|
666
|
+
*
|
|
667
|
+
* @default false
|
|
668
|
+
*/
|
|
669
|
+
derivedHead: z.boolean().optional()
|
|
670
|
+
}).extend({
|
|
671
|
+
/**
|
|
672
|
+
* Where `kizuna generate` writes the document. `.json` renders JSON,
|
|
673
|
+
* anything else YAML.
|
|
674
|
+
*
|
|
675
|
+
* @example
|
|
676
|
+
* output: './openapi.yaml',
|
|
677
|
+
*/
|
|
678
|
+
output: z.string().optional(),
|
|
679
|
+
/**
|
|
680
|
+
* Where the reference UI is served.
|
|
681
|
+
*/
|
|
682
|
+
docsPath: RoutePathSchema.optional(),
|
|
683
|
+
/**
|
|
684
|
+
* Where the document is served. The UI embeds it, so this is only for
|
|
685
|
+
* publishing the file.
|
|
686
|
+
*/
|
|
687
|
+
jsonPath: z.custom((value) => typeof value === "string" && value.startsWith("/") && value.endsWith(".json"), { error: "must start with / and end in .json" }).optional(),
|
|
688
|
+
/**
|
|
689
|
+
* Where the document is served as YAML.
|
|
690
|
+
*/
|
|
691
|
+
yamlPath: z.custom((value) => typeof value === "string" && value.startsWith("/") && value.endsWith(".yaml"), { error: "must start with / and end in .yaml" }).optional(),
|
|
692
|
+
/**
|
|
693
|
+
* Which API reference UI to render.
|
|
694
|
+
*
|
|
695
|
+
* @default 'scalar'
|
|
696
|
+
*/
|
|
697
|
+
provider: z.enum(["scalar", "swagger"]).optional(),
|
|
698
|
+
/**
|
|
699
|
+
* Where to load the UI's assets from, for a self-hosted copy. The script
|
|
700
|
+
* URL for `'scalar'`; the directory holding `swagger-ui.css` and
|
|
701
|
+
* `swagger-ui-bundle.js` for `'swagger'`.
|
|
702
|
+
*/
|
|
703
|
+
cdnUrl: z.string().optional(),
|
|
704
|
+
/**
|
|
705
|
+
* The page's `<title>`.
|
|
706
|
+
*
|
|
707
|
+
* @default the document's `info.title`
|
|
708
|
+
*/
|
|
709
|
+
pageTitle: z.string().optional(),
|
|
710
|
+
/**
|
|
711
|
+
* Merged into `Scalar.createApiReference` or `SwaggerUIBundle`.
|
|
712
|
+
*/
|
|
713
|
+
configuration: z.record(z.string(), z.unknown()).optional()
|
|
714
|
+
}),
|
|
715
|
+
setup: ({ options, api }) => {
|
|
716
|
+
const { output, ...document } = options;
|
|
717
|
+
return {
|
|
718
|
+
routes: openApiRoutes(options, api),
|
|
719
|
+
generators: output === void 0 ? [] : [openApiDocumentGenerator({
|
|
720
|
+
output,
|
|
721
|
+
json: output.endsWith(".json"),
|
|
722
|
+
document
|
|
723
|
+
})]
|
|
724
|
+
};
|
|
725
|
+
}
|
|
726
|
+
});
|
|
727
|
+
/**
|
|
728
|
+
* Writes one document, in the format its `output` names.
|
|
729
|
+
*/
|
|
730
|
+
const openApiDocumentGenerator = defineGenerator({
|
|
731
|
+
options: z.object({
|
|
732
|
+
json: z.boolean(),
|
|
733
|
+
document: z.custom()
|
|
734
|
+
}),
|
|
735
|
+
generate: ({ options, api }) => ({ finalize: () => {
|
|
736
|
+
const render = renderOpenApi(api, options.document);
|
|
737
|
+
return options.json ? `${JSON.stringify(render("json"), null, 4)}\n` : render("yaml");
|
|
738
|
+
} })
|
|
652
739
|
});
|
|
653
|
-
function openApiPlugin(props) {
|
|
654
|
-
return declare(props.slug ?? "openApi", props);
|
|
655
|
-
}
|
|
656
740
|
//#endregion
|
|
657
|
-
export { generateOpenApi,
|
|
741
|
+
export { generateOpenApi, openApiPlugin, renderDocsHtml, renderOpenApi };
|