@elysiajs/openapi 1.4.14 → 1.4.16
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 +131 -101
- package/bun.lock +14 -12
- package/dist/cjs/gen/index.js +1410 -3702
- package/dist/cjs/index.d.ts +3 -3
- package/dist/cjs/index.js +1772 -3857
- package/dist/cjs/openapi.d.ts +11 -8
- package/dist/cjs/openapi.js +301 -101
- package/dist/cjs/scalar/index.js +18 -17
- package/dist/cjs/types.d.ts +11 -3
- package/dist/gen/index.d.ts +43 -1
- package/dist/gen/index.mjs +1403 -3704
- package/dist/index.d.ts +3 -3
- package/dist/index.mjs +1763 -3852
- package/dist/openapi.d.ts +11 -8
- package/dist/openapi.mjs +296 -97
- package/dist/scalar/index.mjs +18 -17
- package/dist/types.d.ts +11 -3
- package/package.json +12 -10
package/dist/cjs/openapi.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { type AnyElysia, type
|
|
1
|
+
import { type AnyElysia, type InputSchema } from 'elysia';
|
|
2
2
|
import type { OpenAPIV3 } from 'openapi-types';
|
|
3
|
-
import { TAnySchema
|
|
4
|
-
import type { AdditionalReferences, ElysiaOpenAPIConfig, MapJsonSchema } from './types';
|
|
3
|
+
import { TAnySchema } from '@sinclair/typebox';
|
|
4
|
+
import type { AdditionalReferences, ElysiaOpenAPIConfig, MapJsonSchema, OpenAPIVersion } from './types';
|
|
5
5
|
export declare const capitalize: (word: string) => string;
|
|
6
6
|
/**
|
|
7
7
|
* Get all possible paths of a path with optional parameters
|
|
@@ -10,24 +10,27 @@ export declare const capitalize: (word: string) => string;
|
|
|
10
10
|
*/
|
|
11
11
|
export declare const getPossiblePath: (path: string) => string[];
|
|
12
12
|
export declare const getLoosePath: (path: string) => string;
|
|
13
|
-
export declare const unwrapSchema: (schema: InputSchema["body"], mapJsonSchema?: MapJsonSchema, io?: "input" | "output") => OpenAPIV3.SchemaObject | undefined;
|
|
13
|
+
export declare const unwrapSchema: (schema: InputSchema["body"], mapJsonSchema?: MapJsonSchema, io?: "input" | "output", openapiVersion?: OpenAPIVersion) => OpenAPIV3.SchemaObject | undefined;
|
|
14
14
|
/**
|
|
15
15
|
* Convert TypeBox enum-like Union schemas to OpenAPI enum schemas
|
|
16
16
|
*
|
|
17
17
|
* Otherwise, return the schema as is
|
|
18
18
|
*/
|
|
19
19
|
export declare const enumToOpenApi: <T extends TAnySchema | OpenAPIV3.SchemaObject | OpenAPIV3.ReferenceObject | undefined>(_schema: T) => T;
|
|
20
|
+
export declare const nullToOpenApi: <T>(schema: T, openapiVersion: OpenAPIVersion) => T;
|
|
20
21
|
/**
|
|
21
|
-
* Converts Elysia routes to OpenAPI
|
|
22
|
+
* Converts Elysia routes to OpenAPI paths schema
|
|
22
23
|
* @param routes Array of Elysia route objects
|
|
23
24
|
* @returns OpenAPI paths object
|
|
24
25
|
*/
|
|
25
|
-
export declare function toOpenAPISchema(app: AnyElysia, exclude?: ElysiaOpenAPIConfig['exclude'], references?: AdditionalReferences, vendors?: MapJsonSchema): {
|
|
26
|
+
export declare function toOpenAPISchema(app: AnyElysia, exclude?: ElysiaOpenAPIConfig['exclude'], references?: AdditionalReferences, vendors?: MapJsonSchema, openapiVersion?: OpenAPIVersion): {
|
|
26
27
|
components: {
|
|
27
28
|
schemas: any;
|
|
28
29
|
};
|
|
29
30
|
paths: OpenAPIV3.PathsObject<{}, {}>;
|
|
30
31
|
};
|
|
31
|
-
|
|
32
|
-
|
|
32
|
+
type ResponseHeaderSchemas = Record<string, Exclude<InputSchema['headers'], undefined>>;
|
|
33
|
+
export declare const withHeaders: <S extends Exclude<InputSchema["body"], string | undefined>, H extends ResponseHeaderSchemas>(schema: S, headers: H) => S & {
|
|
34
|
+
headers: H;
|
|
33
35
|
};
|
|
36
|
+
export {};
|
package/dist/cjs/openapi.js
CHANGED
|
@@ -24,21 +24,16 @@ __export(openapi_exports, {
|
|
|
24
24
|
enumToOpenApi: () => enumToOpenApi,
|
|
25
25
|
getLoosePath: () => getLoosePath,
|
|
26
26
|
getPossiblePath: () => getPossiblePath,
|
|
27
|
+
nullToOpenApi: () => nullToOpenApi,
|
|
27
28
|
toOpenAPISchema: () => toOpenAPISchema,
|
|
28
29
|
unwrapSchema: () => unwrapSchema,
|
|
29
30
|
withHeaders: () => withHeaders
|
|
30
31
|
});
|
|
31
32
|
module.exports = __toCommonJS(openapi_exports);
|
|
32
33
|
var import_elysia = require("elysia");
|
|
33
|
-
|
|
34
|
-
// node_modules/@sinclair/typebox/build/esm/type/symbols/symbols.mjs
|
|
35
|
-
var Kind = /* @__PURE__ */ Symbol.for("TypeBox.Kind");
|
|
36
|
-
|
|
37
|
-
// src/openapi.ts
|
|
34
|
+
var import_typebox = require("@sinclair/typebox");
|
|
38
35
|
var capitalize = (word) => word.charAt(0).toUpperCase() + word.slice(1);
|
|
39
|
-
var toRef = (name) => import_elysia.t.Ref(
|
|
40
|
-
name.startsWith("#/") ? name : `#/components/schemas/${name}`
|
|
41
|
-
);
|
|
36
|
+
var toRef = (name) => import_elysia.t.Ref(name.startsWith("#/") ? name : `#/components/schemas/${name}`);
|
|
42
37
|
var toOperationId = (method, paths) => {
|
|
43
38
|
let operationId = method.toLowerCase();
|
|
44
39
|
if (!paths || paths === "/") return operationId + "Index";
|
|
@@ -59,7 +54,7 @@ var getPossiblePath = (path) => {
|
|
|
59
54
|
}
|
|
60
55
|
return paths;
|
|
61
56
|
};
|
|
62
|
-
var isValidSchema = (schema) => schema && typeof schema === "object" && (Kind in schema && schema[Kind] !== "Unknown" || schema.type || schema.properties || schema.items);
|
|
57
|
+
var isValidSchema = (schema) => schema && typeof schema === "object" && (import_typebox.Kind in schema && schema[import_typebox.Kind] !== "Unknown" || schema.type || schema.properties || schema.items);
|
|
63
58
|
var getLoosePath = (path) => {
|
|
64
59
|
if (path.charCodeAt(path.length - 1) === 47)
|
|
65
60
|
return path.slice(0, path.length - 1);
|
|
@@ -160,7 +155,7 @@ var mergeObjectSchemas = (schemas) => {
|
|
|
160
155
|
};
|
|
161
156
|
var isTSchema = (value) => {
|
|
162
157
|
if (!value || typeof value !== "object") return false;
|
|
163
|
-
if (Kind in value) return true;
|
|
158
|
+
if (import_typebox.Kind in value) return true;
|
|
164
159
|
const keys = Object.keys(value);
|
|
165
160
|
if (keys.length > 0 && keys.every((k) => !isNaN(Number(k)))) {
|
|
166
161
|
return false;
|
|
@@ -172,7 +167,7 @@ var normalizeSchemaReference = (schema) => {
|
|
|
172
167
|
if (typeof schema !== "string") return schema;
|
|
173
168
|
return toRef(schema);
|
|
174
169
|
};
|
|
175
|
-
var mergeSchemaProperty = (existing, incoming, vendors) => {
|
|
170
|
+
var mergeSchemaProperty = (existing, incoming, vendors, openapiVersion = "3.1.2") => {
|
|
176
171
|
if (!existing) return incoming;
|
|
177
172
|
if (!incoming) return existing;
|
|
178
173
|
let existingSchema = normalizeSchemaReference(existing);
|
|
@@ -180,9 +175,19 @@ var mergeSchemaProperty = (existing, incoming, vendors) => {
|
|
|
180
175
|
if (!existingSchema) return incoming;
|
|
181
176
|
if (!incomingSchema) return existing;
|
|
182
177
|
if (!isTSchema(incomingSchema) && incomingSchema["~standard"])
|
|
183
|
-
incomingSchema = unwrapSchema(
|
|
178
|
+
incomingSchema = unwrapSchema(
|
|
179
|
+
incomingSchema,
|
|
180
|
+
vendors,
|
|
181
|
+
"input",
|
|
182
|
+
openapiVersion
|
|
183
|
+
);
|
|
184
184
|
if (!isTSchema(existingSchema) && existingSchema["~standard"])
|
|
185
|
-
existingSchema = unwrapSchema(
|
|
185
|
+
existingSchema = unwrapSchema(
|
|
186
|
+
existingSchema,
|
|
187
|
+
vendors,
|
|
188
|
+
"input",
|
|
189
|
+
openapiVersion
|
|
190
|
+
);
|
|
186
191
|
if (!incomingSchema) return existingSchema;
|
|
187
192
|
if (!existingSchema) return incomingSchema;
|
|
188
193
|
const { schema: mergedSchema, notObjects } = mergeObjectSchemas([
|
|
@@ -195,24 +200,30 @@ var mergeSchemaProperty = (existing, incoming, vendors) => {
|
|
|
195
200
|
}
|
|
196
201
|
return mergedSchema;
|
|
197
202
|
};
|
|
198
|
-
var unwrapResponseSchema = (schema, vendors) => typeof schema === "string" ? normalizeSchemaReference(schema) : !schema ? void 0 : isTSchema(schema) ? schema : (
|
|
203
|
+
var unwrapResponseSchema = (schema, vendors, openapiVersion = "3.1.2") => typeof schema === "string" ? normalizeSchemaReference(schema) : !schema ? void 0 : isTSchema(schema) ? schema : (
|
|
199
204
|
// @ts-ignore
|
|
200
|
-
schema["~standard"] ? unwrapSchema(
|
|
205
|
+
schema["~standard"] ? unwrapSchema(
|
|
206
|
+
schema,
|
|
207
|
+
vendors,
|
|
208
|
+
"output",
|
|
209
|
+
openapiVersion
|
|
210
|
+
) : Object.fromEntries(
|
|
201
211
|
Object.entries(schema).map(([status, schema2]) => [
|
|
202
212
|
status,
|
|
203
213
|
typeof schema2 === "string" ? normalizeSchemaReference(schema2) : isTSchema(schema2) ? schema2 : unwrapSchema(
|
|
204
214
|
schema2,
|
|
205
215
|
vendors,
|
|
206
|
-
"output"
|
|
216
|
+
"output",
|
|
217
|
+
openapiVersion
|
|
207
218
|
)
|
|
208
219
|
])
|
|
209
220
|
)
|
|
210
221
|
);
|
|
211
|
-
var mergeResponseSchema = (_existing, _incoming, vendors) => {
|
|
222
|
+
var mergeResponseSchema = (_existing, _incoming, vendors, openapiVersion = "3.1.2") => {
|
|
212
223
|
if (!_existing) return _incoming;
|
|
213
224
|
if (!_incoming) return _existing;
|
|
214
|
-
let existing = unwrapResponseSchema(_existing, vendors);
|
|
215
|
-
let incoming = unwrapResponseSchema(_incoming, vendors);
|
|
225
|
+
let existing = unwrapResponseSchema(_existing, vendors, openapiVersion);
|
|
226
|
+
let incoming = unwrapResponseSchema(_incoming, vendors, openapiVersion);
|
|
216
227
|
if (!existing && !incoming) return void 0;
|
|
217
228
|
if (incoming && !existing) return incoming;
|
|
218
229
|
if (existing && !incoming) return existing;
|
|
@@ -234,14 +245,15 @@ var mergeResponseSchema = (_existing, _incoming, vendors) => {
|
|
|
234
245
|
schema[status] = mergeSchemaProperty(
|
|
235
246
|
existingSchema,
|
|
236
247
|
incomingSchema,
|
|
237
|
-
vendors
|
|
248
|
+
vendors,
|
|
249
|
+
openapiVersion
|
|
238
250
|
);
|
|
239
251
|
else if (existingSchema) schema[status] = existingSchema;
|
|
240
252
|
else if (incomingSchema) schema[status] = incomingSchema;
|
|
241
253
|
}
|
|
242
254
|
return schema;
|
|
243
255
|
};
|
|
244
|
-
var mergeStandaloneValidators = (hooks, vendors) => {
|
|
256
|
+
var mergeStandaloneValidators = (hooks, vendors, openapiVersion = "3.1.2") => {
|
|
245
257
|
const merged = { ...hooks };
|
|
246
258
|
if (!hooks.standaloneValidator?.length) return merged;
|
|
247
259
|
for (const validator of hooks.standaloneValidator) {
|
|
@@ -249,37 +261,43 @@ var mergeStandaloneValidators = (hooks, vendors) => {
|
|
|
249
261
|
merged.body = mergeSchemaProperty(
|
|
250
262
|
merged.body,
|
|
251
263
|
validator.body,
|
|
252
|
-
vendors
|
|
264
|
+
vendors,
|
|
265
|
+
openapiVersion
|
|
253
266
|
);
|
|
254
267
|
if (validator.headers)
|
|
255
268
|
merged.headers = mergeSchemaProperty(
|
|
256
269
|
merged.headers,
|
|
257
270
|
validator.headers,
|
|
258
|
-
vendors
|
|
271
|
+
vendors,
|
|
272
|
+
openapiVersion
|
|
259
273
|
);
|
|
260
274
|
if (validator.query)
|
|
261
275
|
merged.query = mergeSchemaProperty(
|
|
262
276
|
merged.query,
|
|
263
277
|
validator.query,
|
|
264
|
-
vendors
|
|
278
|
+
vendors,
|
|
279
|
+
openapiVersion
|
|
265
280
|
);
|
|
266
281
|
if (validator.params)
|
|
267
282
|
merged.params = mergeSchemaProperty(
|
|
268
283
|
merged.params,
|
|
269
284
|
validator.params,
|
|
270
|
-
vendors
|
|
285
|
+
vendors,
|
|
286
|
+
openapiVersion
|
|
271
287
|
);
|
|
272
288
|
if (validator.cookie)
|
|
273
289
|
merged.cookie = mergeSchemaProperty(
|
|
274
290
|
merged.cookie,
|
|
275
291
|
validator.cookie,
|
|
276
|
-
vendors
|
|
292
|
+
vendors,
|
|
293
|
+
openapiVersion
|
|
277
294
|
);
|
|
278
295
|
if (validator.response)
|
|
279
296
|
merged.response = mergeResponseSchema(
|
|
280
297
|
merged.response,
|
|
281
298
|
validator.response,
|
|
282
|
-
vendors
|
|
299
|
+
vendors,
|
|
300
|
+
openapiVersion
|
|
283
301
|
);
|
|
284
302
|
}
|
|
285
303
|
if (typeof merged.body === "string")
|
|
@@ -305,36 +323,51 @@ var mergeStandaloneValidators = (hooks, vendors) => {
|
|
|
305
323
|
}
|
|
306
324
|
return merged;
|
|
307
325
|
};
|
|
308
|
-
var flattenRoutes = (routes, vendors) => routes.map((route) => {
|
|
326
|
+
var flattenRoutes = (routes, vendors, openapiVersion = "3.1.2") => routes.map((route) => {
|
|
309
327
|
if (!route.hooks?.standaloneValidator?.length) return route;
|
|
310
328
|
return {
|
|
311
329
|
...route,
|
|
312
|
-
hooks: mergeStandaloneValidators(
|
|
330
|
+
hooks: mergeStandaloneValidators(
|
|
331
|
+
route.hooks,
|
|
332
|
+
vendors,
|
|
333
|
+
openapiVersion
|
|
334
|
+
)
|
|
313
335
|
};
|
|
314
336
|
});
|
|
315
|
-
var unwrapReference = (schema, definitions) => {
|
|
337
|
+
var unwrapReference = (schema, definitions, openapiVersion = "3.1.2") => {
|
|
316
338
|
const ref = schema?.$ref;
|
|
317
339
|
if (!ref) return schema;
|
|
318
340
|
const name = ref.slice(ref.lastIndexOf("/") + 1);
|
|
319
341
|
if (ref && definitions[name]) schema = definitions[name];
|
|
320
|
-
return enumToOpenApi(schema);
|
|
342
|
+
return nullToOpenApi(enumToOpenApi(schema), openapiVersion);
|
|
321
343
|
};
|
|
322
|
-
var unwrapSchema = (schema, mapJsonSchema, io = "input") => {
|
|
344
|
+
var unwrapSchema = (schema, mapJsonSchema, io = "input", openapiVersion = "3.1.2") => {
|
|
323
345
|
if (!schema) return;
|
|
324
346
|
if (typeof schema === "string") schema = toRef(schema);
|
|
325
|
-
if (Kind in schema)
|
|
347
|
+
if (import_typebox.Kind in schema)
|
|
348
|
+
return nullToOpenApi(enumToOpenApi(schema), openapiVersion);
|
|
326
349
|
if (!schema?.["~standard"] && // @ts-ignore
|
|
327
350
|
(schema.$schema || schema.type || schema.properties || schema.items))
|
|
328
|
-
return schema;
|
|
351
|
+
return nullToOpenApi(schema, openapiVersion);
|
|
329
352
|
if (!schema?.["~standard"]) return;
|
|
330
|
-
const
|
|
353
|
+
const standard = schema["~standard"];
|
|
354
|
+
const vendor = standard.vendor;
|
|
331
355
|
try {
|
|
356
|
+
const jsonSchemaTarget = openapiVersion.startsWith("3.0.") ? "draft-07" : "draft-2020-12";
|
|
332
357
|
if (mapJsonSchema?.[vendor] && typeof mapJsonSchema[vendor] === "function")
|
|
333
|
-
return
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
358
|
+
return nullToOpenApi(
|
|
359
|
+
enumToOpenApi(mapJsonSchema[vendor](schema)),
|
|
360
|
+
openapiVersion
|
|
361
|
+
);
|
|
362
|
+
if (standard.jsonSchema?.[io])
|
|
363
|
+
return nullToOpenApi(
|
|
364
|
+
enumToOpenApi(
|
|
365
|
+
standard.jsonSchema[io]({
|
|
366
|
+
target: jsonSchemaTarget
|
|
367
|
+
})
|
|
368
|
+
),
|
|
369
|
+
openapiVersion
|
|
370
|
+
);
|
|
338
371
|
switch (vendor) {
|
|
339
372
|
case "zod":
|
|
340
373
|
if (warned.zod4 || warned.zod3) break;
|
|
@@ -379,10 +412,16 @@ var unwrapSchema = (schema, mapJsonSchema, io = "input") => {
|
|
|
379
412
|
break;
|
|
380
413
|
}
|
|
381
414
|
if (vendor === "arktype")
|
|
382
|
-
return
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
415
|
+
return nullToOpenApi(
|
|
416
|
+
enumToOpenApi(schema.toJsonSchema?.()),
|
|
417
|
+
openapiVersion
|
|
418
|
+
);
|
|
419
|
+
return nullToOpenApi(
|
|
420
|
+
enumToOpenApi(
|
|
421
|
+
// @ts-ignore
|
|
422
|
+
schema.toJSONSchema?.() ?? schema?.toJsonSchema?.()
|
|
423
|
+
),
|
|
424
|
+
openapiVersion
|
|
386
425
|
);
|
|
387
426
|
} catch (error) {
|
|
388
427
|
console.warn(error);
|
|
@@ -390,9 +429,9 @@ var unwrapSchema = (schema, mapJsonSchema, io = "input") => {
|
|
|
390
429
|
};
|
|
391
430
|
var enumToOpenApi = (_schema) => {
|
|
392
431
|
if (!_schema || typeof _schema !== "object") return _schema;
|
|
393
|
-
if (Kind in _schema) {
|
|
432
|
+
if (import_typebox.Kind in _schema) {
|
|
394
433
|
const schema2 = _schema;
|
|
395
|
-
if (schema2[Kind] === "Union" && schema2.anyOf && Array.isArray(schema2.anyOf) && schema2.anyOf.length > 0 && schema2.anyOf.every(
|
|
434
|
+
if (schema2[import_typebox.Kind] === "Union" && schema2.anyOf && Array.isArray(schema2.anyOf) && schema2.anyOf.length > 0 && schema2.anyOf.every(
|
|
396
435
|
(item) => item && typeof item === "object" && item.const !== void 0
|
|
397
436
|
))
|
|
398
437
|
return {
|
|
@@ -415,9 +454,154 @@ var enumToOpenApi = (_schema) => {
|
|
|
415
454
|
...schema,
|
|
416
455
|
items: enumToOpenApi(schema.items)
|
|
417
456
|
};
|
|
457
|
+
if (schema.anyOf && Array.isArray(schema.anyOf)) {
|
|
458
|
+
const mapped = schema.anyOf.map(
|
|
459
|
+
(item) => item && typeof item === "object" && item.type === "Date" ? { type: "string", format: "date-time" } : enumToOpenApi(item)
|
|
460
|
+
);
|
|
461
|
+
const seen = /* @__PURE__ */ new Set();
|
|
462
|
+
const deduped = mapped.filter((item) => {
|
|
463
|
+
if (!item || typeof item !== "object") return true;
|
|
464
|
+
const key = JSON.stringify(
|
|
465
|
+
Object.fromEntries(
|
|
466
|
+
Object.entries(item).sort(
|
|
467
|
+
([a], [b]) => a < b ? -1 : a > b ? 1 : 0
|
|
468
|
+
)
|
|
469
|
+
)
|
|
470
|
+
);
|
|
471
|
+
if (seen.has(key)) return false;
|
|
472
|
+
seen.add(key);
|
|
473
|
+
return true;
|
|
474
|
+
});
|
|
475
|
+
if (deduped.length === 1) return deduped[0];
|
|
476
|
+
return { ...schema, anyOf: deduped };
|
|
477
|
+
}
|
|
418
478
|
return schema;
|
|
419
479
|
};
|
|
420
|
-
|
|
480
|
+
var SCHEMA_MAP_KEYS = /* @__PURE__ */ new Set([
|
|
481
|
+
"properties",
|
|
482
|
+
"patternProperties",
|
|
483
|
+
"$defs",
|
|
484
|
+
"definitions",
|
|
485
|
+
"dependentSchemas"
|
|
486
|
+
]);
|
|
487
|
+
var SCHEMA_ARRAY_KEYS = /* @__PURE__ */ new Set(["allOf", "anyOf", "oneOf", "prefixItems"]);
|
|
488
|
+
var SCHEMA_VALUE_KEYS = /* @__PURE__ */ new Set([
|
|
489
|
+
"items",
|
|
490
|
+
"additionalProperties",
|
|
491
|
+
"unevaluatedProperties",
|
|
492
|
+
"contains",
|
|
493
|
+
"not",
|
|
494
|
+
"if",
|
|
495
|
+
"then",
|
|
496
|
+
"else",
|
|
497
|
+
"propertyNames"
|
|
498
|
+
]);
|
|
499
|
+
var isSchemaObject = (value) => !!value && typeof value === "object" && !Array.isArray(value);
|
|
500
|
+
var nullToOpenApi = (schema, openapiVersion) => {
|
|
501
|
+
const normalize = (value) => {
|
|
502
|
+
if (Array.isArray(value)) return value.map(normalize);
|
|
503
|
+
if (!isSchemaObject(value)) return value;
|
|
504
|
+
const normalized = { ...value };
|
|
505
|
+
const isOpenAPI30 = openapiVersion.startsWith("3.0.");
|
|
506
|
+
for (const unionKey of ["anyOf", "oneOf"]) {
|
|
507
|
+
const union = normalized[unionKey];
|
|
508
|
+
if (!Array.isArray(union)) continue;
|
|
509
|
+
const nonNull = union.filter(
|
|
510
|
+
(item) => !isSchemaObject(item) || item.type !== "null"
|
|
511
|
+
);
|
|
512
|
+
if (nonNull.length === union.length) continue;
|
|
513
|
+
const normalizedNonNull = nonNull.map(normalize);
|
|
514
|
+
if (isOpenAPI30) {
|
|
515
|
+
delete normalized[unionKey];
|
|
516
|
+
if (normalizedNonNull.length === 1 && isSchemaObject(normalizedNonNull[0]))
|
|
517
|
+
Object.assign(normalized, normalizedNonNull[0]);
|
|
518
|
+
else if (normalizedNonNull.length)
|
|
519
|
+
normalized[unionKey] = normalizedNonNull;
|
|
520
|
+
normalized.nullable = true;
|
|
521
|
+
} else if (normalizedNonNull.length === 1 && isSchemaObject(normalizedNonNull[0]) && typeof normalizedNonNull[0].type === "string") {
|
|
522
|
+
delete normalized[unionKey];
|
|
523
|
+
Object.assign(normalized, normalizedNonNull[0]);
|
|
524
|
+
normalized.type = [normalizedNonNull[0].type, "null"];
|
|
525
|
+
} else normalized[unionKey] = union.map(normalize);
|
|
526
|
+
}
|
|
527
|
+
if (isOpenAPI30 && normalized.type === "null") {
|
|
528
|
+
delete normalized.type;
|
|
529
|
+
normalized.nullable = true;
|
|
530
|
+
} else if (isOpenAPI30 && Array.isArray(normalized.type) && normalized.type.includes("null")) {
|
|
531
|
+
const types = normalized.type.filter((type) => type !== "null");
|
|
532
|
+
normalized.nullable = true;
|
|
533
|
+
if (types.length === 1) normalized.type = types[0];
|
|
534
|
+
else if (types.length) normalized.type = types;
|
|
535
|
+
else delete normalized.type;
|
|
536
|
+
}
|
|
537
|
+
for (const [key, nested] of Object.entries(normalized)) {
|
|
538
|
+
if (SCHEMA_MAP_KEYS.has(key) && isSchemaObject(nested))
|
|
539
|
+
normalized[key] = Object.fromEntries(
|
|
540
|
+
Object.entries(nested).map(([name, child]) => [
|
|
541
|
+
name,
|
|
542
|
+
normalize(child)
|
|
543
|
+
])
|
|
544
|
+
);
|
|
545
|
+
else if (SCHEMA_ARRAY_KEYS.has(key) && Array.isArray(nested))
|
|
546
|
+
normalized[key] = nested.map(normalize);
|
|
547
|
+
else if (SCHEMA_VALUE_KEYS.has(key) && isSchemaObject(nested))
|
|
548
|
+
normalized[key] = normalize(nested);
|
|
549
|
+
else if (key === "dependencies" && isSchemaObject(nested))
|
|
550
|
+
normalized[key] = Object.fromEntries(
|
|
551
|
+
Object.entries(nested).map(([name, child]) => [
|
|
552
|
+
name,
|
|
553
|
+
isSchemaObject(child) ? normalize(child) : child
|
|
554
|
+
])
|
|
555
|
+
);
|
|
556
|
+
}
|
|
557
|
+
return normalized;
|
|
558
|
+
};
|
|
559
|
+
return normalize(schema);
|
|
560
|
+
};
|
|
561
|
+
var toResponseHeaders = (schema, vendors, openapiVersion = "3.1.2") => {
|
|
562
|
+
if (!schema || typeof schema === "string" || !("headers" in schema) || !schema.headers)
|
|
563
|
+
return;
|
|
564
|
+
const entries = Object.entries(
|
|
565
|
+
schema.headers
|
|
566
|
+
).map(
|
|
567
|
+
([name, hs]) => [
|
|
568
|
+
name,
|
|
569
|
+
{
|
|
570
|
+
schema: unwrapSchema(
|
|
571
|
+
hs,
|
|
572
|
+
vendors,
|
|
573
|
+
"output",
|
|
574
|
+
openapiVersion
|
|
575
|
+
)
|
|
576
|
+
}
|
|
577
|
+
]
|
|
578
|
+
).filter(([, v]) => v.schema);
|
|
579
|
+
return entries.length ? Object.fromEntries(entries) : void 0;
|
|
580
|
+
};
|
|
581
|
+
var stripHeaders = (schema) => {
|
|
582
|
+
const { headers, ...rest } = schema;
|
|
583
|
+
return rest;
|
|
584
|
+
};
|
|
585
|
+
var VOID_TYPES = /* @__PURE__ */ new Set(["void", "null", "undefined"]);
|
|
586
|
+
var PLAIN_TYPES = /* @__PURE__ */ new Set(["string", "number", "integer", "boolean"]);
|
|
587
|
+
var toResponseContent = (schema, type, description) => VOID_TYPES.has(type) ? { type, description } : PLAIN_TYPES.has(type) ? { "text/plain": { schema } } : { "application/json": { schema } };
|
|
588
|
+
var toResponseObject = (schema, status, definitions, vendors, openapiVersion = "3.1.2") => {
|
|
589
|
+
const response = unwrapSchema(schema, vendors, "output", openapiVersion);
|
|
590
|
+
if (!response) return;
|
|
591
|
+
const responseSchema = stripHeaders(response);
|
|
592
|
+
const { type, description } = unwrapReference(
|
|
593
|
+
responseSchema,
|
|
594
|
+
definitions,
|
|
595
|
+
openapiVersion
|
|
596
|
+
);
|
|
597
|
+
const headers = toResponseHeaders(schema, vendors, openapiVersion);
|
|
598
|
+
return {
|
|
599
|
+
description: description ?? `Response for status ${status}`,
|
|
600
|
+
...headers ? { headers } : {},
|
|
601
|
+
content: toResponseContent(responseSchema, type, description)
|
|
602
|
+
};
|
|
603
|
+
};
|
|
604
|
+
function toOpenAPISchema(app, exclude, references, vendors, openapiVersion = "3.1.2") {
|
|
421
605
|
let {
|
|
422
606
|
methods: excludeMethods = ["options"],
|
|
423
607
|
staticFile: excludeStaticFile = true,
|
|
@@ -434,11 +618,19 @@ function toOpenAPISchema(app, exclude, references, vendors) {
|
|
|
434
618
|
if (typeof reference === "function") references[i] = reference();
|
|
435
619
|
}
|
|
436
620
|
}
|
|
437
|
-
const routes = flattenRoutes(app.getGlobalRoutes(), vendors);
|
|
621
|
+
const routes = flattenRoutes(app.getGlobalRoutes(), vendors, openapiVersion);
|
|
438
622
|
for (const route of routes) {
|
|
439
623
|
if (route.hooks?.detail?.hide) continue;
|
|
440
624
|
const method = route.method.toLowerCase();
|
|
441
|
-
if (excludeStaticFile && route.path.includes(".") || excludePaths.
|
|
625
|
+
if (excludeStaticFile && route.path.includes(".") || excludePaths.some((exclusion) => {
|
|
626
|
+
if (exclusion instanceof RegExp) {
|
|
627
|
+
exclusion.lastIndex = 0;
|
|
628
|
+
return exclusion.test(route.path);
|
|
629
|
+
}
|
|
630
|
+
if (typeof exclusion === "string")
|
|
631
|
+
return exclusion === route.path;
|
|
632
|
+
return false;
|
|
633
|
+
}) || excludeMethods.includes(method))
|
|
442
634
|
continue;
|
|
443
635
|
const hooks = route.hooks ?? {};
|
|
444
636
|
if (references?.length)
|
|
@@ -484,8 +676,9 @@ function toOpenAPISchema(app, exclude, references, vendors) {
|
|
|
484
676
|
const parameters = [];
|
|
485
677
|
if (hooks.params) {
|
|
486
678
|
const params = unwrapReference(
|
|
487
|
-
unwrapSchema(hooks.params, vendors),
|
|
488
|
-
definitions
|
|
679
|
+
unwrapSchema(hooks.params, vendors, "input", openapiVersion),
|
|
680
|
+
definitions,
|
|
681
|
+
openapiVersion
|
|
489
682
|
);
|
|
490
683
|
if (params && params.type === "object" && params.properties)
|
|
491
684
|
for (const [name, schema] of Object.entries(params.properties))
|
|
@@ -509,8 +702,9 @@ function toOpenAPISchema(app, exclude, references, vendors) {
|
|
|
509
702
|
}
|
|
510
703
|
if (hooks.query) {
|
|
511
704
|
const query = unwrapReference(
|
|
512
|
-
unwrapSchema(hooks.query, vendors),
|
|
513
|
-
definitions
|
|
705
|
+
unwrapSchema(hooks.query, vendors, "input", openapiVersion),
|
|
706
|
+
definitions,
|
|
707
|
+
openapiVersion
|
|
514
708
|
);
|
|
515
709
|
if (query && query.type === "object" && query.properties) {
|
|
516
710
|
const required = query.required || [];
|
|
@@ -525,8 +719,9 @@ function toOpenAPISchema(app, exclude, references, vendors) {
|
|
|
525
719
|
}
|
|
526
720
|
if (hooks.headers) {
|
|
527
721
|
const headers = unwrapReference(
|
|
528
|
-
unwrapSchema(hooks.headers, vendors),
|
|
529
|
-
definitions
|
|
722
|
+
unwrapSchema(hooks.headers, vendors, "input", openapiVersion),
|
|
723
|
+
definitions,
|
|
724
|
+
openapiVersion
|
|
530
725
|
);
|
|
531
726
|
if (headers && headers.type === "object" && headers.properties) {
|
|
532
727
|
const required = headers.required || [];
|
|
@@ -541,8 +736,9 @@ function toOpenAPISchema(app, exclude, references, vendors) {
|
|
|
541
736
|
}
|
|
542
737
|
if (hooks.cookie) {
|
|
543
738
|
const cookie = unwrapReference(
|
|
544
|
-
unwrapSchema(hooks.cookie, vendors),
|
|
545
|
-
definitions
|
|
739
|
+
unwrapSchema(hooks.cookie, vendors, "input", openapiVersion),
|
|
740
|
+
definitions,
|
|
741
|
+
openapiVersion
|
|
546
742
|
);
|
|
547
743
|
if (cookie && cookie.type === "object" && cookie.properties) {
|
|
548
744
|
const required = cookie.required || [];
|
|
@@ -557,11 +753,17 @@ function toOpenAPISchema(app, exclude, references, vendors) {
|
|
|
557
753
|
}
|
|
558
754
|
if (parameters.length > 0) operation.parameters = parameters;
|
|
559
755
|
if (hooks.body && method !== "get" && method !== "head") {
|
|
560
|
-
const body = unwrapSchema(
|
|
756
|
+
const body = unwrapSchema(
|
|
757
|
+
hooks.body,
|
|
758
|
+
vendors,
|
|
759
|
+
"input",
|
|
760
|
+
openapiVersion
|
|
761
|
+
);
|
|
561
762
|
if (body) {
|
|
562
763
|
const { type, description, $ref, ...options } = unwrapReference(
|
|
563
764
|
body,
|
|
564
|
-
definitions
|
|
765
|
+
definitions,
|
|
766
|
+
openapiVersion
|
|
565
767
|
);
|
|
566
768
|
if (hooks.parse) {
|
|
567
769
|
const content = {};
|
|
@@ -589,6 +791,12 @@ function toOpenAPISchema(app, exclude, references, vendors) {
|
|
|
589
791
|
schema: body
|
|
590
792
|
};
|
|
591
793
|
continue;
|
|
794
|
+
case "arrayBuffer":
|
|
795
|
+
case "application/octet-stream":
|
|
796
|
+
content["application/octet-stream"] = {
|
|
797
|
+
schema: body
|
|
798
|
+
};
|
|
799
|
+
continue;
|
|
592
800
|
}
|
|
593
801
|
}
|
|
594
802
|
operation.requestBody = {
|
|
@@ -622,50 +830,26 @@ function toOpenAPISchema(app, exclude, references, vendors) {
|
|
|
622
830
|
if (hooks.response) {
|
|
623
831
|
operation.responses = {};
|
|
624
832
|
if (typeof hooks.response === "object" && // TypeBox
|
|
625
|
-
!hooks.response.type && !hooks.response.$ref && !hooks.response["~standard"]) {
|
|
833
|
+
!(import_typebox.Kind in hooks.response) && !hooks.response.type && !hooks.response.$ref && !hooks.response["~standard"]) {
|
|
626
834
|
for (let [status, schema] of Object.entries(hooks.response)) {
|
|
627
|
-
const response =
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
}
|
|
636
|
-
} : {
|
|
637
|
-
"application/json": {
|
|
638
|
-
schema: response
|
|
639
|
-
}
|
|
640
|
-
}
|
|
641
|
-
};
|
|
835
|
+
const response = toResponseObject(
|
|
836
|
+
schema,
|
|
837
|
+
status,
|
|
838
|
+
definitions,
|
|
839
|
+
vendors,
|
|
840
|
+
openapiVersion
|
|
841
|
+
);
|
|
842
|
+
if (response) operation.responses[status] = response;
|
|
642
843
|
}
|
|
643
844
|
} else {
|
|
644
|
-
const response =
|
|
845
|
+
const response = toResponseObject(
|
|
645
846
|
hooks.response,
|
|
847
|
+
"200",
|
|
848
|
+
definitions,
|
|
646
849
|
vendors,
|
|
647
|
-
|
|
850
|
+
openapiVersion
|
|
648
851
|
);
|
|
649
|
-
if (response)
|
|
650
|
-
const {
|
|
651
|
-
type: _type,
|
|
652
|
-
description,
|
|
653
|
-
...options
|
|
654
|
-
} = unwrapReference(response, definitions);
|
|
655
|
-
const type = _type;
|
|
656
|
-
operation.responses["200"] = {
|
|
657
|
-
description: description ?? `Response for status 200`,
|
|
658
|
-
content: type === "void" || type === "null" || type === "undefined" ? { type, description } : type === "string" || type === "number" || type === "integer" || type === "boolean" ? {
|
|
659
|
-
"text/plain": {
|
|
660
|
-
schema: response
|
|
661
|
-
}
|
|
662
|
-
} : {
|
|
663
|
-
"application/json": {
|
|
664
|
-
schema: response
|
|
665
|
-
}
|
|
666
|
-
}
|
|
667
|
-
};
|
|
668
|
-
}
|
|
852
|
+
if (response) operation.responses["200"] = response;
|
|
669
853
|
}
|
|
670
854
|
}
|
|
671
855
|
for (let path of getPossiblePath(route.path)) {
|
|
@@ -699,7 +883,12 @@ function toOpenAPISchema(app, exclude, references, vendors) {
|
|
|
699
883
|
const schemas = /* @__PURE__ */ Object.create(null);
|
|
700
884
|
if (definitions)
|
|
701
885
|
for (const [name, schema] of Object.entries(definitions)) {
|
|
702
|
-
const jsonSchema = unwrapSchema(
|
|
886
|
+
const jsonSchema = unwrapSchema(
|
|
887
|
+
schema,
|
|
888
|
+
vendors,
|
|
889
|
+
"input",
|
|
890
|
+
openapiVersion
|
|
891
|
+
);
|
|
703
892
|
if (jsonSchema) schemas[name] = jsonSchema;
|
|
704
893
|
}
|
|
705
894
|
return {
|
|
@@ -709,15 +898,26 @@ function toOpenAPISchema(app, exclude, references, vendors) {
|
|
|
709
898
|
paths
|
|
710
899
|
};
|
|
711
900
|
}
|
|
712
|
-
var withHeaders = (schema, headers) =>
|
|
713
|
-
|
|
714
|
-
|
|
901
|
+
var withHeaders = (schema, headers) => {
|
|
902
|
+
const clone = Object.create(
|
|
903
|
+
Object.getPrototypeOf(schema),
|
|
904
|
+
Object.getOwnPropertyDescriptors(schema)
|
|
905
|
+
);
|
|
906
|
+
Object.defineProperty(clone, "headers", {
|
|
907
|
+
value: headers,
|
|
908
|
+
enumerable: true,
|
|
909
|
+
configurable: true,
|
|
910
|
+
writable: true
|
|
911
|
+
});
|
|
912
|
+
return clone;
|
|
913
|
+
};
|
|
715
914
|
// Annotate the CommonJS export names for ESM import in node:
|
|
716
915
|
0 && (module.exports = {
|
|
717
916
|
capitalize,
|
|
718
917
|
enumToOpenApi,
|
|
719
918
|
getLoosePath,
|
|
720
919
|
getPossiblePath,
|
|
920
|
+
nullToOpenApi,
|
|
721
921
|
toOpenAPISchema,
|
|
722
922
|
unwrapSchema,
|
|
723
923
|
withHeaders
|