hono-openapi 0.4.5 → 0.4.6
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 +1 -1
- package/arktype.cjs +1 -1
- package/arktype.js +1 -1
- package/effect.cjs +1 -1
- package/effect.js +1 -1
- package/index.cjs +1 -1
- package/index.js +1 -1
- package/package.json +1 -1
- package/src/types.d.ts +8 -2
- package/typebox.cjs +1 -1
- package/typebox.js +1 -1
- package/valibot.cjs +1 -1
- package/valibot.js +1 -1
package/README.md
CHANGED
|
@@ -144,7 +144,7 @@ app.get(
|
|
|
144
144
|
Now, you can access the OpenAPI specification by visiting `http://localhost:3000/openapi`, and you can use this specification to generate client libraries, documentation, and more. Some tools that I used to generate documentation are -
|
|
145
145
|
|
|
146
146
|
- [Swagger UI](https://github.com/honojs/middleware/tree/main/packages/swagger-ui)
|
|
147
|
-
- [Scalar](https://
|
|
147
|
+
- [Scalar](https://www.npmjs.com/package/@scalar/hono-api-reference)
|
|
148
148
|
|
|
149
149
|
##### Scalar Example
|
|
150
150
|
|
package/arktype.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var e=require("@hono/arktype-validator"),r=require("./toOpenAPISchema.cjs"),a=require("./utils.cjs");function t(e){return{builder:async
|
|
1
|
+
"use strict";var e=require("@hono/arktype-validator"),r=require("./toOpenAPISchema.cjs"),a=require("./utils.cjs");function t(e){return{builder:async()=>({schema:await r.convert(e.toJsonSchema())}),validator:r=>{e.assert(r)}}}require("json-schema-walker"),exports.resolver=t,exports.validator=function(r,o,s){const i=e.arktypeValidator(r,o,s);return Object.assign(i,{[a.uniqueSymbol]:{resolver:async e=>a.generateValidatorDocs(r,await t(o).builder(e))}})};
|
package/arktype.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{arktypeValidator as a}from"@hono/arktype-validator";import{c as r}from"./toOpenAPISchema.js";import{u as o,g as t}from"./utils.js";import"json-schema-walker";function s(a){return{builder:async
|
|
1
|
+
import{arktypeValidator as a}from"@hono/arktype-validator";import{c as r}from"./toOpenAPISchema.js";import{u as o,g as t}from"./utils.js";import"json-schema-walker";function s(a){return{builder:async()=>({schema:await r(a.toJsonSchema())}),validator:r=>{a.assert(r)}}}function e(r,e,i){const n=a(r,e,i);return Object.assign(n,{[o]:{resolver:async a=>t(r,await s(e).builder(a))}})}export{s as resolver,e as validator};
|
package/effect.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var e=require("@hono/effect-validator"),r=require("effect"),a=require("./toOpenAPISchema.cjs"),t=require("./utils.cjs");function i(e){return{builder:async
|
|
1
|
+
"use strict";var e=require("@hono/effect-validator"),r=require("effect"),a=require("./toOpenAPISchema.cjs"),t=require("./utils.cjs");function i(e){return{builder:async()=>({schema:await a.convert(r.JSONSchema.make(e))}),validator:async a=>{await r.Schema.decodeUnknownPromise(e)(a)}}}require("json-schema-walker"),exports.resolver=i,exports.validator=function(r,a){const o=e.effectValidator(r,a);return Object.assign(o,{[t.uniqueSymbol]:{resolver:async e=>t.generateValidatorDocs(r,await i(a).builder(e))}})};
|
package/effect.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{effectValidator as o}from"@hono/effect-validator";import{JSONSchema as a,Schema as r}from"effect";import{c as e}from"./toOpenAPISchema.js";import{u as t,g as i}from"./utils.js";import"json-schema-walker";function n(o){return{builder:async
|
|
1
|
+
import{effectValidator as o}from"@hono/effect-validator";import{JSONSchema as a,Schema as r}from"effect";import{c as e}from"./toOpenAPISchema.js";import{u as t,g as i}from"./utils.js";import"json-schema-walker";function n(o){return{builder:async()=>({schema:await e(a.make(o))}),validator:async a=>{await r.decodeUnknownPromise(o)(a)}}}function s(a,r){const e=o(a,r);return Object.assign(e,{[t]:{resolver:async o=>i(a,await n(r).builder(o))}})}export{n as resolver,s as validator};
|
package/index.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var e=require("./utils.cjs"),t=require("hono/http-exception");const
|
|
1
|
+
"use strict";var e=require("./utils.cjs"),t=require("hono/http-exception");const s=["GET","PUT","POST","DELETE","OPTIONS","HEAD","PATCH","TRACE"],n=e=>e.charAt(0).toUpperCase()+e.slice(1),o=new Map,a=(e,t)=>{const s=`${e}:${t}`;if(o.has(s))return o.get(s);let a=e;if("/"===t)return`${a}Index`;for(const e of t.split("/"))123===e.charCodeAt(0)?a+=`By${n(e.slice(1,-1))}`:a+=n(e);return o.set(s,a),a},r=new Map;function c(e,t,s){return e&&t in e?e[t]??s:s}function i(...e){return e.reduce(((e,t)=>{if(!t)return e;let s;return("tags"in e&&e.tags||"tags"in t&&t.tags)&&(s=[...c(e,"tags",[]),...c(t,"tags",[])]),{...e,...t,tags:s,responses:{...c(e,"responses",{}),...c(t,"responses",{})},parameters:u(e.parameters,t.parameters)}}),{})}function p({path:e,method:t,data:s,schema:n}){e=(e=>e.split("/").map((e=>{let t=e;return t.startsWith(":")&&(t=t.slice(1,t.length),t.endsWith("?")&&(t=t.slice(0,-1)),t=`{${t}}`),t})).join("/"))(e);const o=t.toLowerCase();if("all"===o)if(r.has(e)){const t=r.get(e)??{};r.set(e,{...t,...s,parameters:u(t.parameters,s.parameters)})}else r.set(e,s);else{const t=function(e){const t=Array.from(r.keys());let s={};for(const n of t)e.match(n)&&(s=i(s,r.get(n)??{}));return s}(e);n[e]={...n[e]?n[e]:{},[o]:{responses:{},operationId:a(o,e),...i(t,n[e]?.[o],s)}}}}const l=e=>"$ref"in e?e.$ref:`${e.in} ${e.name}`;function u(...e){const t=e.flatMap((e=>e??[])).reduce(((e,t)=>(e.set(l(t),t),e)),new Map);return Array.from(t.values())}function m(e,{excludeStaticFile:t=!0,exclude:s=[]}){const n={},o=Array.isArray(s)?s:[s];for(const[s,a]of Object.entries(e))if(!(o.some((e=>"string"==typeof e?s===e:e.test(s)))||s.includes("*")||t&&s.includes("."))){for(const e of Object.keys(a)){const t=a[e];if(s.includes("{")){t.parameters||(t.parameters=[]);const e=s.split("/").filter((e=>e.startsWith("{")&&!t.parameters.find((t=>"path"===t.in&&t.name===e.slice(1,e.length-1)))));for(const s of e){const e=s.slice(1,s.length-1),n=t.parameters.findIndex((t=>"param"===t.in&&t.name===e));-1!==n?t.parameters[n].in="path":t.parameters.push({schema:{type:"string"},in:"path",name:e,required:!0})}}t.responses||(t.responses={200:{}})}n[s]=a}return n}async function d(t,{documentation:n={},excludeStaticFile:o=!0,exclude:a=[],excludeMethods:r=["OPTIONS"],excludeTags:c=[],defaultOptions:i}={documentation:{},excludeStaticFile:!0,exclude:[],excludeMethods:["OPTIONS"],excludeTags:[]},{version:l="3.1.0",components:u={}}={version:"3.1.0",components:{}},d){const f={version:l,components:u},h={};for(const n of t.routes){if(!(e.uniqueSymbol in n.handler))continue;if(r.includes(n.method))continue;if(!1===s.includes(n.method)&&"ALL"!==n.method)continue;const{resolver:t,metadata:o={}}=n.handler[e.uniqueSymbol],a=i?.[n.method],{docs:c,components:l}=await t({...f,...o},a);f.components={...f.components,...l??{}},p({method:n.method,path:n.path,data:c,schema:h})}for(const e in h)for(const t in h[e]){const s=h[e][t]?.hide;s&&("boolean"==typeof s?s:d&&s(d))&&delete h[e][t]}return{openapi:f.version,...{...n,tags:n.tags?.filter((e=>!c?.includes(e?.name))),info:{title:"Hono Documentation",description:"Development documentation",version:"0.0.0",...n.info},paths:{...m(h,{excludeStaticFile:o,exclude:a}),...n.paths},components:{...n.components,schemas:{...f.components,...n.components?.schemas}}}}}async function f(e,t,s={}){let n={};const o={...s,...t,responses:{...s?.responses,...t.responses}};if(o.responses)for(const t of Object.keys(o.responses)){const s=o.responses[t];if(s&&"content"in s)for(const t of Object.keys(s.content??{})){const o=s.content?.[t];if(o&&(o.schema&&"builder"in o.schema)){const t=await o.schema.builder(e);o.schema=t.schema,t.components&&(n={...n,...t.components})}}}return{docs:o,components:n}}exports.generateValidatorDocs=e.generateValidatorDocs,exports.uniqueSymbol=e.uniqueSymbol,exports.describeRoute=function(s){const{validateResponse:n,...o}=s;return Object.assign((async(e,o)=>{if(await o(),n&&s.responses){const o=e.res.status,a=e.res.headers.get("content-type");if(o&&a){const r=s.responses[o];if(r&&"content"in r&&r.content){const s=a.split(";")[0],o=r.content[s];if(o?.schema&&"validator"in o.schema)try{let t;const n=e.res.clone();if("application/json"===s?t=await n.json():"text/plain"===s&&(t=await n.text()),!t)throw new Error("No data to validate!");await o.schema.validator(t)}catch(e){let s={status:500,message:"Response validation failed!"};throw"object"==typeof n&&(s={...s,...n}),new t.HTTPException(s.status,{message:s.message,cause:e})}}}}}),{[e.uniqueSymbol]:{resolver:(e,t)=>f(e,o,t)}})},exports.generateRouteSpecs=f,exports.generateSpecs=d,exports.openAPISpecs=function(e,t){const s={version:"3.1.0",components:{}};let n=null;return async o=>(n||(n=await d(e,t,s,o)),o.json(n))};
|
package/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{u as e}from"./utils.js";export{g as generateValidatorDocs}from"./utils.js";import{HTTPException as t}from"hono/http-exception";const
|
|
1
|
+
import{u as e}from"./utils.js";export{g as generateValidatorDocs}from"./utils.js";import{HTTPException as t}from"hono/http-exception";const s=["GET","PUT","POST","DELETE","OPTIONS","HEAD","PATCH","TRACE"],n=e=>e.charAt(0).toUpperCase()+e.slice(1),o=new Map,a=(e,t)=>{const s=`${e}:${t}`;if(o.has(s))return o.get(s);let a=e;if("/"===t)return`${a}Index`;for(const e of t.split("/"))123===e.charCodeAt(0)?a+=`By${n(e.slice(1,-1))}`:a+=n(e);return o.set(s,a),a},r=new Map;function c(e,t,s){return e&&t in e?e[t]??s:s}function i(...e){return e.reduce(((e,t)=>{if(!t)return e;let s;return("tags"in e&&e.tags||"tags"in t&&t.tags)&&(s=[...c(e,"tags",[]),...c(t,"tags",[])]),{...e,...t,tags:s,responses:{...c(e,"responses",{}),...c(t,"responses",{})},parameters:m(e.parameters,t.parameters)}}),{})}function p({path:e,method:t,data:s,schema:n}){e=(e=>e.split("/").map((e=>{let t=e;return t.startsWith(":")&&(t=t.slice(1,t.length),t.endsWith("?")&&(t=t.slice(0,-1)),t=`{${t}}`),t})).join("/"))(e);const o=t.toLowerCase();if("all"===o)if(r.has(e)){const t=r.get(e)??{};r.set(e,{...t,...s,parameters:m(t.parameters,s.parameters)})}else r.set(e,s);else{const t=function(e){const t=Array.from(r.keys());let s={};for(const n of t)e.match(n)&&(s=i(s,r.get(n)??{}));return s}(e);n[e]={...n[e]?n[e]:{},[o]:{responses:{},operationId:a(o,e),...i(t,n[e]?.[o],s)}}}}const l=e=>"$ref"in e?e.$ref:`${e.in} ${e.name}`;function m(...e){const t=e.flatMap((e=>e??[])).reduce(((e,t)=>(e.set(l(t),t),e)),new Map);return Array.from(t.values())}function u(e,{excludeStaticFile:t=!0,exclude:s=[]}){const n={},o=Array.isArray(s)?s:[s];for(const[s,a]of Object.entries(e))if(!(o.some((e=>"string"==typeof e?s===e:e.test(s)))||s.includes("*")||t&&s.includes("."))){for(const e of Object.keys(a)){const t=a[e];if(s.includes("{")){t.parameters||(t.parameters=[]);const e=s.split("/").filter((e=>e.startsWith("{")&&!t.parameters.find((t=>"path"===t.in&&t.name===e.slice(1,e.length-1)))));for(const s of e){const e=s.slice(1,s.length-1),n=t.parameters.findIndex((t=>"param"===t.in&&t.name===e));-1!==n?t.parameters[n].in="path":t.parameters.push({schema:{type:"string"},in:"path",name:e,required:!0})}}t.responses||(t.responses={200:{}})}n[s]=a}return n}function f(e,t){const s={version:"3.1.0",components:{}};let n=null;return async o=>(n||(n=await d(e,t,s,o)),o.json(n))}async function d(t,{documentation:n={},excludeStaticFile:o=!0,exclude:a=[],excludeMethods:r=["OPTIONS"],excludeTags:c=[],defaultOptions:i}={documentation:{},excludeStaticFile:!0,exclude:[],excludeMethods:["OPTIONS"],excludeTags:[]},{version:l="3.1.0",components:m={}}={version:"3.1.0",components:{}},f){const d={version:l,components:m},h={};for(const n of t.routes){if(!(e in n.handler))continue;if(r.includes(n.method))continue;if(!1===s.includes(n.method)&&"ALL"!==n.method)continue;const{resolver:t,metadata:o={}}=n.handler[e],a=i?.[n.method],{docs:c,components:l}=await t({...d,...o},a);d.components={...d.components,...l??{}},p({method:n.method,path:n.path,data:c,schema:h})}for(const e in h)for(const t in h[e]){const s=h[e][t]?.hide;s&&("boolean"==typeof s?s:f&&s(f))&&delete h[e][t]}return{openapi:d.version,...{...n,tags:n.tags?.filter((e=>!c?.includes(e?.name))),info:{title:"Hono Documentation",description:"Development documentation",version:"0.0.0",...n.info},paths:{...u(h,{excludeStaticFile:o,exclude:a}),...n.paths},components:{...n.components,schemas:{...d.components,...n.components?.schemas}}}}}function h(s){const{validateResponse:n,...o}=s;return Object.assign((async(e,o)=>{if(await o(),n&&s.responses){const o=e.res.status,a=e.res.headers.get("content-type");if(o&&a){const r=s.responses[o];if(r&&"content"in r&&r.content){const s=a.split(";")[0],o=r.content[s];if(o?.schema&&"validator"in o.schema)try{let t;const n=e.res.clone();if("application/json"===s?t=await n.json():"text/plain"===s&&(t=await n.text()),!t)throw new Error("No data to validate!");await o.schema.validator(t)}catch(e){let s={status:500,message:"Response validation failed!"};throw"object"==typeof n&&(s={...s,...n}),new t(s.status,{message:s.message,cause:e})}}}}}),{[e]:{resolver:(e,t)=>x(e,o,t)}})}async function x(e,t,s={}){let n={};const o={...s,...t,responses:{...s?.responses,...t.responses}};if(o.responses)for(const t of Object.keys(o.responses)){const s=o.responses[t];if(s&&"content"in s)for(const t of Object.keys(s.content??{})){const o=s.content?.[t];if(o&&(o.schema&&"builder"in o.schema)){const t=await o.schema.builder(e);o.schema=t.schema,t.components&&(n={...n,...t.components})}}}return{docs:o,components:n}}export{h as describeRoute,x as generateRouteSpecs,d as generateSpecs,f as openAPISpecs,e as uniqueSymbol};
|
package/package.json
CHANGED
package/src/types.d.ts
CHANGED
|
@@ -25,7 +25,7 @@ export type HandlerResponse = {
|
|
|
25
25
|
}>;
|
|
26
26
|
metadata?: Record<string, unknown>;
|
|
27
27
|
};
|
|
28
|
-
export type DescribeRouteOptions = Omit<OpenAPIV3.OperationObject, "responses"> & {
|
|
28
|
+
export type DescribeRouteOptions = Omit<OpenAPIV3.OperationObject, "responses" | "parameters"> & {
|
|
29
29
|
/**
|
|
30
30
|
* Pass `true` to hide route from OpenAPI/swagger document
|
|
31
31
|
*/
|
|
@@ -49,10 +49,16 @@ export type DescribeRouteOptions = Omit<OpenAPIV3.OperationObject, "responses">
|
|
|
49
49
|
};
|
|
50
50
|
}) | OpenAPIV3.ReferenceObject;
|
|
51
51
|
};
|
|
52
|
+
/**
|
|
53
|
+
* Parameters of the request
|
|
54
|
+
*/
|
|
55
|
+
parameters?: (OpenAPIV3.ParameterObject | (OpenAPIV3.ParameterObject & {
|
|
56
|
+
schema: ResolverResult;
|
|
57
|
+
}))[];
|
|
52
58
|
};
|
|
53
59
|
export interface OpenAPIRoute {
|
|
54
60
|
path: string;
|
|
55
|
-
method: (typeof ALLOWED_METHODS)[number];
|
|
61
|
+
method: (typeof ALLOWED_METHODS)[number] | "ALL";
|
|
56
62
|
data: DescribeRouteOptions | Pick<OpenAPIV3.OperationObject, "parameters" | "requestBody">;
|
|
57
63
|
}
|
|
58
64
|
export type OpenApiSpecsOptions = {
|
package/typebox.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var e=require("@hono/typebox-validator"),r=require("@sinclair/typebox/value"),a=require("./toOpenAPISchema.cjs"),t=require("./utils.cjs");function i(e){return{builder:async
|
|
1
|
+
"use strict";var e=require("@hono/typebox-validator"),r=require("@sinclair/typebox/value"),a=require("./toOpenAPISchema.cjs"),t=require("./utils.cjs");function i(e){return{builder:async()=>({schema:await a.convert(e)}),validator:a=>{r.Value.Parse(e,a)}}}require("json-schema-walker"),exports.resolver=i,exports.validator=function(r,a,o){const s=e.tbValidator(r,a,o);return Object.assign(s,{[t.uniqueSymbol]:{resolver:async e=>t.generateValidatorDocs(r,await i(a).builder(e))}})};
|
package/typebox.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{tbValidator as r}from"@hono/typebox-validator";import{Value as o}from"@sinclair/typebox/value";import{c as a}from"./toOpenAPISchema.js";import{u as t,g as e}from"./utils.js";import"json-schema-walker";function i(r){return{builder:async
|
|
1
|
+
import{tbValidator as r}from"@hono/typebox-validator";import{Value as o}from"@sinclair/typebox/value";import{c as a}from"./toOpenAPISchema.js";import{u as t,g as e}from"./utils.js";import"json-schema-walker";function i(r){return{builder:async()=>({schema:await a(r)}),validator:a=>{o.Parse(r,a)}}}function s(o,a,s){const n=r(o,a,s);return Object.assign(n,{[t]:{resolver:async r=>e(o,await i(a).builder(r))}})}export{i as resolver,s as validator};
|
package/valibot.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var e=require("@hono/valibot-validator"),r=require("@valibot/to-json-schema"),a=require("valibot"),t=require("./toOpenAPISchema.cjs"),o=require("./utils.cjs");function i(e,o){return{builder:async
|
|
1
|
+
"use strict";var e=require("@hono/valibot-validator"),r=require("@valibot/to-json-schema"),a=require("valibot"),t=require("./toOpenAPISchema.cjs"),o=require("./utils.cjs");function i(e,o){return{builder:async()=>({schema:await t.convert(r.toJsonSchema(e,o))}),validator:async r=>{await a.parseAsync(e,r)}}}require("json-schema-walker"),exports.resolver=i,exports.validator=function(r,a,t){const s=e.vValidator(r,a,t);return Object.assign(s,{[o.uniqueSymbol]:{resolver:async e=>o.generateValidatorDocs(r,await i(a).builder(e))}})};
|
package/valibot.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{vValidator as o}from"@hono/valibot-validator";import{toJsonSchema as a}from"@valibot/to-json-schema";import{parseAsync as t}from"valibot";import{c as r}from"./toOpenAPISchema.js";import{u as i,g as s}from"./utils.js";import"json-schema-walker";function m(o,i){return{builder:async
|
|
1
|
+
import{vValidator as o}from"@hono/valibot-validator";import{toJsonSchema as a}from"@valibot/to-json-schema";import{parseAsync as t}from"valibot";import{c as r}from"./toOpenAPISchema.js";import{u as i,g as s}from"./utils.js";import"json-schema-walker";function m(o,i){return{builder:async()=>({schema:await r(a(o,i))}),validator:async a=>{await t(o,a)}}}function n(a,t,r){const n=o(a,t,r);return Object.assign(n,{[i]:{resolver:async o=>s(a,await m(t).builder(o))}})}export{m as resolver,n as validator};
|