hono-openapi 1.3.1 → 1.3.3
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 +214 -69
- package/dist/index.d.cts +48 -64
- package/dist/index.d.ts +48 -64
- package/dist/index.js +214 -70
- package/package.json +7 -13
package/dist/index.cjs
CHANGED
|
@@ -6,6 +6,7 @@ var standardJson = require('@standard-community/standard-json');
|
|
|
6
6
|
var standardOpenapi = require('@standard-community/standard-openapi');
|
|
7
7
|
|
|
8
8
|
const uniqueSymbol = Symbol("openapi");
|
|
9
|
+
const VALIDATION_MARKER = "__HonoOpenAPIValidator__";
|
|
9
10
|
const ALLOWED_METHODS = [
|
|
10
11
|
"GET",
|
|
11
12
|
"PUT",
|
|
@@ -55,10 +56,12 @@ function mergeParameters(...params) {
|
|
|
55
56
|
return Array.from(merged.values());
|
|
56
57
|
}
|
|
57
58
|
const specsByPathContext = /* @__PURE__ */ new Map();
|
|
58
|
-
function getPathContext(path) {
|
|
59
|
+
function getPathContext(path, pathContext) {
|
|
59
60
|
const context = [];
|
|
60
|
-
for (const [key, data] of
|
|
61
|
-
if (data
|
|
61
|
+
for (const [key, data] of pathContext) {
|
|
62
|
+
if (!data) continue;
|
|
63
|
+
const prefix = key.endsWith("/*") ? key.slice(0, -2) : key;
|
|
64
|
+
if (path === prefix || path.startsWith(`${prefix}/`)) {
|
|
62
65
|
context.push(data);
|
|
63
66
|
}
|
|
64
67
|
}
|
|
@@ -67,6 +70,19 @@ function getPathContext(path) {
|
|
|
67
70
|
function clearSpecsContext() {
|
|
68
71
|
specsByPathContext.clear();
|
|
69
72
|
}
|
|
73
|
+
function mergeRequestBodies(previous, current) {
|
|
74
|
+
if (!previous || !current || "$ref" in previous || "$ref" in current) {
|
|
75
|
+
return current;
|
|
76
|
+
}
|
|
77
|
+
return {
|
|
78
|
+
...previous,
|
|
79
|
+
...current,
|
|
80
|
+
content: {
|
|
81
|
+
...previous.content,
|
|
82
|
+
...current.content
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
}
|
|
70
86
|
function mergeSpecs(route, ...specs) {
|
|
71
87
|
return specs.reduce(
|
|
72
88
|
(prev, spec) => {
|
|
@@ -88,6 +104,11 @@ function mergeSpecs(route, ...specs) {
|
|
|
88
104
|
} else {
|
|
89
105
|
if (key === "parameters") {
|
|
90
106
|
prev[key] = mergeParameters(prev[key], value);
|
|
107
|
+
} else if (key === "requestBody") {
|
|
108
|
+
prev.requestBody = mergeRequestBodies(
|
|
109
|
+
prev.requestBody,
|
|
110
|
+
value
|
|
111
|
+
);
|
|
91
112
|
} else {
|
|
92
113
|
prev[key] = {
|
|
93
114
|
...prev[key],
|
|
@@ -106,30 +127,26 @@ function mergeSpecs(route, ...specs) {
|
|
|
106
127
|
}
|
|
107
128
|
);
|
|
108
129
|
}
|
|
109
|
-
function registerSchemaPath({
|
|
110
|
-
route,
|
|
111
|
-
specs,
|
|
112
|
-
paths
|
|
113
|
-
}) {
|
|
130
|
+
function registerSchemaPath({ route, specs, paths }, pathContext = specsByPathContext) {
|
|
114
131
|
const path = toOpenAPIPath(route.path);
|
|
115
132
|
const method = route.method.toLowerCase();
|
|
116
133
|
if (method === "all") {
|
|
117
134
|
if (!specs) return;
|
|
118
|
-
if (
|
|
119
|
-
const prev =
|
|
120
|
-
|
|
135
|
+
if (pathContext.has(path)) {
|
|
136
|
+
const prev = pathContext.get(path) ?? {};
|
|
137
|
+
pathContext.set(path, mergeSpecs(route, prev, specs));
|
|
121
138
|
} else {
|
|
122
|
-
|
|
139
|
+
pathContext.set(path, specs);
|
|
123
140
|
}
|
|
124
141
|
} else {
|
|
125
|
-
const
|
|
142
|
+
const context = getPathContext(path, pathContext);
|
|
126
143
|
if (!(path in paths)) {
|
|
127
144
|
paths[path] = {};
|
|
128
145
|
}
|
|
129
146
|
if (paths[path]) {
|
|
130
147
|
paths[path][method] = mergeSpecs(
|
|
131
148
|
route,
|
|
132
|
-
...
|
|
149
|
+
...context,
|
|
133
150
|
paths[path]?.[method],
|
|
134
151
|
specs
|
|
135
152
|
);
|
|
@@ -159,6 +176,8 @@ function removeExcludedPaths(paths, ctx) {
|
|
|
159
176
|
for (const method of Object.keys(value)) {
|
|
160
177
|
const schema = value[method];
|
|
161
178
|
if (schema == null) continue;
|
|
179
|
+
const hasValidation = schema[VALIDATION_MARKER] === true;
|
|
180
|
+
delete schema[VALIDATION_MARKER];
|
|
162
181
|
if (key.includes("{")) {
|
|
163
182
|
schema.parameters = schema.parameters ? [...schema.parameters] : [];
|
|
164
183
|
const pathParameters = key.split("/").filter(
|
|
@@ -198,6 +217,16 @@ function removeExcludedPaths(paths, ctx) {
|
|
|
198
217
|
200: {}
|
|
199
218
|
};
|
|
200
219
|
}
|
|
220
|
+
if (hasValidation && ctx.options.defaultValidationErrorResponse !== false && !schema.responses["400"]) {
|
|
221
|
+
const errorResponse = ctx.options.defaultValidationErrorResponse;
|
|
222
|
+
if (typeof errorResponse === "object") {
|
|
223
|
+
schema.responses["400"] = structuredClone(errorResponse);
|
|
224
|
+
} else if (ctx.validationErrorResponse) {
|
|
225
|
+
schema.responses["400"] = structuredClone(
|
|
226
|
+
ctx.validationErrorResponse
|
|
227
|
+
);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
201
230
|
}
|
|
202
231
|
const filteredValue = {};
|
|
203
232
|
for (const method of Object.keys(value)) {
|
|
@@ -217,7 +246,27 @@ const DEFAULT_OPTIONS = {
|
|
|
217
246
|
excludeStaticFile: true,
|
|
218
247
|
exclude: [],
|
|
219
248
|
excludeMethods: ["OPTIONS"],
|
|
220
|
-
excludeTags: []
|
|
249
|
+
excludeTags: [],
|
|
250
|
+
defaultValidationErrorResponse: true
|
|
251
|
+
};
|
|
252
|
+
const DEFAULT_VALIDATION_ERROR = {
|
|
253
|
+
description: "Validation Error",
|
|
254
|
+
content: {
|
|
255
|
+
"application/json": {
|
|
256
|
+
schema: {
|
|
257
|
+
type: "object",
|
|
258
|
+
properties: {
|
|
259
|
+
success: { type: "boolean", enum: [false] },
|
|
260
|
+
error: {
|
|
261
|
+
type: "array",
|
|
262
|
+
items: {}
|
|
263
|
+
},
|
|
264
|
+
data: {}
|
|
265
|
+
},
|
|
266
|
+
required: ["success", "error", "data"]
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
221
270
|
};
|
|
222
271
|
function openAPIRouteHandler(hono, options) {
|
|
223
272
|
let specs;
|
|
@@ -234,10 +283,14 @@ async function generateSpecs(hono, options = DEFAULT_OPTIONS, c) {
|
|
|
234
283
|
options: {
|
|
235
284
|
...DEFAULT_OPTIONS,
|
|
236
285
|
...options
|
|
237
|
-
}
|
|
286
|
+
},
|
|
287
|
+
validationErrorResponse: DEFAULT_VALIDATION_ERROR
|
|
238
288
|
};
|
|
239
289
|
const _documentation = ctx.options.documentation ?? {};
|
|
240
|
-
|
|
290
|
+
const documentation = {
|
|
291
|
+
..._documentation,
|
|
292
|
+
components: _documentation.components && { ..._documentation.components }
|
|
293
|
+
};
|
|
241
294
|
const paths = await generatePaths(hono, ctx);
|
|
242
295
|
for (const path in paths) {
|
|
243
296
|
for (const method in paths[path]) {
|
|
@@ -252,41 +305,48 @@ async function generateSpecs(hono, options = DEFAULT_OPTIONS, c) {
|
|
|
252
305
|
}
|
|
253
306
|
}
|
|
254
307
|
}
|
|
255
|
-
const
|
|
308
|
+
const resolvedDocumentation = documentation.components?.responses ? await resolveResponseSchemas(documentation.components.responses) : void 0;
|
|
309
|
+
if (resolvedDocumentation && documentation.components) {
|
|
310
|
+
documentation.components.responses = resolvedDocumentation.responses;
|
|
311
|
+
}
|
|
256
312
|
const components = mergeComponentsObjects(
|
|
257
|
-
|
|
258
|
-
|
|
313
|
+
documentation.components,
|
|
314
|
+
resolvedDocumentation?.components,
|
|
259
315
|
ctx.components
|
|
260
316
|
);
|
|
261
317
|
return {
|
|
262
318
|
openapi: "3.1.0",
|
|
263
|
-
...
|
|
264
|
-
tags:
|
|
319
|
+
...documentation,
|
|
320
|
+
tags: documentation.tags?.filter(
|
|
265
321
|
(tag) => !ctx.options.excludeTags?.includes(tag?.name)
|
|
266
322
|
),
|
|
267
323
|
info: {
|
|
268
324
|
title: "Hono Documentation",
|
|
269
325
|
description: "Development documentation",
|
|
270
326
|
version: "0.0.0",
|
|
271
|
-
...
|
|
327
|
+
...documentation.info
|
|
272
328
|
},
|
|
273
329
|
paths: {
|
|
274
330
|
...removeExcludedPaths(paths, ctx),
|
|
275
|
-
...
|
|
331
|
+
...documentation.paths
|
|
276
332
|
},
|
|
277
333
|
components
|
|
278
334
|
};
|
|
279
335
|
}
|
|
280
336
|
async function generatePaths(hono, ctx) {
|
|
281
337
|
const paths = {};
|
|
338
|
+
const pathContext = /* @__PURE__ */ new Map();
|
|
282
339
|
for (const route of hono.routes) {
|
|
283
340
|
const middlewareHandler = handler.findTargetHandler(route.handler)[uniqueSymbol];
|
|
284
341
|
if (!middlewareHandler) {
|
|
285
342
|
if (ctx.options.includeEmptyPaths) {
|
|
286
|
-
registerSchemaPath(
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
343
|
+
registerSchemaPath(
|
|
344
|
+
{
|
|
345
|
+
route,
|
|
346
|
+
paths
|
|
347
|
+
},
|
|
348
|
+
pathContext
|
|
349
|
+
);
|
|
290
350
|
}
|
|
291
351
|
continue;
|
|
292
352
|
}
|
|
@@ -302,14 +362,18 @@ async function generatePaths(hono, ctx) {
|
|
|
302
362
|
const defaultOptionsForThisMethod = ctx.options.defaultOptions?.[routeMethod] && { ...ctx.options.defaultOptions[routeMethod] };
|
|
303
363
|
const { schema: routeSpecs, components = {} } = await getSpec(
|
|
304
364
|
middlewareHandler,
|
|
305
|
-
defaultOptionsForThisMethod
|
|
365
|
+
defaultOptionsForThisMethod,
|
|
366
|
+
ctx.components.parameters
|
|
306
367
|
);
|
|
307
368
|
ctx.components = mergeComponentsObjects(ctx.components, components);
|
|
308
|
-
registerSchemaPath(
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
369
|
+
registerSchemaPath(
|
|
370
|
+
{
|
|
371
|
+
route,
|
|
372
|
+
specs: routeSpecs,
|
|
373
|
+
paths
|
|
374
|
+
},
|
|
375
|
+
pathContext
|
|
376
|
+
);
|
|
313
377
|
}
|
|
314
378
|
return paths;
|
|
315
379
|
}
|
|
@@ -325,7 +389,7 @@ function getHiddenValue(options) {
|
|
|
325
389
|
}
|
|
326
390
|
return false;
|
|
327
391
|
}
|
|
328
|
-
async function getSpec(middlewareHandler, defaultOptions) {
|
|
392
|
+
async function getSpec(middlewareHandler, defaultOptions, parameterComponents) {
|
|
329
393
|
if ("spec" in middlewareHandler) {
|
|
330
394
|
const tmp = {
|
|
331
395
|
...defaultOptions,
|
|
@@ -338,14 +402,29 @@ async function getSpec(middlewareHandler, defaultOptions) {
|
|
|
338
402
|
let components = {};
|
|
339
403
|
if (tmp.responses) {
|
|
340
404
|
const resolved = await resolveResponseSchemas(tmp.responses);
|
|
405
|
+
tmp.responses = resolved.responses;
|
|
341
406
|
components = resolved.components;
|
|
342
407
|
}
|
|
408
|
+
if (tmp.requestBody && "content" in tmp.requestBody) {
|
|
409
|
+
const resolved = await resolveContentSchemas(tmp.requestBody.content);
|
|
410
|
+
tmp.requestBody = {
|
|
411
|
+
...tmp.requestBody,
|
|
412
|
+
content: resolved.content
|
|
413
|
+
};
|
|
414
|
+
components = mergeComponentsObjects(components, resolved.components);
|
|
415
|
+
}
|
|
343
416
|
return { schema: tmp, components };
|
|
344
417
|
}
|
|
345
418
|
const result = await middlewareHandler.toOpenAPISchema();
|
|
346
|
-
|
|
419
|
+
liftSchemaDefs(result);
|
|
420
|
+
const docs = {
|
|
421
|
+
...defaultOptions,
|
|
422
|
+
// Mark this operation as validator-derived so a default 400 validation
|
|
423
|
+
// error response can be auto-injected later (see removeExcludedPaths).
|
|
424
|
+
[VALIDATION_MARKER]: true
|
|
425
|
+
};
|
|
347
426
|
if (middlewareHandler.target === "form" || middlewareHandler.target === "json") {
|
|
348
|
-
const media = middlewareHandler.options?.media ?? middlewareHandler.target === "json" ? "application/json" : "multipart/form-data";
|
|
427
|
+
const media = middlewareHandler.options?.media ?? (middlewareHandler.target === "json" ? "application/json" : "multipart/form-data");
|
|
349
428
|
if (!docs.requestBody || !("content" in docs.requestBody) || !docs.requestBody.content) {
|
|
350
429
|
docs.requestBody = {
|
|
351
430
|
required: true,
|
|
@@ -367,65 +446,130 @@ async function getSpec(middlewareHandler, defaultOptions) {
|
|
|
367
446
|
const pos = ref.split("/").pop();
|
|
368
447
|
if (pos && result.components?.schemas?.[pos]) {
|
|
369
448
|
const schema = result.components.schemas[pos];
|
|
370
|
-
const
|
|
449
|
+
const generatedParameters = generateParameters(
|
|
371
450
|
middlewareHandler.target,
|
|
372
|
-
schema
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
451
|
+
schema,
|
|
452
|
+
result.components.schemas
|
|
453
|
+
);
|
|
454
|
+
const singleParameter = generatedParameters.length === 1 ? generatedParameters[0] : void 0;
|
|
455
|
+
const existingParameter = parameterComponents?.[pos];
|
|
456
|
+
if (singleParameter && (!existingParameter || "in" in existingParameter && existingParameter.in === singleParameter.in && existingParameter.name === singleParameter.name)) {
|
|
457
|
+
result.components.parameters ??= {};
|
|
458
|
+
result.components.parameters[pos] = singleParameter;
|
|
459
|
+
parameters.push({ $ref: `#/components/parameters/${pos}` });
|
|
460
|
+
delete result.components.schemas[pos];
|
|
461
|
+
} else {
|
|
462
|
+
parameters = generatedParameters;
|
|
376
463
|
}
|
|
377
|
-
result.components.parameters[pos] = newParameters;
|
|
378
|
-
delete result.components.schemas[pos];
|
|
379
|
-
parameters.push({
|
|
380
|
-
$ref: `#/components/parameters/${pos}`
|
|
381
|
-
});
|
|
382
464
|
}
|
|
383
465
|
} else {
|
|
384
|
-
parameters = generateParameters(
|
|
466
|
+
parameters = generateParameters(
|
|
467
|
+
middlewareHandler.target,
|
|
468
|
+
result.schema,
|
|
469
|
+
result.components?.schemas
|
|
470
|
+
);
|
|
385
471
|
}
|
|
386
472
|
docs.parameters = parameters;
|
|
387
473
|
}
|
|
388
474
|
return { schema: docs, components: result.components };
|
|
389
475
|
}
|
|
390
|
-
function generateParameters(target, schema) {
|
|
476
|
+
function generateParameters(target, schema, schemas) {
|
|
391
477
|
const parameters = [];
|
|
392
|
-
for (const [key,
|
|
478
|
+
for (const [key, property] of collectParameterProperties(schema, schemas)) {
|
|
393
479
|
const def = {
|
|
394
480
|
in: target === "param" ? "path" : target,
|
|
395
481
|
name: key,
|
|
396
|
-
// @ts-expect-error
|
|
397
|
-
schema:
|
|
482
|
+
// @ts-expect-error ParameterObject uses the OpenAPI 3.0 schema type.
|
|
483
|
+
schema: property.schema
|
|
398
484
|
};
|
|
399
|
-
|
|
400
|
-
if (isRequired) {
|
|
485
|
+
if (property.required) {
|
|
401
486
|
def.required = true;
|
|
402
487
|
}
|
|
403
488
|
if (def.schema && "description" in def.schema && def.schema.description) {
|
|
404
489
|
def.description = def.schema.description;
|
|
405
|
-
def.schema.description
|
|
490
|
+
def.schema = { ...def.schema, description: void 0 };
|
|
406
491
|
}
|
|
407
492
|
parameters.push(def);
|
|
408
493
|
}
|
|
409
494
|
return parameters;
|
|
410
495
|
}
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
496
|
+
function collectParameterProperties(schema, schemas) {
|
|
497
|
+
const properties = /* @__PURE__ */ new Map();
|
|
498
|
+
const resolvingRefs = /* @__PURE__ */ new Set();
|
|
499
|
+
const collect = (current) => {
|
|
500
|
+
for (const [key, value] of Object.entries(current.properties ?? {})) {
|
|
501
|
+
const existing = properties.get(key);
|
|
502
|
+
properties.set(key, {
|
|
503
|
+
schema: existing ? { allOf: [existing.schema, value] } : value,
|
|
504
|
+
required: Boolean(current.required?.includes(key)) || existing?.required
|
|
505
|
+
});
|
|
506
|
+
}
|
|
507
|
+
for (const member of current.allOf ?? []) {
|
|
508
|
+
if ("$ref" in member) {
|
|
509
|
+
const prefix = "#/components/schemas/";
|
|
510
|
+
if (!member.$ref.startsWith(prefix)) continue;
|
|
511
|
+
const name = member.$ref.slice(prefix.length).replaceAll("~1", "/").replaceAll("~0", "~");
|
|
512
|
+
const referencedSchema = schemas?.[name];
|
|
513
|
+
if (referencedSchema && !resolvingRefs.has(name)) {
|
|
514
|
+
resolvingRefs.add(name);
|
|
515
|
+
collect(referencedSchema);
|
|
516
|
+
resolvingRefs.delete(name);
|
|
424
517
|
}
|
|
518
|
+
} else {
|
|
519
|
+
collect(member);
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
};
|
|
523
|
+
collect(schema);
|
|
524
|
+
return properties;
|
|
525
|
+
}
|
|
526
|
+
async function resolveContentSchemas(content) {
|
|
527
|
+
let components = {};
|
|
528
|
+
const resolvedContent = {};
|
|
529
|
+
for (const [contentKey, raw] of Object.entries(content)) {
|
|
530
|
+
if (!raw) continue;
|
|
531
|
+
if (raw.schema && "toOpenAPISchema" in raw.schema) {
|
|
532
|
+
const result = await raw.schema.toOpenAPISchema();
|
|
533
|
+
liftSchemaDefs(result);
|
|
534
|
+
resolvedContent[contentKey] = {
|
|
535
|
+
...raw,
|
|
536
|
+
schema: result.schema
|
|
537
|
+
};
|
|
538
|
+
if (result.components) {
|
|
539
|
+
components = mergeComponentsObjects(components, result.components);
|
|
425
540
|
}
|
|
541
|
+
} else {
|
|
542
|
+
resolvedContent[contentKey] = raw;
|
|
426
543
|
}
|
|
427
544
|
}
|
|
428
|
-
return {
|
|
545
|
+
return { content: resolvedContent, components };
|
|
546
|
+
}
|
|
547
|
+
async function resolveResponseSchemas(responses) {
|
|
548
|
+
let components = {};
|
|
549
|
+
const resolvedResponses = {};
|
|
550
|
+
for (const [key, response] of Object.entries(responses)) {
|
|
551
|
+
if (!response || !("content" in response) || !response.content) {
|
|
552
|
+
resolvedResponses[key] = response;
|
|
553
|
+
continue;
|
|
554
|
+
}
|
|
555
|
+
const resolved = await resolveContentSchemas(response.content);
|
|
556
|
+
resolvedResponses[key] = {
|
|
557
|
+
...response,
|
|
558
|
+
content: resolved.content
|
|
559
|
+
};
|
|
560
|
+
components = mergeComponentsObjects(components, resolved.components);
|
|
561
|
+
}
|
|
562
|
+
return { responses: resolvedResponses, components };
|
|
563
|
+
}
|
|
564
|
+
function liftSchemaDefs(result) {
|
|
565
|
+
const defs = result.schema.$defs;
|
|
566
|
+
if (!defs || typeof defs !== "object") return;
|
|
567
|
+
result.components ??= {};
|
|
568
|
+
result.components.schemas = {
|
|
569
|
+
...defs,
|
|
570
|
+
...result.components.schemas
|
|
571
|
+
};
|
|
572
|
+
delete result.schema.$defs;
|
|
429
573
|
}
|
|
430
574
|
function mergeComponentsObjects(...components) {
|
|
431
575
|
return components.reduce(
|
|
@@ -571,6 +715,7 @@ function describeResponse(handler, responses, options) {
|
|
|
571
715
|
}
|
|
572
716
|
|
|
573
717
|
exports.ALLOWED_METHODS = ALLOWED_METHODS;
|
|
718
|
+
exports.VALIDATION_MARKER = VALIDATION_MARKER;
|
|
574
719
|
exports.clearSpecsContext = clearSpecsContext;
|
|
575
720
|
exports.describeResponse = describeResponse;
|
|
576
721
|
exports.describeRoute = describeRoute;
|
package/dist/index.d.cts
CHANGED
|
@@ -1,72 +1,17 @@
|
|
|
1
1
|
import * as openapi_types from 'openapi-types';
|
|
2
2
|
import { OpenAPIV3_1 } from 'openapi-types';
|
|
3
|
+
import * as hono from 'hono';
|
|
3
4
|
import { Env, Input, Context, Next, MiddlewareHandler, ValidationTargets, Hono } from 'hono';
|
|
4
5
|
import { TypedResponse, RouterRoute, ValidationTargets as ValidationTargets$1, BlankEnv, Input as Input$1, BlankInput, Schema, BlankSchema, MiddlewareHandler as MiddlewareHandler$1 } from 'hono/types';
|
|
5
6
|
import { loadVendor as loadVendor$2, ToOpenAPISchemaContext } from '@standard-community/standard-openapi';
|
|
6
7
|
import { Hook } from '@hono/standard-validator';
|
|
7
8
|
import { loadVendor as loadVendor$1 } from '@standard-community/standard-json';
|
|
9
|
+
import { StandardSchemaV1 } from '@standard-schema/spec';
|
|
8
10
|
import { StatusCode } from 'hono/utils/http-status';
|
|
9
11
|
import { JSONParsed } from 'hono/utils/types';
|
|
10
12
|
import { InferInput } from 'hono/validator';
|
|
11
13
|
import { JSONSchema7 } from 'json-schema';
|
|
12
14
|
|
|
13
|
-
/** The Standard Schema interface. */
|
|
14
|
-
interface StandardSchemaV1<Input = unknown, Output = Input> {
|
|
15
|
-
/** The Standard Schema properties. */
|
|
16
|
-
readonly "~standard": StandardSchemaV1.Props<Input, Output>;
|
|
17
|
-
}
|
|
18
|
-
declare namespace StandardSchemaV1 {
|
|
19
|
-
/** The Standard Schema properties interface. */
|
|
20
|
-
export interface Props<Input = unknown, Output = Input> {
|
|
21
|
-
/** The version number of the standard. */
|
|
22
|
-
readonly version: 1;
|
|
23
|
-
/** The vendor name of the schema library. */
|
|
24
|
-
readonly vendor: string;
|
|
25
|
-
/** Validates unknown input values. */
|
|
26
|
-
readonly validate: (value: unknown) => Result<Output> | Promise<Result<Output>>;
|
|
27
|
-
/** Inferred types associated with the schema. */
|
|
28
|
-
readonly types?: Types<Input, Output> | undefined;
|
|
29
|
-
}
|
|
30
|
-
/** The result interface of the validate function. */
|
|
31
|
-
export type Result<Output> = SuccessResult<Output> | FailureResult;
|
|
32
|
-
/** The result interface if validation succeeds. */
|
|
33
|
-
export interface SuccessResult<Output> {
|
|
34
|
-
/** The typed output value. */
|
|
35
|
-
readonly value: Output;
|
|
36
|
-
/** The non-existent issues. */
|
|
37
|
-
readonly issues?: undefined;
|
|
38
|
-
}
|
|
39
|
-
/** The result interface if validation fails. */
|
|
40
|
-
export interface FailureResult {
|
|
41
|
-
/** The issues of failed validation. */
|
|
42
|
-
readonly issues: ReadonlyArray<Issue>;
|
|
43
|
-
}
|
|
44
|
-
/** The issue interface of the failure output. */
|
|
45
|
-
export interface Issue {
|
|
46
|
-
/** The error message of the issue. */
|
|
47
|
-
readonly message: string;
|
|
48
|
-
/** The path of the issue, if any. */
|
|
49
|
-
readonly path?: ReadonlyArray<PropertyKey | PathSegment> | undefined;
|
|
50
|
-
}
|
|
51
|
-
/** The path segment interface of the issue. */
|
|
52
|
-
export interface PathSegment {
|
|
53
|
-
/** The key representing a path segment. */
|
|
54
|
-
readonly key: PropertyKey;
|
|
55
|
-
}
|
|
56
|
-
/** The Standard Schema types interface. */
|
|
57
|
-
export interface Types<Input = unknown, Output = Input> {
|
|
58
|
-
/** The input type of the schema. */
|
|
59
|
-
readonly input: Input;
|
|
60
|
-
/** The output type of the schema. */
|
|
61
|
-
readonly output: Output;
|
|
62
|
-
}
|
|
63
|
-
/** Infers the input type of a Standard Schema. */
|
|
64
|
-
export type InferInput<Schema extends StandardSchemaV1> = NonNullable<Schema["~standard"]["types"]>["input"];
|
|
65
|
-
/** Infers the output type of a Standard Schema. */
|
|
66
|
-
export type InferOutput<Schema extends StandardSchemaV1> = NonNullable<Schema["~standard"]["types"]>["output"];
|
|
67
|
-
export { };
|
|
68
|
-
}
|
|
69
|
-
|
|
70
15
|
declare function loadVendor(vendor: string, fn: {
|
|
71
16
|
toJSONSchema?: Parameters<typeof loadVendor$1>[1];
|
|
72
17
|
toOpenAPISchema?: Parameters<typeof loadVendor$2>[1];
|
|
@@ -129,10 +74,31 @@ declare function describeResponse<E extends Env, P extends string, I extends Inp
|
|
|
129
74
|
* The unique symbol for the middlewares, which makes it easier to identify them. Not meant to be used directly, unless you're creating a custom middleware.
|
|
130
75
|
*/
|
|
131
76
|
declare const uniqueSymbol: unique symbol;
|
|
77
|
+
/**
|
|
78
|
+
* Internal marker key set on an operation's spec when it is produced by a
|
|
79
|
+
* `validator()` middleware. It is used to decide whether to auto-inject the
|
|
80
|
+
* default 400 validation error response, and is stripped from the operation
|
|
81
|
+
* before the spec is emitted. Must be an enumerable string key so it survives
|
|
82
|
+
* the `Object.entries`-based merge in `mergeSpecs`.
|
|
83
|
+
*/
|
|
84
|
+
declare const VALIDATION_MARKER = "__HonoOpenAPIValidator__";
|
|
132
85
|
declare const ALLOWED_METHODS: readonly ["GET", "PUT", "POST", "DELETE", "OPTIONS", "HEAD", "PATCH", "TRACE"];
|
|
133
86
|
type AllowedMethods = (typeof ALLOWED_METHODS)[number];
|
|
134
87
|
declare function clearSpecsContext(): void;
|
|
135
|
-
declare function registerSchemaPath({ route, specs, paths
|
|
88
|
+
declare function registerSchemaPath({ route, specs, paths }: RegisterSchemaPathOptions, pathContext?: Map<string, Omit<OpenAPIV3_1.OperationObject<{}>, "operationId" | "requestBody" | "responses"> & {
|
|
89
|
+
operationId?: string | ((route: RouterRoute) => string);
|
|
90
|
+
requestBody?: OpenAPIV3_1.ReferenceObject | (Omit<OpenAPIV3_1.RequestBodyObject, "content"> & {
|
|
91
|
+
content: ContentWithResolver;
|
|
92
|
+
});
|
|
93
|
+
hide?: boolean | ((props: {
|
|
94
|
+
c?: hono.Context;
|
|
95
|
+
method: string;
|
|
96
|
+
path: string;
|
|
97
|
+
}) => boolean);
|
|
98
|
+
responses?: ResponsesWithResolver;
|
|
99
|
+
} & {
|
|
100
|
+
operationId?: string | ((route: RouterRoute) => string);
|
|
101
|
+
}>): void;
|
|
136
102
|
declare function removeExcludedPaths(paths: OpenAPIV3_1.PathsObject, ctx: SpecContext): OpenAPIV3_1.PathsObject<{}, {}>;
|
|
137
103
|
|
|
138
104
|
type PromiseOr<T> = T | Promise<T>;
|
|
@@ -155,13 +121,17 @@ type HandlerUniqueProperty = (ResolverReturnType & {
|
|
|
155
121
|
type MediaTypeObjectWithResolver = Omit<OpenAPIV3_1.MediaTypeObject, "schema"> & {
|
|
156
122
|
schema?: OpenAPIV3_1.ReferenceObject | OpenAPIV3_1.SchemaObject | ResolverReturnType;
|
|
157
123
|
};
|
|
124
|
+
type ContentWithResolver = {
|
|
125
|
+
[media: string]: MediaTypeObjectWithResolver;
|
|
126
|
+
};
|
|
158
127
|
/**
|
|
159
128
|
* A response object that accepts resolver() output in schema positions.
|
|
160
129
|
*/
|
|
161
130
|
type ResponseObjectWithResolver = (Omit<OpenAPIV3_1.ResponseObject, "content"> & {
|
|
162
|
-
content?:
|
|
163
|
-
|
|
164
|
-
|
|
131
|
+
content?: ContentWithResolver;
|
|
132
|
+
}) | OpenAPIV3_1.ReferenceObject;
|
|
133
|
+
type RequestBodyObjectWithResolver = (Omit<OpenAPIV3_1.RequestBodyObject, "content"> & {
|
|
134
|
+
content: ContentWithResolver;
|
|
165
135
|
}) | OpenAPIV3_1.ReferenceObject;
|
|
166
136
|
/**
|
|
167
137
|
* A responses map that accepts resolver() output in schema positions.
|
|
@@ -214,10 +184,23 @@ type GenerateSpecOptions = {
|
|
|
214
184
|
* Default options for `describeRoute` method
|
|
215
185
|
*/
|
|
216
186
|
defaultOptions: Partial<Record<AllowedMethods | "ALL", DescribeRouteOptions>>;
|
|
187
|
+
/**
|
|
188
|
+
* Automatically include a 400 validation error response for routes
|
|
189
|
+
* that use `validator()`. Set to `false` to disable, `true` to use
|
|
190
|
+
* the built-in schema, or provide a custom `ResponseObject`.
|
|
191
|
+
*
|
|
192
|
+
* @default true
|
|
193
|
+
*/
|
|
194
|
+
defaultValidationErrorResponse: boolean | OpenAPIV3_1.ResponseObject;
|
|
217
195
|
};
|
|
218
196
|
type OperationId = string | ((route: RouterRoute) => string);
|
|
219
|
-
type DescribeRouteOptions = Omit<OpenAPIV3_1.OperationObject, "responses" | "operationId"> & {
|
|
197
|
+
type DescribeRouteOptions = Omit<OpenAPIV3_1.OperationObject, "requestBody" | "responses" | "operationId"> & {
|
|
220
198
|
operationId?: OperationId;
|
|
199
|
+
/**
|
|
200
|
+
* Request body metadata. `resolver()` values are converted to OpenAPI
|
|
201
|
+
* schemas while generating the document.
|
|
202
|
+
*/
|
|
203
|
+
requestBody?: RequestBodyObjectWithResolver;
|
|
221
204
|
/**
|
|
222
205
|
* Pass `true` to hide route from OpenAPI/swagger document
|
|
223
206
|
*/
|
|
@@ -238,11 +221,12 @@ type RegisterSchemaPathOptions = {
|
|
|
238
221
|
};
|
|
239
222
|
paths: Partial<OpenAPIV3_1.PathsObject>;
|
|
240
223
|
};
|
|
241
|
-
type HaveDefaultValues = "documentation" | "excludeStaticFile" | "exclude" | "excludeMethods" | "excludeTags";
|
|
224
|
+
type HaveDefaultValues = "documentation" | "excludeStaticFile" | "exclude" | "excludeMethods" | "excludeTags" | "defaultValidationErrorResponse";
|
|
242
225
|
type SanitizedGenerateSpecOptions = Pick<GenerateSpecOptions, HaveDefaultValues> & Omit<Partial<GenerateSpecOptions>, HaveDefaultValues>;
|
|
243
226
|
type SpecContext = {
|
|
244
227
|
components: OpenAPIV3_1.ComponentsObject;
|
|
245
228
|
options: SanitizedGenerateSpecOptions;
|
|
229
|
+
validationErrorResponse?: OpenAPIV3_1.ResponseObject;
|
|
246
230
|
};
|
|
247
231
|
|
|
248
232
|
/**
|
|
@@ -295,4 +279,4 @@ declare function generateSpecs<E extends Env = BlankEnv, P extends string = stri
|
|
|
295
279
|
jsonSchemaDialect?: string;
|
|
296
280
|
}>;
|
|
297
281
|
|
|
298
|
-
export { ALLOWED_METHODS, type AllowedMethods, type DescribeRouteOptions, type GenerateSpecOptions, type HandlerUniqueProperty, type PromiseOr, type RegisterSchemaPathOptions, type ResolverReturnType, type ResponsesWithResolver, type SpecContext, clearSpecsContext, describeResponse, describeRoute, generateSpecs, loadVendor, openAPIRouteHandler, registerSchemaPath, removeExcludedPaths, resolver, uniqueSymbol, validator };
|
|
282
|
+
export { ALLOWED_METHODS, type AllowedMethods, type ContentWithResolver, type DescribeRouteOptions, type GenerateSpecOptions, type HandlerUniqueProperty, type PromiseOr, type RegisterSchemaPathOptions, type ResolverReturnType, type ResponsesWithResolver, type SpecContext, VALIDATION_MARKER, clearSpecsContext, describeResponse, describeRoute, generateSpecs, loadVendor, openAPIRouteHandler, registerSchemaPath, removeExcludedPaths, resolver, uniqueSymbol, validator };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,72 +1,17 @@
|
|
|
1
1
|
import * as openapi_types from 'openapi-types';
|
|
2
2
|
import { OpenAPIV3_1 } from 'openapi-types';
|
|
3
|
+
import * as hono from 'hono';
|
|
3
4
|
import { Env, Input, Context, Next, MiddlewareHandler, ValidationTargets, Hono } from 'hono';
|
|
4
5
|
import { TypedResponse, RouterRoute, ValidationTargets as ValidationTargets$1, BlankEnv, Input as Input$1, BlankInput, Schema, BlankSchema, MiddlewareHandler as MiddlewareHandler$1 } from 'hono/types';
|
|
5
6
|
import { loadVendor as loadVendor$2, ToOpenAPISchemaContext } from '@standard-community/standard-openapi';
|
|
6
7
|
import { Hook } from '@hono/standard-validator';
|
|
7
8
|
import { loadVendor as loadVendor$1 } from '@standard-community/standard-json';
|
|
9
|
+
import { StandardSchemaV1 } from '@standard-schema/spec';
|
|
8
10
|
import { StatusCode } from 'hono/utils/http-status';
|
|
9
11
|
import { JSONParsed } from 'hono/utils/types';
|
|
10
12
|
import { InferInput } from 'hono/validator';
|
|
11
13
|
import { JSONSchema7 } from 'json-schema';
|
|
12
14
|
|
|
13
|
-
/** The Standard Schema interface. */
|
|
14
|
-
interface StandardSchemaV1<Input = unknown, Output = Input> {
|
|
15
|
-
/** The Standard Schema properties. */
|
|
16
|
-
readonly "~standard": StandardSchemaV1.Props<Input, Output>;
|
|
17
|
-
}
|
|
18
|
-
declare namespace StandardSchemaV1 {
|
|
19
|
-
/** The Standard Schema properties interface. */
|
|
20
|
-
export interface Props<Input = unknown, Output = Input> {
|
|
21
|
-
/** The version number of the standard. */
|
|
22
|
-
readonly version: 1;
|
|
23
|
-
/** The vendor name of the schema library. */
|
|
24
|
-
readonly vendor: string;
|
|
25
|
-
/** Validates unknown input values. */
|
|
26
|
-
readonly validate: (value: unknown) => Result<Output> | Promise<Result<Output>>;
|
|
27
|
-
/** Inferred types associated with the schema. */
|
|
28
|
-
readonly types?: Types<Input, Output> | undefined;
|
|
29
|
-
}
|
|
30
|
-
/** The result interface of the validate function. */
|
|
31
|
-
export type Result<Output> = SuccessResult<Output> | FailureResult;
|
|
32
|
-
/** The result interface if validation succeeds. */
|
|
33
|
-
export interface SuccessResult<Output> {
|
|
34
|
-
/** The typed output value. */
|
|
35
|
-
readonly value: Output;
|
|
36
|
-
/** The non-existent issues. */
|
|
37
|
-
readonly issues?: undefined;
|
|
38
|
-
}
|
|
39
|
-
/** The result interface if validation fails. */
|
|
40
|
-
export interface FailureResult {
|
|
41
|
-
/** The issues of failed validation. */
|
|
42
|
-
readonly issues: ReadonlyArray<Issue>;
|
|
43
|
-
}
|
|
44
|
-
/** The issue interface of the failure output. */
|
|
45
|
-
export interface Issue {
|
|
46
|
-
/** The error message of the issue. */
|
|
47
|
-
readonly message: string;
|
|
48
|
-
/** The path of the issue, if any. */
|
|
49
|
-
readonly path?: ReadonlyArray<PropertyKey | PathSegment> | undefined;
|
|
50
|
-
}
|
|
51
|
-
/** The path segment interface of the issue. */
|
|
52
|
-
export interface PathSegment {
|
|
53
|
-
/** The key representing a path segment. */
|
|
54
|
-
readonly key: PropertyKey;
|
|
55
|
-
}
|
|
56
|
-
/** The Standard Schema types interface. */
|
|
57
|
-
export interface Types<Input = unknown, Output = Input> {
|
|
58
|
-
/** The input type of the schema. */
|
|
59
|
-
readonly input: Input;
|
|
60
|
-
/** The output type of the schema. */
|
|
61
|
-
readonly output: Output;
|
|
62
|
-
}
|
|
63
|
-
/** Infers the input type of a Standard Schema. */
|
|
64
|
-
export type InferInput<Schema extends StandardSchemaV1> = NonNullable<Schema["~standard"]["types"]>["input"];
|
|
65
|
-
/** Infers the output type of a Standard Schema. */
|
|
66
|
-
export type InferOutput<Schema extends StandardSchemaV1> = NonNullable<Schema["~standard"]["types"]>["output"];
|
|
67
|
-
export { };
|
|
68
|
-
}
|
|
69
|
-
|
|
70
15
|
declare function loadVendor(vendor: string, fn: {
|
|
71
16
|
toJSONSchema?: Parameters<typeof loadVendor$1>[1];
|
|
72
17
|
toOpenAPISchema?: Parameters<typeof loadVendor$2>[1];
|
|
@@ -129,10 +74,31 @@ declare function describeResponse<E extends Env, P extends string, I extends Inp
|
|
|
129
74
|
* The unique symbol for the middlewares, which makes it easier to identify them. Not meant to be used directly, unless you're creating a custom middleware.
|
|
130
75
|
*/
|
|
131
76
|
declare const uniqueSymbol: unique symbol;
|
|
77
|
+
/**
|
|
78
|
+
* Internal marker key set on an operation's spec when it is produced by a
|
|
79
|
+
* `validator()` middleware. It is used to decide whether to auto-inject the
|
|
80
|
+
* default 400 validation error response, and is stripped from the operation
|
|
81
|
+
* before the spec is emitted. Must be an enumerable string key so it survives
|
|
82
|
+
* the `Object.entries`-based merge in `mergeSpecs`.
|
|
83
|
+
*/
|
|
84
|
+
declare const VALIDATION_MARKER = "__HonoOpenAPIValidator__";
|
|
132
85
|
declare const ALLOWED_METHODS: readonly ["GET", "PUT", "POST", "DELETE", "OPTIONS", "HEAD", "PATCH", "TRACE"];
|
|
133
86
|
type AllowedMethods = (typeof ALLOWED_METHODS)[number];
|
|
134
87
|
declare function clearSpecsContext(): void;
|
|
135
|
-
declare function registerSchemaPath({ route, specs, paths
|
|
88
|
+
declare function registerSchemaPath({ route, specs, paths }: RegisterSchemaPathOptions, pathContext?: Map<string, Omit<OpenAPIV3_1.OperationObject<{}>, "operationId" | "requestBody" | "responses"> & {
|
|
89
|
+
operationId?: string | ((route: RouterRoute) => string);
|
|
90
|
+
requestBody?: OpenAPIV3_1.ReferenceObject | (Omit<OpenAPIV3_1.RequestBodyObject, "content"> & {
|
|
91
|
+
content: ContentWithResolver;
|
|
92
|
+
});
|
|
93
|
+
hide?: boolean | ((props: {
|
|
94
|
+
c?: hono.Context;
|
|
95
|
+
method: string;
|
|
96
|
+
path: string;
|
|
97
|
+
}) => boolean);
|
|
98
|
+
responses?: ResponsesWithResolver;
|
|
99
|
+
} & {
|
|
100
|
+
operationId?: string | ((route: RouterRoute) => string);
|
|
101
|
+
}>): void;
|
|
136
102
|
declare function removeExcludedPaths(paths: OpenAPIV3_1.PathsObject, ctx: SpecContext): OpenAPIV3_1.PathsObject<{}, {}>;
|
|
137
103
|
|
|
138
104
|
type PromiseOr<T> = T | Promise<T>;
|
|
@@ -155,13 +121,17 @@ type HandlerUniqueProperty = (ResolverReturnType & {
|
|
|
155
121
|
type MediaTypeObjectWithResolver = Omit<OpenAPIV3_1.MediaTypeObject, "schema"> & {
|
|
156
122
|
schema?: OpenAPIV3_1.ReferenceObject | OpenAPIV3_1.SchemaObject | ResolverReturnType;
|
|
157
123
|
};
|
|
124
|
+
type ContentWithResolver = {
|
|
125
|
+
[media: string]: MediaTypeObjectWithResolver;
|
|
126
|
+
};
|
|
158
127
|
/**
|
|
159
128
|
* A response object that accepts resolver() output in schema positions.
|
|
160
129
|
*/
|
|
161
130
|
type ResponseObjectWithResolver = (Omit<OpenAPIV3_1.ResponseObject, "content"> & {
|
|
162
|
-
content?:
|
|
163
|
-
|
|
164
|
-
|
|
131
|
+
content?: ContentWithResolver;
|
|
132
|
+
}) | OpenAPIV3_1.ReferenceObject;
|
|
133
|
+
type RequestBodyObjectWithResolver = (Omit<OpenAPIV3_1.RequestBodyObject, "content"> & {
|
|
134
|
+
content: ContentWithResolver;
|
|
165
135
|
}) | OpenAPIV3_1.ReferenceObject;
|
|
166
136
|
/**
|
|
167
137
|
* A responses map that accepts resolver() output in schema positions.
|
|
@@ -214,10 +184,23 @@ type GenerateSpecOptions = {
|
|
|
214
184
|
* Default options for `describeRoute` method
|
|
215
185
|
*/
|
|
216
186
|
defaultOptions: Partial<Record<AllowedMethods | "ALL", DescribeRouteOptions>>;
|
|
187
|
+
/**
|
|
188
|
+
* Automatically include a 400 validation error response for routes
|
|
189
|
+
* that use `validator()`. Set to `false` to disable, `true` to use
|
|
190
|
+
* the built-in schema, or provide a custom `ResponseObject`.
|
|
191
|
+
*
|
|
192
|
+
* @default true
|
|
193
|
+
*/
|
|
194
|
+
defaultValidationErrorResponse: boolean | OpenAPIV3_1.ResponseObject;
|
|
217
195
|
};
|
|
218
196
|
type OperationId = string | ((route: RouterRoute) => string);
|
|
219
|
-
type DescribeRouteOptions = Omit<OpenAPIV3_1.OperationObject, "responses" | "operationId"> & {
|
|
197
|
+
type DescribeRouteOptions = Omit<OpenAPIV3_1.OperationObject, "requestBody" | "responses" | "operationId"> & {
|
|
220
198
|
operationId?: OperationId;
|
|
199
|
+
/**
|
|
200
|
+
* Request body metadata. `resolver()` values are converted to OpenAPI
|
|
201
|
+
* schemas while generating the document.
|
|
202
|
+
*/
|
|
203
|
+
requestBody?: RequestBodyObjectWithResolver;
|
|
221
204
|
/**
|
|
222
205
|
* Pass `true` to hide route from OpenAPI/swagger document
|
|
223
206
|
*/
|
|
@@ -238,11 +221,12 @@ type RegisterSchemaPathOptions = {
|
|
|
238
221
|
};
|
|
239
222
|
paths: Partial<OpenAPIV3_1.PathsObject>;
|
|
240
223
|
};
|
|
241
|
-
type HaveDefaultValues = "documentation" | "excludeStaticFile" | "exclude" | "excludeMethods" | "excludeTags";
|
|
224
|
+
type HaveDefaultValues = "documentation" | "excludeStaticFile" | "exclude" | "excludeMethods" | "excludeTags" | "defaultValidationErrorResponse";
|
|
242
225
|
type SanitizedGenerateSpecOptions = Pick<GenerateSpecOptions, HaveDefaultValues> & Omit<Partial<GenerateSpecOptions>, HaveDefaultValues>;
|
|
243
226
|
type SpecContext = {
|
|
244
227
|
components: OpenAPIV3_1.ComponentsObject;
|
|
245
228
|
options: SanitizedGenerateSpecOptions;
|
|
229
|
+
validationErrorResponse?: OpenAPIV3_1.ResponseObject;
|
|
246
230
|
};
|
|
247
231
|
|
|
248
232
|
/**
|
|
@@ -295,4 +279,4 @@ declare function generateSpecs<E extends Env = BlankEnv, P extends string = stri
|
|
|
295
279
|
jsonSchemaDialect?: string;
|
|
296
280
|
}>;
|
|
297
281
|
|
|
298
|
-
export { ALLOWED_METHODS, type AllowedMethods, type DescribeRouteOptions, type GenerateSpecOptions, type HandlerUniqueProperty, type PromiseOr, type RegisterSchemaPathOptions, type ResolverReturnType, type ResponsesWithResolver, type SpecContext, clearSpecsContext, describeResponse, describeRoute, generateSpecs, loadVendor, openAPIRouteHandler, registerSchemaPath, removeExcludedPaths, resolver, uniqueSymbol, validator };
|
|
282
|
+
export { ALLOWED_METHODS, type AllowedMethods, type ContentWithResolver, type DescribeRouteOptions, type GenerateSpecOptions, type HandlerUniqueProperty, type PromiseOr, type RegisterSchemaPathOptions, type ResolverReturnType, type ResponsesWithResolver, type SpecContext, VALIDATION_MARKER, clearSpecsContext, describeResponse, describeRoute, generateSpecs, loadVendor, openAPIRouteHandler, registerSchemaPath, removeExcludedPaths, resolver, uniqueSymbol, validator };
|
package/dist/index.js
CHANGED
|
@@ -4,6 +4,7 @@ import { loadVendor as loadVendor$1, toJsonSchema } from '@standard-community/st
|
|
|
4
4
|
import { loadVendor as loadVendor$2, toOpenAPISchema } from '@standard-community/standard-openapi';
|
|
5
5
|
|
|
6
6
|
const uniqueSymbol = Symbol("openapi");
|
|
7
|
+
const VALIDATION_MARKER = "__HonoOpenAPIValidator__";
|
|
7
8
|
const ALLOWED_METHODS = [
|
|
8
9
|
"GET",
|
|
9
10
|
"PUT",
|
|
@@ -53,10 +54,12 @@ function mergeParameters(...params) {
|
|
|
53
54
|
return Array.from(merged.values());
|
|
54
55
|
}
|
|
55
56
|
const specsByPathContext = /* @__PURE__ */ new Map();
|
|
56
|
-
function getPathContext(path) {
|
|
57
|
+
function getPathContext(path, pathContext) {
|
|
57
58
|
const context = [];
|
|
58
|
-
for (const [key, data] of
|
|
59
|
-
if (data
|
|
59
|
+
for (const [key, data] of pathContext) {
|
|
60
|
+
if (!data) continue;
|
|
61
|
+
const prefix = key.endsWith("/*") ? key.slice(0, -2) : key;
|
|
62
|
+
if (path === prefix || path.startsWith(`${prefix}/`)) {
|
|
60
63
|
context.push(data);
|
|
61
64
|
}
|
|
62
65
|
}
|
|
@@ -65,6 +68,19 @@ function getPathContext(path) {
|
|
|
65
68
|
function clearSpecsContext() {
|
|
66
69
|
specsByPathContext.clear();
|
|
67
70
|
}
|
|
71
|
+
function mergeRequestBodies(previous, current) {
|
|
72
|
+
if (!previous || !current || "$ref" in previous || "$ref" in current) {
|
|
73
|
+
return current;
|
|
74
|
+
}
|
|
75
|
+
return {
|
|
76
|
+
...previous,
|
|
77
|
+
...current,
|
|
78
|
+
content: {
|
|
79
|
+
...previous.content,
|
|
80
|
+
...current.content
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
}
|
|
68
84
|
function mergeSpecs(route, ...specs) {
|
|
69
85
|
return specs.reduce(
|
|
70
86
|
(prev, spec) => {
|
|
@@ -86,6 +102,11 @@ function mergeSpecs(route, ...specs) {
|
|
|
86
102
|
} else {
|
|
87
103
|
if (key === "parameters") {
|
|
88
104
|
prev[key] = mergeParameters(prev[key], value);
|
|
105
|
+
} else if (key === "requestBody") {
|
|
106
|
+
prev.requestBody = mergeRequestBodies(
|
|
107
|
+
prev.requestBody,
|
|
108
|
+
value
|
|
109
|
+
);
|
|
89
110
|
} else {
|
|
90
111
|
prev[key] = {
|
|
91
112
|
...prev[key],
|
|
@@ -104,30 +125,26 @@ function mergeSpecs(route, ...specs) {
|
|
|
104
125
|
}
|
|
105
126
|
);
|
|
106
127
|
}
|
|
107
|
-
function registerSchemaPath({
|
|
108
|
-
route,
|
|
109
|
-
specs,
|
|
110
|
-
paths
|
|
111
|
-
}) {
|
|
128
|
+
function registerSchemaPath({ route, specs, paths }, pathContext = specsByPathContext) {
|
|
112
129
|
const path = toOpenAPIPath(route.path);
|
|
113
130
|
const method = route.method.toLowerCase();
|
|
114
131
|
if (method === "all") {
|
|
115
132
|
if (!specs) return;
|
|
116
|
-
if (
|
|
117
|
-
const prev =
|
|
118
|
-
|
|
133
|
+
if (pathContext.has(path)) {
|
|
134
|
+
const prev = pathContext.get(path) ?? {};
|
|
135
|
+
pathContext.set(path, mergeSpecs(route, prev, specs));
|
|
119
136
|
} else {
|
|
120
|
-
|
|
137
|
+
pathContext.set(path, specs);
|
|
121
138
|
}
|
|
122
139
|
} else {
|
|
123
|
-
const
|
|
140
|
+
const context = getPathContext(path, pathContext);
|
|
124
141
|
if (!(path in paths)) {
|
|
125
142
|
paths[path] = {};
|
|
126
143
|
}
|
|
127
144
|
if (paths[path]) {
|
|
128
145
|
paths[path][method] = mergeSpecs(
|
|
129
146
|
route,
|
|
130
|
-
...
|
|
147
|
+
...context,
|
|
131
148
|
paths[path]?.[method],
|
|
132
149
|
specs
|
|
133
150
|
);
|
|
@@ -157,6 +174,8 @@ function removeExcludedPaths(paths, ctx) {
|
|
|
157
174
|
for (const method of Object.keys(value)) {
|
|
158
175
|
const schema = value[method];
|
|
159
176
|
if (schema == null) continue;
|
|
177
|
+
const hasValidation = schema[VALIDATION_MARKER] === true;
|
|
178
|
+
delete schema[VALIDATION_MARKER];
|
|
160
179
|
if (key.includes("{")) {
|
|
161
180
|
schema.parameters = schema.parameters ? [...schema.parameters] : [];
|
|
162
181
|
const pathParameters = key.split("/").filter(
|
|
@@ -196,6 +215,16 @@ function removeExcludedPaths(paths, ctx) {
|
|
|
196
215
|
200: {}
|
|
197
216
|
};
|
|
198
217
|
}
|
|
218
|
+
if (hasValidation && ctx.options.defaultValidationErrorResponse !== false && !schema.responses["400"]) {
|
|
219
|
+
const errorResponse = ctx.options.defaultValidationErrorResponse;
|
|
220
|
+
if (typeof errorResponse === "object") {
|
|
221
|
+
schema.responses["400"] = structuredClone(errorResponse);
|
|
222
|
+
} else if (ctx.validationErrorResponse) {
|
|
223
|
+
schema.responses["400"] = structuredClone(
|
|
224
|
+
ctx.validationErrorResponse
|
|
225
|
+
);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
199
228
|
}
|
|
200
229
|
const filteredValue = {};
|
|
201
230
|
for (const method of Object.keys(value)) {
|
|
@@ -215,7 +244,27 @@ const DEFAULT_OPTIONS = {
|
|
|
215
244
|
excludeStaticFile: true,
|
|
216
245
|
exclude: [],
|
|
217
246
|
excludeMethods: ["OPTIONS"],
|
|
218
|
-
excludeTags: []
|
|
247
|
+
excludeTags: [],
|
|
248
|
+
defaultValidationErrorResponse: true
|
|
249
|
+
};
|
|
250
|
+
const DEFAULT_VALIDATION_ERROR = {
|
|
251
|
+
description: "Validation Error",
|
|
252
|
+
content: {
|
|
253
|
+
"application/json": {
|
|
254
|
+
schema: {
|
|
255
|
+
type: "object",
|
|
256
|
+
properties: {
|
|
257
|
+
success: { type: "boolean", enum: [false] },
|
|
258
|
+
error: {
|
|
259
|
+
type: "array",
|
|
260
|
+
items: {}
|
|
261
|
+
},
|
|
262
|
+
data: {}
|
|
263
|
+
},
|
|
264
|
+
required: ["success", "error", "data"]
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
}
|
|
219
268
|
};
|
|
220
269
|
function openAPIRouteHandler(hono, options) {
|
|
221
270
|
let specs;
|
|
@@ -232,10 +281,14 @@ async function generateSpecs(hono, options = DEFAULT_OPTIONS, c) {
|
|
|
232
281
|
options: {
|
|
233
282
|
...DEFAULT_OPTIONS,
|
|
234
283
|
...options
|
|
235
|
-
}
|
|
284
|
+
},
|
|
285
|
+
validationErrorResponse: DEFAULT_VALIDATION_ERROR
|
|
236
286
|
};
|
|
237
287
|
const _documentation = ctx.options.documentation ?? {};
|
|
238
|
-
|
|
288
|
+
const documentation = {
|
|
289
|
+
..._documentation,
|
|
290
|
+
components: _documentation.components && { ..._documentation.components }
|
|
291
|
+
};
|
|
239
292
|
const paths = await generatePaths(hono, ctx);
|
|
240
293
|
for (const path in paths) {
|
|
241
294
|
for (const method in paths[path]) {
|
|
@@ -250,41 +303,48 @@ async function generateSpecs(hono, options = DEFAULT_OPTIONS, c) {
|
|
|
250
303
|
}
|
|
251
304
|
}
|
|
252
305
|
}
|
|
253
|
-
const
|
|
306
|
+
const resolvedDocumentation = documentation.components?.responses ? await resolveResponseSchemas(documentation.components.responses) : void 0;
|
|
307
|
+
if (resolvedDocumentation && documentation.components) {
|
|
308
|
+
documentation.components.responses = resolvedDocumentation.responses;
|
|
309
|
+
}
|
|
254
310
|
const components = mergeComponentsObjects(
|
|
255
|
-
|
|
256
|
-
|
|
311
|
+
documentation.components,
|
|
312
|
+
resolvedDocumentation?.components,
|
|
257
313
|
ctx.components
|
|
258
314
|
);
|
|
259
315
|
return {
|
|
260
316
|
openapi: "3.1.0",
|
|
261
|
-
...
|
|
262
|
-
tags:
|
|
317
|
+
...documentation,
|
|
318
|
+
tags: documentation.tags?.filter(
|
|
263
319
|
(tag) => !ctx.options.excludeTags?.includes(tag?.name)
|
|
264
320
|
),
|
|
265
321
|
info: {
|
|
266
322
|
title: "Hono Documentation",
|
|
267
323
|
description: "Development documentation",
|
|
268
324
|
version: "0.0.0",
|
|
269
|
-
...
|
|
325
|
+
...documentation.info
|
|
270
326
|
},
|
|
271
327
|
paths: {
|
|
272
328
|
...removeExcludedPaths(paths, ctx),
|
|
273
|
-
...
|
|
329
|
+
...documentation.paths
|
|
274
330
|
},
|
|
275
331
|
components
|
|
276
332
|
};
|
|
277
333
|
}
|
|
278
334
|
async function generatePaths(hono, ctx) {
|
|
279
335
|
const paths = {};
|
|
336
|
+
const pathContext = /* @__PURE__ */ new Map();
|
|
280
337
|
for (const route of hono.routes) {
|
|
281
338
|
const middlewareHandler = findTargetHandler(route.handler)[uniqueSymbol];
|
|
282
339
|
if (!middlewareHandler) {
|
|
283
340
|
if (ctx.options.includeEmptyPaths) {
|
|
284
|
-
registerSchemaPath(
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
341
|
+
registerSchemaPath(
|
|
342
|
+
{
|
|
343
|
+
route,
|
|
344
|
+
paths
|
|
345
|
+
},
|
|
346
|
+
pathContext
|
|
347
|
+
);
|
|
288
348
|
}
|
|
289
349
|
continue;
|
|
290
350
|
}
|
|
@@ -300,14 +360,18 @@ async function generatePaths(hono, ctx) {
|
|
|
300
360
|
const defaultOptionsForThisMethod = ctx.options.defaultOptions?.[routeMethod] && { ...ctx.options.defaultOptions[routeMethod] };
|
|
301
361
|
const { schema: routeSpecs, components = {} } = await getSpec(
|
|
302
362
|
middlewareHandler,
|
|
303
|
-
defaultOptionsForThisMethod
|
|
363
|
+
defaultOptionsForThisMethod,
|
|
364
|
+
ctx.components.parameters
|
|
304
365
|
);
|
|
305
366
|
ctx.components = mergeComponentsObjects(ctx.components, components);
|
|
306
|
-
registerSchemaPath(
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
367
|
+
registerSchemaPath(
|
|
368
|
+
{
|
|
369
|
+
route,
|
|
370
|
+
specs: routeSpecs,
|
|
371
|
+
paths
|
|
372
|
+
},
|
|
373
|
+
pathContext
|
|
374
|
+
);
|
|
311
375
|
}
|
|
312
376
|
return paths;
|
|
313
377
|
}
|
|
@@ -323,7 +387,7 @@ function getHiddenValue(options) {
|
|
|
323
387
|
}
|
|
324
388
|
return false;
|
|
325
389
|
}
|
|
326
|
-
async function getSpec(middlewareHandler, defaultOptions) {
|
|
390
|
+
async function getSpec(middlewareHandler, defaultOptions, parameterComponents) {
|
|
327
391
|
if ("spec" in middlewareHandler) {
|
|
328
392
|
const tmp = {
|
|
329
393
|
...defaultOptions,
|
|
@@ -336,14 +400,29 @@ async function getSpec(middlewareHandler, defaultOptions) {
|
|
|
336
400
|
let components = {};
|
|
337
401
|
if (tmp.responses) {
|
|
338
402
|
const resolved = await resolveResponseSchemas(tmp.responses);
|
|
403
|
+
tmp.responses = resolved.responses;
|
|
339
404
|
components = resolved.components;
|
|
340
405
|
}
|
|
406
|
+
if (tmp.requestBody && "content" in tmp.requestBody) {
|
|
407
|
+
const resolved = await resolveContentSchemas(tmp.requestBody.content);
|
|
408
|
+
tmp.requestBody = {
|
|
409
|
+
...tmp.requestBody,
|
|
410
|
+
content: resolved.content
|
|
411
|
+
};
|
|
412
|
+
components = mergeComponentsObjects(components, resolved.components);
|
|
413
|
+
}
|
|
341
414
|
return { schema: tmp, components };
|
|
342
415
|
}
|
|
343
416
|
const result = await middlewareHandler.toOpenAPISchema();
|
|
344
|
-
|
|
417
|
+
liftSchemaDefs(result);
|
|
418
|
+
const docs = {
|
|
419
|
+
...defaultOptions,
|
|
420
|
+
// Mark this operation as validator-derived so a default 400 validation
|
|
421
|
+
// error response can be auto-injected later (see removeExcludedPaths).
|
|
422
|
+
[VALIDATION_MARKER]: true
|
|
423
|
+
};
|
|
345
424
|
if (middlewareHandler.target === "form" || middlewareHandler.target === "json") {
|
|
346
|
-
const media = middlewareHandler.options?.media ?? middlewareHandler.target === "json" ? "application/json" : "multipart/form-data";
|
|
425
|
+
const media = middlewareHandler.options?.media ?? (middlewareHandler.target === "json" ? "application/json" : "multipart/form-data");
|
|
347
426
|
if (!docs.requestBody || !("content" in docs.requestBody) || !docs.requestBody.content) {
|
|
348
427
|
docs.requestBody = {
|
|
349
428
|
required: true,
|
|
@@ -365,65 +444,130 @@ async function getSpec(middlewareHandler, defaultOptions) {
|
|
|
365
444
|
const pos = ref.split("/").pop();
|
|
366
445
|
if (pos && result.components?.schemas?.[pos]) {
|
|
367
446
|
const schema = result.components.schemas[pos];
|
|
368
|
-
const
|
|
447
|
+
const generatedParameters = generateParameters(
|
|
369
448
|
middlewareHandler.target,
|
|
370
|
-
schema
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
449
|
+
schema,
|
|
450
|
+
result.components.schemas
|
|
451
|
+
);
|
|
452
|
+
const singleParameter = generatedParameters.length === 1 ? generatedParameters[0] : void 0;
|
|
453
|
+
const existingParameter = parameterComponents?.[pos];
|
|
454
|
+
if (singleParameter && (!existingParameter || "in" in existingParameter && existingParameter.in === singleParameter.in && existingParameter.name === singleParameter.name)) {
|
|
455
|
+
result.components.parameters ??= {};
|
|
456
|
+
result.components.parameters[pos] = singleParameter;
|
|
457
|
+
parameters.push({ $ref: `#/components/parameters/${pos}` });
|
|
458
|
+
delete result.components.schemas[pos];
|
|
459
|
+
} else {
|
|
460
|
+
parameters = generatedParameters;
|
|
374
461
|
}
|
|
375
|
-
result.components.parameters[pos] = newParameters;
|
|
376
|
-
delete result.components.schemas[pos];
|
|
377
|
-
parameters.push({
|
|
378
|
-
$ref: `#/components/parameters/${pos}`
|
|
379
|
-
});
|
|
380
462
|
}
|
|
381
463
|
} else {
|
|
382
|
-
parameters = generateParameters(
|
|
464
|
+
parameters = generateParameters(
|
|
465
|
+
middlewareHandler.target,
|
|
466
|
+
result.schema,
|
|
467
|
+
result.components?.schemas
|
|
468
|
+
);
|
|
383
469
|
}
|
|
384
470
|
docs.parameters = parameters;
|
|
385
471
|
}
|
|
386
472
|
return { schema: docs, components: result.components };
|
|
387
473
|
}
|
|
388
|
-
function generateParameters(target, schema) {
|
|
474
|
+
function generateParameters(target, schema, schemas) {
|
|
389
475
|
const parameters = [];
|
|
390
|
-
for (const [key,
|
|
476
|
+
for (const [key, property] of collectParameterProperties(schema, schemas)) {
|
|
391
477
|
const def = {
|
|
392
478
|
in: target === "param" ? "path" : target,
|
|
393
479
|
name: key,
|
|
394
|
-
// @ts-expect-error
|
|
395
|
-
schema:
|
|
480
|
+
// @ts-expect-error ParameterObject uses the OpenAPI 3.0 schema type.
|
|
481
|
+
schema: property.schema
|
|
396
482
|
};
|
|
397
|
-
|
|
398
|
-
if (isRequired) {
|
|
483
|
+
if (property.required) {
|
|
399
484
|
def.required = true;
|
|
400
485
|
}
|
|
401
486
|
if (def.schema && "description" in def.schema && def.schema.description) {
|
|
402
487
|
def.description = def.schema.description;
|
|
403
|
-
def.schema.description
|
|
488
|
+
def.schema = { ...def.schema, description: void 0 };
|
|
404
489
|
}
|
|
405
490
|
parameters.push(def);
|
|
406
491
|
}
|
|
407
492
|
return parameters;
|
|
408
493
|
}
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
494
|
+
function collectParameterProperties(schema, schemas) {
|
|
495
|
+
const properties = /* @__PURE__ */ new Map();
|
|
496
|
+
const resolvingRefs = /* @__PURE__ */ new Set();
|
|
497
|
+
const collect = (current) => {
|
|
498
|
+
for (const [key, value] of Object.entries(current.properties ?? {})) {
|
|
499
|
+
const existing = properties.get(key);
|
|
500
|
+
properties.set(key, {
|
|
501
|
+
schema: existing ? { allOf: [existing.schema, value] } : value,
|
|
502
|
+
required: Boolean(current.required?.includes(key)) || existing?.required
|
|
503
|
+
});
|
|
504
|
+
}
|
|
505
|
+
for (const member of current.allOf ?? []) {
|
|
506
|
+
if ("$ref" in member) {
|
|
507
|
+
const prefix = "#/components/schemas/";
|
|
508
|
+
if (!member.$ref.startsWith(prefix)) continue;
|
|
509
|
+
const name = member.$ref.slice(prefix.length).replaceAll("~1", "/").replaceAll("~0", "~");
|
|
510
|
+
const referencedSchema = schemas?.[name];
|
|
511
|
+
if (referencedSchema && !resolvingRefs.has(name)) {
|
|
512
|
+
resolvingRefs.add(name);
|
|
513
|
+
collect(referencedSchema);
|
|
514
|
+
resolvingRefs.delete(name);
|
|
422
515
|
}
|
|
516
|
+
} else {
|
|
517
|
+
collect(member);
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
};
|
|
521
|
+
collect(schema);
|
|
522
|
+
return properties;
|
|
523
|
+
}
|
|
524
|
+
async function resolveContentSchemas(content) {
|
|
525
|
+
let components = {};
|
|
526
|
+
const resolvedContent = {};
|
|
527
|
+
for (const [contentKey, raw] of Object.entries(content)) {
|
|
528
|
+
if (!raw) continue;
|
|
529
|
+
if (raw.schema && "toOpenAPISchema" in raw.schema) {
|
|
530
|
+
const result = await raw.schema.toOpenAPISchema();
|
|
531
|
+
liftSchemaDefs(result);
|
|
532
|
+
resolvedContent[contentKey] = {
|
|
533
|
+
...raw,
|
|
534
|
+
schema: result.schema
|
|
535
|
+
};
|
|
536
|
+
if (result.components) {
|
|
537
|
+
components = mergeComponentsObjects(components, result.components);
|
|
423
538
|
}
|
|
539
|
+
} else {
|
|
540
|
+
resolvedContent[contentKey] = raw;
|
|
424
541
|
}
|
|
425
542
|
}
|
|
426
|
-
return {
|
|
543
|
+
return { content: resolvedContent, components };
|
|
544
|
+
}
|
|
545
|
+
async function resolveResponseSchemas(responses) {
|
|
546
|
+
let components = {};
|
|
547
|
+
const resolvedResponses = {};
|
|
548
|
+
for (const [key, response] of Object.entries(responses)) {
|
|
549
|
+
if (!response || !("content" in response) || !response.content) {
|
|
550
|
+
resolvedResponses[key] = response;
|
|
551
|
+
continue;
|
|
552
|
+
}
|
|
553
|
+
const resolved = await resolveContentSchemas(response.content);
|
|
554
|
+
resolvedResponses[key] = {
|
|
555
|
+
...response,
|
|
556
|
+
content: resolved.content
|
|
557
|
+
};
|
|
558
|
+
components = mergeComponentsObjects(components, resolved.components);
|
|
559
|
+
}
|
|
560
|
+
return { responses: resolvedResponses, components };
|
|
561
|
+
}
|
|
562
|
+
function liftSchemaDefs(result) {
|
|
563
|
+
const defs = result.schema.$defs;
|
|
564
|
+
if (!defs || typeof defs !== "object") return;
|
|
565
|
+
result.components ??= {};
|
|
566
|
+
result.components.schemas = {
|
|
567
|
+
...defs,
|
|
568
|
+
...result.components.schemas
|
|
569
|
+
};
|
|
570
|
+
delete result.schema.$defs;
|
|
427
571
|
}
|
|
428
572
|
function mergeComponentsObjects(...components) {
|
|
429
573
|
return components.reduce(
|
|
@@ -568,4 +712,4 @@ function describeResponse(handler, responses, options) {
|
|
|
568
712
|
});
|
|
569
713
|
}
|
|
570
714
|
|
|
571
|
-
export { ALLOWED_METHODS, clearSpecsContext, describeResponse, describeRoute, generateSpecs, loadVendor, openAPIRouteHandler, registerSchemaPath, removeExcludedPaths, resolver, uniqueSymbol, validator };
|
|
715
|
+
export { ALLOWED_METHODS, VALIDATION_MARKER, clearSpecsContext, describeResponse, describeRoute, generateSpecs, loadVendor, openAPIRouteHandler, registerSchemaPath, removeExcludedPaths, resolver, uniqueSymbol, validator };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hono-openapi",
|
|
3
3
|
"description": "OpenAPI schema generator for Hono",
|
|
4
|
-
"version": "1.3.
|
|
4
|
+
"version": "1.3.3",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.cjs",
|
|
7
7
|
"module": "dist/index.js",
|
|
@@ -40,28 +40,22 @@
|
|
|
40
40
|
"default": "./dist/index.cjs"
|
|
41
41
|
}
|
|
42
42
|
},
|
|
43
|
-
"
|
|
44
|
-
"@hono/standard-validator": "^0.
|
|
43
|
+
"dependencies": {
|
|
44
|
+
"@hono/standard-validator": "^0.4.0",
|
|
45
45
|
"@standard-community/standard-json": "^0.3.5",
|
|
46
46
|
"@standard-community/standard-openapi": "^0.2.9",
|
|
47
|
+
"@standard-schema/spec": "^1.0.0",
|
|
47
48
|
"@types/json-schema": "^7.0.15",
|
|
48
|
-
"hono": "^4.11.2",
|
|
49
49
|
"openapi-types": "^12.1.3"
|
|
50
50
|
},
|
|
51
|
-
"
|
|
52
|
-
"
|
|
53
|
-
"optional": true
|
|
54
|
-
},
|
|
55
|
-
"hono": {
|
|
56
|
-
"optional": true
|
|
57
|
-
}
|
|
51
|
+
"peerDependencies": {
|
|
52
|
+
"hono": "^4.11.2"
|
|
58
53
|
},
|
|
59
54
|
"devDependencies": {
|
|
60
55
|
"@biomejs/biome": "^2.0.6",
|
|
61
|
-
"@standard-schema/spec": "^1.0.0",
|
|
62
56
|
"@valibot/to-json-schema": "^1.3.0",
|
|
63
57
|
"arktype": "^2.1.22",
|
|
64
|
-
"effect": "^3.17.
|
|
58
|
+
"effect": "^3.17.14",
|
|
65
59
|
"husky": "^9.1.7",
|
|
66
60
|
"is-ci": "^4.1.0",
|
|
67
61
|
"nano-staged": "^0.8.0",
|