hono-openapi 0.2.1 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -2
- package/arktype.cjs.js +1 -11
- package/arktype.esm.js +1 -8
- package/effect.cjs.d.ts +1 -0
- package/effect.cjs.js +1 -0
- package/effect.esm.d.ts +1 -0
- package/effect.esm.js +1 -0
- package/index.cjs.js +1 -13
- package/index.cjs2.js +1 -9
- package/index.esm.js +1 -10
- package/index.esm2.js +1 -7
- package/package.json +17 -4
- package/src/effect.d.ts +22 -0
- package/src/toOpenAPISchema/index.d.ts +1 -1
- package/typebox.cjs.js +1 -12
- package/typebox.esm.js +1 -9
- package/utils.cjs.js +1 -6
- package/utils.esm.js +1 -3
- package/valibot.cjs.js +1 -13
- package/valibot.esm.js +1 -10
- package/zod.cjs.js +1 -10
- package/zod.esm.js +1 -7
package/README.md
CHANGED
|
@@ -12,6 +12,7 @@ Supported Validation Libraries:
|
|
|
12
12
|
- [x] [Valibot](https://valibot.dev/)
|
|
13
13
|
- [x] [ArkType](https://arktype.io/)
|
|
14
14
|
- [x] [TypeBox](https://github.com/sinclairzx81/typebox)
|
|
15
|
+
- [x] [Effect](https://effect.website/docs/schema/introduction/)
|
|
15
16
|
|
|
16
17
|
> [!Note]
|
|
17
18
|
> This package is still in development and your feedback is highly appreciated. If you have any suggestions or issues, please let us know by creating an issue on GitHub.
|
|
@@ -46,6 +47,17 @@ pnpm add hono-openapi @hono/arktype-validator arktype
|
|
|
46
47
|
pnpm add hono-openapi @hono/typebox-validator @sinclair/typebox"
|
|
47
48
|
```
|
|
48
49
|
|
|
50
|
+
#### For Effect
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
pnpm add hono-openapi @hono/effect-validator effect
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
> [!IMPORTANT]
|
|
57
|
+
>
|
|
58
|
+
> Requires `effect@^3.10.0`.
|
|
59
|
+
> Also, use the `Schema` class from the `effect` package, as `@effect/schema` is not supported.
|
|
60
|
+
|
|
49
61
|
### Basic Usage
|
|
50
62
|
|
|
51
63
|
#### Setting up your application
|
|
@@ -220,10 +232,10 @@ app.get(
|
|
|
220
232
|
"/",
|
|
221
233
|
describeRoute({
|
|
222
234
|
// ...
|
|
223
|
-
validateResponse:
|
|
235
|
+
validateResponse: true,
|
|
224
236
|
}),
|
|
225
237
|
(c) => {
|
|
226
|
-
return c.
|
|
238
|
+
return c.json({ message: "This response will be validated" });
|
|
227
239
|
}
|
|
228
240
|
);
|
|
229
241
|
```
|
package/arktype.cjs.js
CHANGED
|
@@ -1,11 +1 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
var arktypeValidator = require('@hono/arktype-validator');
|
|
4
|
-
var index = require('./index.cjs2.js');
|
|
5
|
-
var utils = require('./utils.cjs.js');
|
|
6
|
-
require('json-schema-walker');
|
|
7
|
-
|
|
8
|
-
function resolver(schema){return {builder:async options=>({schema:await index.convert(schema.toJsonSchema())}),validator:value=>{schema(value);}}}function validator(target,schema,hook){const middleware=arktypeValidator.arktypeValidator(target,schema,hook);return Object.assign(middleware,{[utils.uniqueSymbol]:{resolver:async config=>utils.generateValidatorDocs(target,await resolver(schema).builder(config))}})}
|
|
9
|
-
|
|
10
|
-
exports.resolver = resolver;
|
|
11
|
-
exports.validator = validator;
|
|
1
|
+
"use strict";var e=require("@hono/arktype-validator"),r=require("./index.cjs2.js"),a=require("./utils.cjs.js");function t(e){return{builder:async a=>({schema:await r.convert(e.toJsonSchema())}),validator:r=>{e(r)}}}require("json-schema-walker"),exports.resolver=t,exports.validator=function(r,s,i){const o=e.arktypeValidator(r,s,i);return Object.assign(o,{[a.uniqueSymbol]:{resolver:async e=>a.generateValidatorDocs(r,await t(s).builder(e))}})};
|
package/arktype.esm.js
CHANGED
|
@@ -1,8 +1 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { c as convert } from './index.esm2.js';
|
|
3
|
-
import { u as uniqueSymbol, g as generateValidatorDocs } from './utils.esm.js';
|
|
4
|
-
import 'json-schema-walker';
|
|
5
|
-
|
|
6
|
-
function resolver(schema){return {builder:async options=>({schema:await convert(schema.toJsonSchema())}),validator:value=>{schema(value);}}}function validator(target,schema,hook){const middleware=arktypeValidator(target,schema,hook);return Object.assign(middleware,{[uniqueSymbol]:{resolver:async config=>generateValidatorDocs(target,await resolver(schema).builder(config))}})}
|
|
7
|
-
|
|
8
|
-
export { resolver, validator };
|
|
1
|
+
import{arktypeValidator as r}from"@hono/arktype-validator";import{c as a}from"./index.esm2.js";import{u as o,g as s}from"./utils.esm.js";import"json-schema-walker";function t(r){return{builder:async o=>({schema:await a(r.toJsonSchema())}),validator:a=>{r(a)}}}function e(a,e,i){const n=r(a,e,i);return Object.assign(n,{[o]:{resolver:async r=>s(a,await t(e).builder(r))}})}export{t as resolver,e as validator};
|
package/effect.cjs.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./src/effect";
|
package/effect.cjs.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";var e=require("@hono/effect-validator"),r=require("effect"),a=require("./index.cjs2.js"),t=require("./utils.cjs.js");function i(e){return{builder:async t=>({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 s=e.effectValidator(r,a);return Object.assign(s,{[t.uniqueSymbol]:{resolver:async e=>t.generateValidatorDocs(r,await i(a).builder(e))}})};
|
package/effect.esm.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./src/effect";
|
package/effect.esm.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{effectValidator as e}from"@hono/effect-validator";import{JSONSchema as o,Schema as r}from"effect";import{c as a}from"./index.esm2.js";import{u as t,g as s}from"./utils.esm.js";import"json-schema-walker";function i(e){return{builder:async r=>({schema:await a(o.make(e))}),validator:async o=>{await r.decodeUnknownPromise(e)(o)}}}function n(o,r){const a=e(o,r);return Object.assign(a,{[t]:{resolver:async e=>s(o,await i(r).builder(e))}})}export{i as resolver,n as validator};
|
package/index.cjs.js
CHANGED
|
@@ -1,13 +1 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
var httpException = require('hono/http-exception');
|
|
4
|
-
var utils = require('./utils.cjs.js');
|
|
5
|
-
|
|
6
|
-
function describeRoute(specs){const middleware=async(c,next)=>{await next();if(specs.validateResponse&&specs.responses){const status=c.res.status;const contentType=c.res.headers.get("content-type");if(status&&contentType){const response=specs.responses[status];if(response&&"content"in response&&response.content){const content=response.content[contentType];if(content?.schema&&"validator"in content.schema){try{await content.schema.validator(c.res.body);}catch(error){throw new httpException.HTTPException(400,{message:"Response validation failed!"})}}}}}};return Object.assign(middleware,{[utils.uniqueSymbol]:{resolver:async config=>{const docs={...specs};let components={};if(docs.responses){for(const key of Object.keys(docs.responses)){const response=docs.responses[key];if(response&&!("content"in response))continue;for(const contentKey of Object.keys(response.content??{})){const raw=response.content?.[contentKey];if(!raw)continue;if(raw.schema&&"builder"in raw.schema){const result=await raw.schema.builder(config);raw.schema=result.schema;if(result.components){components={...components,...result.components};}}}}}return {docs,components}}}})}
|
|
7
|
-
|
|
8
|
-
const ALLOWED_METHODS=["GET","PUT","POST","DELETE","OPTIONS","HEAD","PATCH","TRACE"];const toOpenAPIPath=path=>path.split("/").map(x=>{let tmp=x;if(tmp.startsWith(":")){tmp=tmp.slice(1,tmp.length);if(tmp.endsWith("?"))tmp=tmp.slice(0,-1);tmp=`{${tmp}}`;}return tmp}).join("/");const capitalize=word=>word.charAt(0).toUpperCase()+word.slice(1);const generateOperationId=(method,paths)=>{let operationId=method;if(paths==="/")return `${operationId}Index`;for(const path of paths.split("/")){if(path.charCodeAt(0)===123){operationId+=`By${capitalize(path.slice(1,-1))}`;}else {operationId+=capitalize(path);}}return operationId};function registerSchemaPath({path,method:_method,data,schema}){path=toOpenAPIPath(path);const method=_method.toLowerCase();schema[path]={...schema[path]?schema[path]:{},[method]:{responses:{},...schema[path]?.[method]??{},operationId:generateOperationId(method,path),...data}};}function filterPaths(paths,{excludeStaticFile=true,exclude=[]}){const newPaths={};for(const[key,value]of Object.entries(paths)){if(!exclude.some(x=>{if(typeof x==="string")return key===x;return x.test(key)})&&!key.includes("*")&&(excludeStaticFile?!key.includes("."):true)){for(const method of Object.keys(value)){const schema=value[method];if(key.includes("{")){if(!schema.parameters)schema.parameters=[];schema.parameters=[...key.split("/").filter(x=>x.startsWith("{")&&!schema.parameters.find(params=>params.in==="path"&¶ms.name===x.slice(1,x.length-1))).map(x=>({schema:{type:"string"},in:"path",name:x.slice(1,x.length-1),required:true})),...schema.parameters];}if(!schema.responses)schema.responses={200:{}};}newPaths[key]=value;}}return newPaths}
|
|
9
|
-
|
|
10
|
-
function openAPISpecs(hono,{documentation={},excludeStaticFile=true,exclude=[],excludeMethods=["OPTIONS"],excludeTags=[]}={documentation:{},excludeStaticFile:true,exclude:[],excludeMethods:["OPTIONS"],excludeTags:[]}){const config={version:"3.1.0",components:{}};const schema={};let specs=null;return async c=>{if(specs)return c.json(specs);for(const route of hono.routes){if(!(utils.uniqueSymbol in route.handler))continue;if(excludeMethods.includes(route.method))continue;if(ALLOWED_METHODS.includes(route.method)===false&&route.method!=="ALL")continue;const{resolver,metadata={}}=route.handler[utils.uniqueSymbol];const{docs,components}=await resolver({...config,...metadata});config.components={...config.components,...components??{}};if(route.method==="ALL"){for(const method of ALLOWED_METHODS){registerSchemaPath({path:route.path,data:docs,method,schema});}}else {registerSchemaPath({method:route.method,path:route.path,data:docs,schema});}}for(const path in schema){for(const method in schema[path]){const valueOrFunc=schema[path][method]?.hide;if(valueOrFunc&&(typeof valueOrFunc==="boolean"?valueOrFunc:valueOrFunc(c))){delete schema[path][method];}}}specs={openapi:config.version,...{...documentation,tags:documentation.tags?.filter(tag=>!excludeTags?.includes(tag?.name)),info:{title:"Hono Documentation",description:"Development documentation",version:"0.0.0",...documentation.info},paths:{...filterPaths(schema,{excludeStaticFile,exclude:Array.isArray(exclude)?exclude:[exclude]}),...documentation.paths},components:{...documentation.components,schemas:{...config.components,...documentation.components?.schemas}}}};return c.json(specs)}}
|
|
11
|
-
|
|
12
|
-
exports.describeRoute = describeRoute;
|
|
13
|
-
exports.openAPISpecs = openAPISpecs;
|
|
1
|
+
"use strict";var e=require("hono/http-exception"),t=require("./utils.cjs.js");const n=["GET","PUT","POST","DELETE","OPTIONS","HEAD","PATCH","TRACE"],s=e=>e.charAt(0).toUpperCase()+e.slice(1),o=(e,t)=>{let n=e;if("/"===t)return`${n}Index`;for(const e of t.split("/"))123===e.charCodeAt(0)?n+=`By${s(e.slice(1,-1))}`:n+=s(e);return n};function c({path:e,method:t,data:n,schema:s}){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 c=t.toLowerCase();s[e]={...s[e]?s[e]:{},[c]:{responses:{},...s[e]?.[c]??{},operationId:o(c,e),...n}}}function i(e,{excludeStaticFile:t=!0,exclude:n=[]}){const s={};for(const[o,c]of Object.entries(e))if(!(n.some((e=>"string"==typeof e?o===e:e.test(o)))||o.includes("*")||t&&o.includes("."))){for(const e of Object.keys(c)){const t=c[e];if(o.includes("{")){t.parameters||(t.parameters=[]);const e=o.split("/").filter((e=>e.startsWith("{")&&!t.parameters.find((t=>"path"===t.in&&t.name===e.slice(1,e.length-1)))));for(const n of e){const e=n.slice(1,n.length-1),s=t.parameters.findIndex((t=>"param"===t.in&&t.name===e));-1!==s?t.parameters[s].in="path":t.parameters.push(n)}}t.responses||(t.responses={200:{}})}s[o]=c}return s}exports.describeRoute=function(n){return Object.assign((async(t,s)=>{if(await s(),n.validateResponse&&n.responses){const s=t.res.status,o=t.res.headers.get("content-type");if(s&&o){const c=n.responses[s];if(c&&"content"in c&&c.content){const n=o.split(";")[0],s=c.content[n];if(s?.schema&&"validator"in s.schema)try{let e;if("application/json"===n?e=await t.res.json():"text/plain"===n&&(e=await t.res.text()),!e)throw new Error("No data to validate!");await s.schema.validator(e)}catch(t){throw new e.HTTPException(400,{message:"Response validation failed!"})}}}}}),{[t.uniqueSymbol]:{resolver:async e=>{const t={...n};let s={};if(t.responses)for(const n of Object.keys(t.responses)){const o=t.responses[n];if(!o||"content"in o)for(const t of Object.keys(o.content??{})){const n=o.content?.[t];if(n&&(n.schema&&"builder"in n.schema)){const t=await n.schema.builder(e);n.schema=t.schema,t.components&&(s={...s,...t.components})}}}return{docs:t,components:s}}}})},exports.openAPISpecs=function(e,{documentation:s={},excludeStaticFile:o=!0,exclude:a=[],excludeMethods:r=["OPTIONS"],excludeTags:l=[]}={documentation:{},excludeStaticFile:!0,exclude:[],excludeMethods:["OPTIONS"],excludeTags:[]}){const p={version:"3.1.0",components:{}},d={};let u=null;return async m=>{if(u)return m.json(u);for(const s of e.routes){if(!(t.uniqueSymbol in s.handler))continue;if(r.includes(s.method))continue;if(!1===n.includes(s.method)&&"ALL"!==s.method)continue;const{resolver:e,metadata:o={}}=s.handler[t.uniqueSymbol],{docs:i,components:a}=await e({...p,...o});if(p.components={...p.components,...a??{}},"ALL"===s.method)for(const e of n)c({path:s.path,data:i,method:e,schema:d});else c({method:s.method,path:s.path,data:i,schema:d})}for(const e in d)for(const t in d[e]){const n=d[e][t]?.hide;n&&("boolean"==typeof n?n:n(m))&&delete d[e][t]}return u={openapi:p.version,...{...s,tags:s.tags?.filter((e=>!l?.includes(e?.name))),info:{title:"Hono Documentation",description:"Development documentation",version:"0.0.0",...s.info},paths:{...i(d,{excludeStaticFile:o,exclude:Array.isArray(a)?a:[a]}),...s.paths},components:{...s.components,schemas:{...p.components,...s.components?.schemas}}}},m.json(u)}};
|
package/index.cjs2.js
CHANGED
|
@@ -1,9 +1 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
var jsonSchemaWalker = require('json-schema-walker');
|
|
4
|
-
|
|
5
|
-
const allowedKeywords=["$ref","definitions","title","multipleOf","maximum","exclusiveMaximum","minimum","exclusiveMinimum","maxLength","minLength","pattern","maxItems","minItems","uniqueItems","maxProperties","minProperties","required","enum","type","not","allOf","oneOf","anyOf","items","properties","additionalProperties","description","format","default","nullable","discriminator","readOnly","writeOnly","example","externalDocs","deprecated","xml"];
|
|
6
|
-
|
|
7
|
-
let InvalidTypeError=class InvalidTypeError extends Error{constructor(message){super(message);this.name="InvalidTypeError";this.message=message;}};const oasExtensionPrefix="x-";const handleDefinition=async(def,schema)=>{if(typeof def!=="object"){return def}const type=def.type;if(type){const walker=new jsonSchemaWalker.Walker;await walker.loadSchema({definitions:schema["definitions"]||[],...def,$schema:schema["$schema"]},{dereference:true,cloneSchema:true,dereferenceOptions:{dereference:{circular:"ignore"}}});await walker.walk(convertSchema,walker.vocabularies.DRAFT_07);if("definitions"in walker.rootSchema){walker.rootSchema.definitions=undefined;}return walker.rootSchema}if(Array.isArray(def)){const typeArr=def;const hasNull=typeArr.includes("null");if(hasNull){const actualTypes=typeArr.filter(l=>l!=="null");return {type:actualTypes.length===1?actualTypes[0]:actualTypes,nullable:true}}}return def};const convert=async(schema,options)=>{const walker=new jsonSchemaWalker.Walker;await walker.loadSchema(schema,options);await walker.walk(convertSchema,walker.vocabularies.DRAFT_07);const rootSchema=walker.rootSchema;if(rootSchema?.definitions){for(const defName in rootSchema.definitions){const def=rootSchema.definitions[defName];rootSchema.definitions[defName]=await handleDefinition(def,schema);}}return rootSchema};function stripIllegalKeywords(schema){if(typeof schema!=="object"){return schema}schema["$schema"]=undefined;schema["$id"]=undefined;if("id"in schema){schema["id"]=undefined;}return schema}function convertSchema(schema){if(!schema){return schema}schema=stripIllegalKeywords(schema);schema=convertTypes(schema);schema=rewriteConst(schema);schema=convertDependencies(schema);schema=convertNullable(schema);schema=rewriteIfThenElse(schema);schema=rewriteExclusiveMinMax(schema);schema=convertExamples(schema);if(typeof schema["patternProperties"]==="object"){schema=convertPatternProperties(schema);}if(schema.type==="array"&&typeof schema.items==="undefined"){schema.items={};}schema=convertIllegalKeywordsAsExtensions(schema);return schema}const validTypes=new Set(["null","boolean","object","array","number","string","integer"]);function validateType(type){if(typeof type==="object"&&!Array.isArray(type)){if(type.$ref){return}if(type.properties){return}}const types=Array.isArray(type)?type:[type];for(const type of types){if(type&&!validTypes.has(type))throw new InvalidTypeError(`Type "${type}" is not a valid type`)}}function convertDependencies(schema){const deps=schema.dependencies;if(typeof deps!=="object"){return schema}schema.dependencies=undefined;if(!Array.isArray(schema.allOf)){schema.allOf=[];}for(const key in deps){const foo={oneOf:[{not:{required:[key]}},{required:[key,deps[key]].flat()}]};schema.allOf.push(foo);}return schema}function convertNullable(schema){for(const key of ["oneOf","anyOf"]){const schemas=schema[key];if(!schemas)continue;if(!Array.isArray(schemas)){return schema}const hasNullable=schemas.some(item=>item.type==="null");if(!hasNullable){return schema}const filtered=schemas.filter(l=>l.type!=="null");for(const schemaEntry of filtered){schemaEntry.nullable=true;}schema[key]=filtered;}return schema}function convertTypes(schema){if(typeof schema!=="object"){return schema}if(schema.type===undefined){return schema}validateType(schema.type);if(Array.isArray(schema.type)){if(schema.type.includes("null")){schema.nullable=true;}const typesWithoutNull=schema.type.filter(type=>type!=="null");if(typesWithoutNull.length===0){schema.type=undefined;}else if(typesWithoutNull.length===1){schema.type=typesWithoutNull[0];}else {schema.type=undefined;schema.anyOf=typesWithoutNull.map(type=>({type}));}}else if(schema.type==="null"){schema.type=undefined;schema.nullable=true;}return schema}function convertPatternProperties(schema){schema["x-patternProperties"]=schema.patternProperties;schema.patternProperties=undefined;schema.additionalProperties??=true;return schema}function convertIllegalKeywordsAsExtensions(schema){const keys=Object.keys(schema);for(const keyword of keys){if(!keyword.startsWith(oasExtensionPrefix)&&!allowedKeywords.includes(keyword)){const key=`${oasExtensionPrefix}${keyword}`;schema[key]=schema[keyword];schema[keyword]=undefined;}}return schema}function convertExamples(schema){if(schema["examples"]&&Array.isArray(schema["examples"])){schema["example"]=schema["examples"][0];schema["examples"]=undefined;}return schema}function rewriteConst(schema){if(Object.hasOwnProperty.call(schema,"const")){schema.enum=[schema.const];schema.const=undefined;}return schema}function rewriteIfThenElse(schema){if(typeof schema!=="object"){return schema}if("if"in schema&&schema.if&&schema.then){schema.oneOf=[{allOf:[schema.if,schema.then].filter(Boolean)},{allOf:[{not:schema.if},schema.else].filter(Boolean)}];schema.if=undefined;schema.then=undefined;schema.else=undefined;}return schema}function rewriteExclusiveMinMax(schema){if(typeof schema.exclusiveMaximum==="number"){schema.maximum=schema.exclusiveMaximum;schema.exclusiveMaximum=true;}if(typeof schema.exclusiveMinimum==="number"){schema.minimum=schema.exclusiveMinimum;schema.exclusiveMinimum=true;}return schema}
|
|
8
|
-
|
|
9
|
-
exports.convert = convert;
|
|
1
|
+
"use strict";var e=require("json-schema-walker");const t=["$ref","definitions","title","multipleOf","maximum","exclusiveMaximum","minimum","exclusiveMinimum","maxLength","minLength","pattern","maxItems","minItems","uniqueItems","maxProperties","minProperties","required","enum","type","not","allOf","oneOf","anyOf","items","properties","additionalProperties","description","format","default","nullable","discriminator","readOnly","writeOnly","example","externalDocs","deprecated","xml"];let n=class extends Error{constructor(e){super(e),this.name="InvalidTypeError",this.message=e}};const i="x-",r=async(t,n)=>{if("object"!=typeof t)return t;if(t.type){const i=new e.Walker;return await i.loadSchema({definitions:n.definitions||[],...t,$schema:n.$schema},{dereference:!0,cloneSchema:!0,dereferenceOptions:{dereference:{circular:"ignore"}}}),await i.walk(o,i.vocabularies.DRAFT_07),"definitions"in i.rootSchema&&(i.rootSchema.definitions=void 0),i.rootSchema}if(Array.isArray(t)){const e=t;if(e.includes("null")){const t=e.filter((e=>"null"!==e));return{type:1===t.length?t[0]:t,nullable:!0}}}return t};function o(e){let r=e;return r?(r=function(e){return"object"!=typeof e||(e.$schema=void 0,e.$id=void 0,"id"in e&&(e.id=void 0)),e}(r),r=function(e){if("object"!=typeof e)return e;if(void 0===e.type)return e;if(function(e){if("object"==typeof e&&!Array.isArray(e)){if(e&&"$ref"in e&&e.$ref)return;if(e&&"properties"in e&&e.properties)return}const t=Array.isArray(e)?e:[e];for(const e of t)if(e&&!a.has(e))throw new n(`Type "${e}" is not a valid type`)}(e.type),Array.isArray(e.type)){e.type.includes("null")&&(e.nullable=!0);const t=e.type.filter((e=>"null"!==e));0===t.length?e.type=void 0:1===t.length?e.type=t[0]:(e.type=void 0,e.anyOf=t.map((e=>({type:e}))))}else"null"===e.type&&(e.type=void 0,e.nullable=!0);return e}(r),r=function(e){Object.hasOwnProperty.call(e,"const")&&(e.enum=[e.const],e.const=void 0);return e}(r),r=function(e){const t=e.dependencies;if("object"!=typeof t)return e;e.dependencies=void 0,Array.isArray(e.allOf)||(e.allOf=[]);for(const n in t){const i={oneOf:[{not:{required:[n]}},{required:[n,t[n]].flat()}]};e.allOf.push(i)}return e}(r),r=function(e){for(const t of["oneOf","anyOf"]){const n=e[t];if(!n)continue;if(!Array.isArray(n))return e;if(!n.some((e=>"null"===e.type)))return e;const i=n.filter((e=>"null"!==e.type));for(const e of i)e.nullable=!0;e[t]=i}return e}(r),r=function(e){if("object"!=typeof e)return e;"if"in e&&e.if&&e.then&&(e.oneOf=[{allOf:[e.if,e.then].filter(Boolean)},{allOf:[{not:e.if},e.else].filter(Boolean)}],e.if=void 0,e.then=void 0,e.else=void 0);return e}(r),r=function(e){"number"==typeof e.exclusiveMaximum&&(e.maximum=e.exclusiveMaximum,e.exclusiveMaximum=!0);"number"==typeof e.exclusiveMinimum&&(e.minimum=e.exclusiveMinimum,e.exclusiveMinimum=!0);return e}(r),r=function(e){e.examples&&Array.isArray(e.examples)&&(e.example=e.examples[0],e.examples=void 0);return e}(r),"object"==typeof r.patternProperties&&(r=function(e){return e["x-patternProperties"]=e.patternProperties,e.patternProperties=void 0,e.additionalProperties??=!0,e}(r)),"array"===r.type&&void 0===r.items&&(r.items={}),r=function(e){const n=Object.keys(e);for(const r of n)if(!r.startsWith(i)&&!t.includes(r)){e[`${i}${r}`]=e[r],e[r]=void 0}return e}(r),r):r}const a=new Set(["null","boolean","object","array","number","string","integer"]);exports.convert=async(t,n)=>{const i=new e.Walker;await i.loadSchema(t,n),await i.walk(o,i.vocabularies.DRAFT_07);const a=i.rootSchema;if(a?.definitions)for(const e in a.definitions){const n=a.definitions[e];a.definitions[e]=await r(n,t)}return a};
|
package/index.esm.js
CHANGED
|
@@ -1,10 +1 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { u as uniqueSymbol } from './utils.esm.js';
|
|
3
|
-
|
|
4
|
-
function describeRoute(specs){const middleware=async(c,next)=>{await next();if(specs.validateResponse&&specs.responses){const status=c.res.status;const contentType=c.res.headers.get("content-type");if(status&&contentType){const response=specs.responses[status];if(response&&"content"in response&&response.content){const content=response.content[contentType];if(content?.schema&&"validator"in content.schema){try{await content.schema.validator(c.res.body);}catch(error){throw new HTTPException(400,{message:"Response validation failed!"})}}}}}};return Object.assign(middleware,{[uniqueSymbol]:{resolver:async config=>{const docs={...specs};let components={};if(docs.responses){for(const key of Object.keys(docs.responses)){const response=docs.responses[key];if(response&&!("content"in response))continue;for(const contentKey of Object.keys(response.content??{})){const raw=response.content?.[contentKey];if(!raw)continue;if(raw.schema&&"builder"in raw.schema){const result=await raw.schema.builder(config);raw.schema=result.schema;if(result.components){components={...components,...result.components};}}}}}return {docs,components}}}})}
|
|
5
|
-
|
|
6
|
-
const ALLOWED_METHODS=["GET","PUT","POST","DELETE","OPTIONS","HEAD","PATCH","TRACE"];const toOpenAPIPath=path=>path.split("/").map(x=>{let tmp=x;if(tmp.startsWith(":")){tmp=tmp.slice(1,tmp.length);if(tmp.endsWith("?"))tmp=tmp.slice(0,-1);tmp=`{${tmp}}`;}return tmp}).join("/");const capitalize=word=>word.charAt(0).toUpperCase()+word.slice(1);const generateOperationId=(method,paths)=>{let operationId=method;if(paths==="/")return `${operationId}Index`;for(const path of paths.split("/")){if(path.charCodeAt(0)===123){operationId+=`By${capitalize(path.slice(1,-1))}`;}else {operationId+=capitalize(path);}}return operationId};function registerSchemaPath({path,method:_method,data,schema}){path=toOpenAPIPath(path);const method=_method.toLowerCase();schema[path]={...schema[path]?schema[path]:{},[method]:{responses:{},...schema[path]?.[method]??{},operationId:generateOperationId(method,path),...data}};}function filterPaths(paths,{excludeStaticFile=true,exclude=[]}){const newPaths={};for(const[key,value]of Object.entries(paths)){if(!exclude.some(x=>{if(typeof x==="string")return key===x;return x.test(key)})&&!key.includes("*")&&(excludeStaticFile?!key.includes("."):true)){for(const method of Object.keys(value)){const schema=value[method];if(key.includes("{")){if(!schema.parameters)schema.parameters=[];schema.parameters=[...key.split("/").filter(x=>x.startsWith("{")&&!schema.parameters.find(params=>params.in==="path"&¶ms.name===x.slice(1,x.length-1))).map(x=>({schema:{type:"string"},in:"path",name:x.slice(1,x.length-1),required:true})),...schema.parameters];}if(!schema.responses)schema.responses={200:{}};}newPaths[key]=value;}}return newPaths}
|
|
7
|
-
|
|
8
|
-
function openAPISpecs(hono,{documentation={},excludeStaticFile=true,exclude=[],excludeMethods=["OPTIONS"],excludeTags=[]}={documentation:{},excludeStaticFile:true,exclude:[],excludeMethods:["OPTIONS"],excludeTags:[]}){const config={version:"3.1.0",components:{}};const schema={};let specs=null;return async c=>{if(specs)return c.json(specs);for(const route of hono.routes){if(!(uniqueSymbol in route.handler))continue;if(excludeMethods.includes(route.method))continue;if(ALLOWED_METHODS.includes(route.method)===false&&route.method!=="ALL")continue;const{resolver,metadata={}}=route.handler[uniqueSymbol];const{docs,components}=await resolver({...config,...metadata});config.components={...config.components,...components??{}};if(route.method==="ALL"){for(const method of ALLOWED_METHODS){registerSchemaPath({path:route.path,data:docs,method,schema});}}else {registerSchemaPath({method:route.method,path:route.path,data:docs,schema});}}for(const path in schema){for(const method in schema[path]){const valueOrFunc=schema[path][method]?.hide;if(valueOrFunc&&(typeof valueOrFunc==="boolean"?valueOrFunc:valueOrFunc(c))){delete schema[path][method];}}}specs={openapi:config.version,...{...documentation,tags:documentation.tags?.filter(tag=>!excludeTags?.includes(tag?.name)),info:{title:"Hono Documentation",description:"Development documentation",version:"0.0.0",...documentation.info},paths:{...filterPaths(schema,{excludeStaticFile,exclude:Array.isArray(exclude)?exclude:[exclude]}),...documentation.paths},components:{...documentation.components,schemas:{...config.components,...documentation.components?.schemas}}}};return c.json(specs)}}
|
|
9
|
-
|
|
10
|
-
export { describeRoute, openAPISpecs };
|
|
1
|
+
import{HTTPException as e}from"hono/http-exception";import{u as t}from"./utils.esm.js";function n(n){return Object.assign((async(t,s)=>{if(await s(),n.validateResponse&&n.responses){const s=t.res.status,o=t.res.headers.get("content-type");if(s&&o){const c=n.responses[s];if(c&&"content"in c&&c.content){const n=o.split(";")[0],s=c.content[n];if(s?.schema&&"validator"in s.schema)try{let e;if("application/json"===n?e=await t.res.json():"text/plain"===n&&(e=await t.res.text()),!e)throw new Error("No data to validate!");await s.schema.validator(e)}catch(t){throw new e(400,{message:"Response validation failed!"})}}}}}),{[t]:{resolver:async e=>{const t={...n};let s={};if(t.responses)for(const n of Object.keys(t.responses)){const o=t.responses[n];if(!o||"content"in o)for(const t of Object.keys(o.content??{})){const n=o.content?.[t];if(n&&(n.schema&&"builder"in n.schema)){const t=await n.schema.builder(e);n.schema=t.schema,t.components&&(s={...s,...t.components})}}}return{docs:t,components:s}}}})}const s=["GET","PUT","POST","DELETE","OPTIONS","HEAD","PATCH","TRACE"],o=e=>e.charAt(0).toUpperCase()+e.slice(1),c=(e,t)=>{let n=e;if("/"===t)return`${n}Index`;for(const e of t.split("/"))123===e.charCodeAt(0)?n+=`By${o(e.slice(1,-1))}`:n+=o(e);return n};function a({path:e,method:t,data:n,schema:s}){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();s[e]={...s[e]?s[e]:{},[o]:{responses:{},...s[e]?.[o]??{},operationId:c(o,e),...n}}}function i(e,{excludeStaticFile:t=!0,exclude:n=[]}){const s={};for(const[o,c]of Object.entries(e))if(!(n.some((e=>"string"==typeof e?o===e:e.test(o)))||o.includes("*")||t&&o.includes("."))){for(const e of Object.keys(c)){const t=c[e];if(o.includes("{")){t.parameters||(t.parameters=[]);const e=o.split("/").filter((e=>e.startsWith("{")&&!t.parameters.find((t=>"path"===t.in&&t.name===e.slice(1,e.length-1)))));for(const n of e){const e=n.slice(1,n.length-1),s=t.parameters.findIndex((t=>"param"===t.in&&t.name===e));-1!==s?t.parameters[s].in="path":t.parameters.push(n)}}t.responses||(t.responses={200:{}})}s[o]=c}return s}function r(e,{documentation:n={},excludeStaticFile:o=!0,exclude:c=[],excludeMethods:r=["OPTIONS"],excludeTags:l=[]}={documentation:{},excludeStaticFile:!0,exclude:[],excludeMethods:["OPTIONS"],excludeTags:[]}){const p={version:"3.1.0",components:{}},d={};let m=null;return async h=>{if(m)return h.json(m);for(const n of e.routes){if(!(t in n.handler))continue;if(r.includes(n.method))continue;if(!1===s.includes(n.method)&&"ALL"!==n.method)continue;const{resolver:e,metadata:o={}}=n.handler[t],{docs:c,components:i}=await e({...p,...o});if(p.components={...p.components,...i??{}},"ALL"===n.method)for(const e of s)a({path:n.path,data:c,method:e,schema:d});else a({method:n.method,path:n.path,data:c,schema:d})}for(const e in d)for(const t in d[e]){const n=d[e][t]?.hide;n&&("boolean"==typeof n?n:n(h))&&delete d[e][t]}return m={openapi:p.version,...{...n,tags:n.tags?.filter((e=>!l?.includes(e?.name))),info:{title:"Hono Documentation",description:"Development documentation",version:"0.0.0",...n.info},paths:{...i(d,{excludeStaticFile:o,exclude:Array.isArray(c)?c:[c]}),...n.paths},components:{...n.components,schemas:{...p.components,...n.components?.schemas}}}},h.json(m)}}export{n as describeRoute,r as openAPISpecs};
|
package/index.esm2.js
CHANGED
|
@@ -1,7 +1 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
const allowedKeywords=["$ref","definitions","title","multipleOf","maximum","exclusiveMaximum","minimum","exclusiveMinimum","maxLength","minLength","pattern","maxItems","minItems","uniqueItems","maxProperties","minProperties","required","enum","type","not","allOf","oneOf","anyOf","items","properties","additionalProperties","description","format","default","nullable","discriminator","readOnly","writeOnly","example","externalDocs","deprecated","xml"];
|
|
4
|
-
|
|
5
|
-
let InvalidTypeError=class InvalidTypeError extends Error{constructor(message){super(message);this.name="InvalidTypeError";this.message=message;}};const oasExtensionPrefix="x-";const handleDefinition=async(def,schema)=>{if(typeof def!=="object"){return def}const type=def.type;if(type){const walker=new Walker;await walker.loadSchema({definitions:schema["definitions"]||[],...def,$schema:schema["$schema"]},{dereference:true,cloneSchema:true,dereferenceOptions:{dereference:{circular:"ignore"}}});await walker.walk(convertSchema,walker.vocabularies.DRAFT_07);if("definitions"in walker.rootSchema){walker.rootSchema.definitions=undefined;}return walker.rootSchema}if(Array.isArray(def)){const typeArr=def;const hasNull=typeArr.includes("null");if(hasNull){const actualTypes=typeArr.filter(l=>l!=="null");return {type:actualTypes.length===1?actualTypes[0]:actualTypes,nullable:true}}}return def};const convert=async(schema,options)=>{const walker=new Walker;await walker.loadSchema(schema,options);await walker.walk(convertSchema,walker.vocabularies.DRAFT_07);const rootSchema=walker.rootSchema;if(rootSchema?.definitions){for(const defName in rootSchema.definitions){const def=rootSchema.definitions[defName];rootSchema.definitions[defName]=await handleDefinition(def,schema);}}return rootSchema};function stripIllegalKeywords(schema){if(typeof schema!=="object"){return schema}schema["$schema"]=undefined;schema["$id"]=undefined;if("id"in schema){schema["id"]=undefined;}return schema}function convertSchema(schema){if(!schema){return schema}schema=stripIllegalKeywords(schema);schema=convertTypes(schema);schema=rewriteConst(schema);schema=convertDependencies(schema);schema=convertNullable(schema);schema=rewriteIfThenElse(schema);schema=rewriteExclusiveMinMax(schema);schema=convertExamples(schema);if(typeof schema["patternProperties"]==="object"){schema=convertPatternProperties(schema);}if(schema.type==="array"&&typeof schema.items==="undefined"){schema.items={};}schema=convertIllegalKeywordsAsExtensions(schema);return schema}const validTypes=new Set(["null","boolean","object","array","number","string","integer"]);function validateType(type){if(typeof type==="object"&&!Array.isArray(type)){if(type.$ref){return}if(type.properties){return}}const types=Array.isArray(type)?type:[type];for(const type of types){if(type&&!validTypes.has(type))throw new InvalidTypeError(`Type "${type}" is not a valid type`)}}function convertDependencies(schema){const deps=schema.dependencies;if(typeof deps!=="object"){return schema}schema.dependencies=undefined;if(!Array.isArray(schema.allOf)){schema.allOf=[];}for(const key in deps){const foo={oneOf:[{not:{required:[key]}},{required:[key,deps[key]].flat()}]};schema.allOf.push(foo);}return schema}function convertNullable(schema){for(const key of ["oneOf","anyOf"]){const schemas=schema[key];if(!schemas)continue;if(!Array.isArray(schemas)){return schema}const hasNullable=schemas.some(item=>item.type==="null");if(!hasNullable){return schema}const filtered=schemas.filter(l=>l.type!=="null");for(const schemaEntry of filtered){schemaEntry.nullable=true;}schema[key]=filtered;}return schema}function convertTypes(schema){if(typeof schema!=="object"){return schema}if(schema.type===undefined){return schema}validateType(schema.type);if(Array.isArray(schema.type)){if(schema.type.includes("null")){schema.nullable=true;}const typesWithoutNull=schema.type.filter(type=>type!=="null");if(typesWithoutNull.length===0){schema.type=undefined;}else if(typesWithoutNull.length===1){schema.type=typesWithoutNull[0];}else {schema.type=undefined;schema.anyOf=typesWithoutNull.map(type=>({type}));}}else if(schema.type==="null"){schema.type=undefined;schema.nullable=true;}return schema}function convertPatternProperties(schema){schema["x-patternProperties"]=schema.patternProperties;schema.patternProperties=undefined;schema.additionalProperties??=true;return schema}function convertIllegalKeywordsAsExtensions(schema){const keys=Object.keys(schema);for(const keyword of keys){if(!keyword.startsWith(oasExtensionPrefix)&&!allowedKeywords.includes(keyword)){const key=`${oasExtensionPrefix}${keyword}`;schema[key]=schema[keyword];schema[keyword]=undefined;}}return schema}function convertExamples(schema){if(schema["examples"]&&Array.isArray(schema["examples"])){schema["example"]=schema["examples"][0];schema["examples"]=undefined;}return schema}function rewriteConst(schema){if(Object.hasOwnProperty.call(schema,"const")){schema.enum=[schema.const];schema.const=undefined;}return schema}function rewriteIfThenElse(schema){if(typeof schema!=="object"){return schema}if("if"in schema&&schema.if&&schema.then){schema.oneOf=[{allOf:[schema.if,schema.then].filter(Boolean)},{allOf:[{not:schema.if},schema.else].filter(Boolean)}];schema.if=undefined;schema.then=undefined;schema.else=undefined;}return schema}function rewriteExclusiveMinMax(schema){if(typeof schema.exclusiveMaximum==="number"){schema.maximum=schema.exclusiveMaximum;schema.exclusiveMaximum=true;}if(typeof schema.exclusiveMinimum==="number"){schema.minimum=schema.exclusiveMinimum;schema.exclusiveMinimum=true;}return schema}
|
|
6
|
-
|
|
7
|
-
export { convert as c };
|
|
1
|
+
import{Walker as e}from"json-schema-walker";const t=["$ref","definitions","title","multipleOf","maximum","exclusiveMaximum","minimum","exclusiveMinimum","maxLength","minLength","pattern","maxItems","minItems","uniqueItems","maxProperties","minProperties","required","enum","type","not","allOf","oneOf","anyOf","items","properties","additionalProperties","description","format","default","nullable","discriminator","readOnly","writeOnly","example","externalDocs","deprecated","xml"];let n=class extends Error{constructor(e){super(e),this.name="InvalidTypeError",this.message=e}};const i="x-",r=async(t,n)=>{if("object"!=typeof t)return t;if(t.type){const i=new e;return await i.loadSchema({definitions:n.definitions||[],...t,$schema:n.$schema},{dereference:!0,cloneSchema:!0,dereferenceOptions:{dereference:{circular:"ignore"}}}),await i.walk(a,i.vocabularies.DRAFT_07),"definitions"in i.rootSchema&&(i.rootSchema.definitions=void 0),i.rootSchema}if(Array.isArray(t)){const e=t;if(e.includes("null")){const t=e.filter((e=>"null"!==e));return{type:1===t.length?t[0]:t,nullable:!0}}}return t},o=async(t,n)=>{const i=new e;await i.loadSchema(t,n),await i.walk(a,i.vocabularies.DRAFT_07);const o=i.rootSchema;if(o?.definitions)for(const e in o.definitions){const n=o.definitions[e];o.definitions[e]=await r(n,t)}return o};function a(e){let r=e;return r?(r=function(e){return"object"!=typeof e||(e.$schema=void 0,e.$id=void 0,"id"in e&&(e.id=void 0)),e}(r),r=function(e){if("object"!=typeof e)return e;if(void 0===e.type)return e;if(function(e){if("object"==typeof e&&!Array.isArray(e)){if(e&&"$ref"in e&&e.$ref)return;if(e&&"properties"in e&&e.properties)return}const t=Array.isArray(e)?e:[e];for(const e of t)if(e&&!s.has(e))throw new n(`Type "${e}" is not a valid type`)}(e.type),Array.isArray(e.type)){e.type.includes("null")&&(e.nullable=!0);const t=e.type.filter((e=>"null"!==e));0===t.length?e.type=void 0:1===t.length?e.type=t[0]:(e.type=void 0,e.anyOf=t.map((e=>({type:e}))))}else"null"===e.type&&(e.type=void 0,e.nullable=!0);return e}(r),r=function(e){Object.hasOwnProperty.call(e,"const")&&(e.enum=[e.const],e.const=void 0);return e}(r),r=function(e){const t=e.dependencies;if("object"!=typeof t)return e;e.dependencies=void 0,Array.isArray(e.allOf)||(e.allOf=[]);for(const n in t){const i={oneOf:[{not:{required:[n]}},{required:[n,t[n]].flat()}]};e.allOf.push(i)}return e}(r),r=function(e){for(const t of["oneOf","anyOf"]){const n=e[t];if(!n)continue;if(!Array.isArray(n))return e;if(!n.some((e=>"null"===e.type)))return e;const i=n.filter((e=>"null"!==e.type));for(const e of i)e.nullable=!0;e[t]=i}return e}(r),r=function(e){if("object"!=typeof e)return e;"if"in e&&e.if&&e.then&&(e.oneOf=[{allOf:[e.if,e.then].filter(Boolean)},{allOf:[{not:e.if},e.else].filter(Boolean)}],e.if=void 0,e.then=void 0,e.else=void 0);return e}(r),r=function(e){"number"==typeof e.exclusiveMaximum&&(e.maximum=e.exclusiveMaximum,e.exclusiveMaximum=!0);"number"==typeof e.exclusiveMinimum&&(e.minimum=e.exclusiveMinimum,e.exclusiveMinimum=!0);return e}(r),r=function(e){e.examples&&Array.isArray(e.examples)&&(e.example=e.examples[0],e.examples=void 0);return e}(r),"object"==typeof r.patternProperties&&(r=function(e){return e["x-patternProperties"]=e.patternProperties,e.patternProperties=void 0,e.additionalProperties??=!0,e}(r)),"array"===r.type&&void 0===r.items&&(r.items={}),r=function(e){const n=Object.keys(e);for(const r of n)if(!r.startsWith(i)&&!t.includes(r)){e[`${i}${r}`]=e[r],e[r]=void 0}return e}(r),r):r}const s=new Set(["null","boolean","object","array","number","string","integer"]);export{o as c};
|
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": "0.
|
|
4
|
+
"version": "0.3.0",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"hono",
|
|
@@ -9,7 +9,8 @@
|
|
|
9
9
|
"zod",
|
|
10
10
|
"valibot",
|
|
11
11
|
"typebox",
|
|
12
|
-
"arktype"
|
|
12
|
+
"arktype",
|
|
13
|
+
"effect"
|
|
13
14
|
],
|
|
14
15
|
"homepage": "https://github.com/rhinobase/hono-openapi",
|
|
15
16
|
"publishConfig": {
|
|
@@ -28,21 +29,23 @@
|
|
|
28
29
|
},
|
|
29
30
|
"optionalDependencies": {
|
|
30
31
|
"@hono/arktype-validator": "^2.0.0",
|
|
32
|
+
"@hono/effect-validator": "^1.2.0",
|
|
31
33
|
"@hono/typebox-validator": "^0.2.6",
|
|
32
34
|
"@hono/valibot-validator": "^0.5.1",
|
|
33
35
|
"@hono/zod-validator": "^0.4.1",
|
|
34
36
|
"@sinclair/typebox": "^0.34.9",
|
|
35
37
|
"@valibot/to-json-schema": "^1.0.0-beta.3",
|
|
36
38
|
"arktype": "2.0.0-rc.25",
|
|
37
|
-
"
|
|
39
|
+
"effect": "^3.11.3",
|
|
40
|
+
"hono": "^4.6.13",
|
|
38
41
|
"openapi-types": "^12.1.3",
|
|
39
42
|
"valibot": "^1.0.0-beta.9",
|
|
40
43
|
"zod": "^3.23.8",
|
|
41
44
|
"zod-openapi": "^4.0.0"
|
|
42
45
|
},
|
|
43
46
|
"devDependencies": {
|
|
44
|
-
"@rollup/plugin-terser": "^0.4.4",
|
|
45
47
|
"@apidevtools/json-schema-ref-parser": "^11.7.2",
|
|
48
|
+
"@rollup/plugin-terser": "^0.4.4",
|
|
46
49
|
"@types/json-schema": "^7.0.15"
|
|
47
50
|
},
|
|
48
51
|
"exports": {
|
|
@@ -95,6 +98,16 @@
|
|
|
95
98
|
"default": "./arktype.cjs.js",
|
|
96
99
|
"types": "./arktype.cjs.d.ts"
|
|
97
100
|
}
|
|
101
|
+
},
|
|
102
|
+
"./effect": {
|
|
103
|
+
"import": {
|
|
104
|
+
"default": "./effect.esm.js",
|
|
105
|
+
"types": "./effect.esm.d.ts"
|
|
106
|
+
},
|
|
107
|
+
"require": {
|
|
108
|
+
"default": "./effect.cjs.js",
|
|
109
|
+
"types": "./effect.cjs.d.ts"
|
|
110
|
+
}
|
|
98
111
|
}
|
|
99
112
|
},
|
|
100
113
|
"module": "./index.esm.js",
|
package/src/effect.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Schema } from "effect";
|
|
2
|
+
import type { Env, Input as HonoInput, MiddlewareHandler, ValidationTargets } from "hono";
|
|
3
|
+
import type { HasUndefined, ResolverResult } from "./types";
|
|
4
|
+
export declare function resolver<Type, Context>(schema: Schema.Schema<Type, Context, never>): ResolverResult;
|
|
5
|
+
export declare function validator<Type, Context, Target extends keyof ValidationTargets, E extends Env, P extends string, In = Schema.Schema<Type, Context, never>["Encoded"], Out = Schema.Schema<Type, Context, never>["Type"], I extends HonoInput = {
|
|
6
|
+
in: HasUndefined<In> extends true ? {
|
|
7
|
+
[K in Target]?: K extends "json" ? In : HasUndefined<keyof ValidationTargets[K]> extends true ? {
|
|
8
|
+
[K2 in keyof In]?: ValidationTargets[K][K2];
|
|
9
|
+
} : {
|
|
10
|
+
[K2 in keyof In]: ValidationTargets[K][K2];
|
|
11
|
+
};
|
|
12
|
+
} : {
|
|
13
|
+
[K in Target]: K extends "json" ? In : HasUndefined<keyof ValidationTargets[K]> extends true ? {
|
|
14
|
+
[K2 in keyof In]?: ValidationTargets[K][K2];
|
|
15
|
+
} : {
|
|
16
|
+
[K2 in keyof In]: ValidationTargets[K][K2];
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
out: {
|
|
20
|
+
[K in Target]: Out;
|
|
21
|
+
};
|
|
22
|
+
}, V extends I = I>(target: Target, schema: Schema.Schema<Type, Context, never>): MiddlewareHandler<E, P, V>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { JSONSchema4 } from "json-schema";
|
|
2
|
-
import type { Options } from "./types";
|
|
3
2
|
import type { OpenAPIV3 } from "openapi-types";
|
|
3
|
+
import type { Options } from "./types";
|
|
4
4
|
declare const convert: <T extends object = JSONSchema4>(schema: T, options?: Options) => Promise<OpenAPIV3.Document>;
|
|
5
5
|
export default convert;
|
package/typebox.cjs.js
CHANGED
|
@@ -1,12 +1 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
var typeboxValidator = require('@hono/typebox-validator');
|
|
4
|
-
var index = require('./index.cjs2.js');
|
|
5
|
-
var value = require('@sinclair/typebox/value');
|
|
6
|
-
var utils = require('./utils.cjs.js');
|
|
7
|
-
require('json-schema-walker');
|
|
8
|
-
|
|
9
|
-
function resolver(schema){return {builder:async options=>({schema:await index.convert(schema)}),validator:value$1=>{value.Value.Parse(schema,value$1);}}}function validator(target,schema,hook){const middleware=typeboxValidator.tbValidator(target,schema,hook);return Object.assign(middleware,{[utils.uniqueSymbol]:{resolver:async config=>utils.generateValidatorDocs(target,await resolver(schema).builder(config))}})}
|
|
10
|
-
|
|
11
|
-
exports.resolver = resolver;
|
|
12
|
-
exports.validator = validator;
|
|
1
|
+
"use strict";var e=require("@hono/typebox-validator"),r=require("./index.cjs2.js"),a=require("@sinclair/typebox/value"),i=require("./utils.cjs.js");function t(e){return{builder:async a=>({schema:await r.convert(e)}),validator:r=>{a.Value.Parse(e,r)}}}require("json-schema-walker"),exports.resolver=t,exports.validator=function(r,a,s){const o=e.tbValidator(r,a,s);return Object.assign(o,{[i.uniqueSymbol]:{resolver:async e=>i.generateValidatorDocs(r,await t(a).builder(e))}})};
|
package/typebox.esm.js
CHANGED
|
@@ -1,9 +1 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { c as convert } from './index.esm2.js';
|
|
3
|
-
import { Value } from '@sinclair/typebox/value';
|
|
4
|
-
import { u as uniqueSymbol, g as generateValidatorDocs } from './utils.esm.js';
|
|
5
|
-
import 'json-schema-walker';
|
|
6
|
-
|
|
7
|
-
function resolver(schema){return {builder:async options=>({schema:await convert(schema)}),validator:value=>{Value.Parse(schema,value);}}}function validator(target,schema,hook){const middleware=tbValidator(target,schema,hook);return Object.assign(middleware,{[uniqueSymbol]:{resolver:async config=>generateValidatorDocs(target,await resolver(schema).builder(config))}})}
|
|
8
|
-
|
|
9
|
-
export { resolver, validator };
|
|
1
|
+
import{tbValidator as r}from"@hono/typebox-validator";import{c as o}from"./index.esm2.js";import{Value as a}from"@sinclair/typebox/value";import{u as s,g as t}from"./utils.esm.js";import"json-schema-walker";function e(r){return{builder:async a=>({schema:await o(r)}),validator:o=>{a.Parse(r,o)}}}function i(o,a,i){const n=r(o,a,i);return Object.assign(n,{[s]:{resolver:async r=>t(o,await e(a).builder(r))}})}export{e as resolver,i as validator};
|
package/utils.cjs.js
CHANGED
|
@@ -1,6 +1 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
const uniqueSymbol=Symbol("openapi");async function generateValidatorDocs(target,_result){const result=await _result;const docs={};if(target==="form"||target==="json"){docs.requestBody={content:{[target==="json"?"application/json":"application/x-www-form-urlencoded"]:{schema:result.schema}}};}else {const parameters=[];if("$ref"in result.schema){parameters.push({in:target,name:result.schema.$ref,schema:result.schema});}else {for(const[key,value]of Object.entries(result.schema.properties??{})){parameters.push({in:target,name:key,schema:value,required:result.schema.required?.includes(key)});}}docs.parameters=parameters;}return {docs,components:result.components}}
|
|
4
|
-
|
|
5
|
-
exports.generateValidatorDocs = generateValidatorDocs;
|
|
6
|
-
exports.uniqueSymbol = uniqueSymbol;
|
|
1
|
+
"use strict";const e=Symbol("openapi");exports.generateValidatorDocs=async function(e,s){const n=await s,o={};if("form"===e||"json"===e)o.requestBody={content:{["json"===e?"application/json":"application/x-www-form-urlencoded"]:{schema:n.schema}}};else{const s=[];if("$ref"in n.schema)s.push({in:e,name:n.schema.$ref,schema:n.schema});else for(const[o,c]of Object.entries(n.schema.properties??{}))s.push({in:e,name:o,schema:c,required:n.schema.required?.includes(o)});o.parameters=s}return{docs:o,components:n.components}},exports.uniqueSymbol=e;
|
package/utils.esm.js
CHANGED
|
@@ -1,3 +1 @@
|
|
|
1
|
-
const
|
|
2
|
-
|
|
3
|
-
export { generateValidatorDocs as g, uniqueSymbol as u };
|
|
1
|
+
const e=Symbol("openapi");async function s(e,s){const n=await s,o={};if("form"===e||"json"===e)o.requestBody={content:{["json"===e?"application/json":"application/x-www-form-urlencoded"]:{schema:n.schema}}};else{const s=[];if("$ref"in n.schema)s.push({in:e,name:n.schema.$ref,schema:n.schema});else for(const[o,c]of Object.entries(n.schema.properties??{}))s.push({in:e,name:o,schema:c,required:n.schema.required?.includes(o)});o.parameters=s}return{docs:o,components:n.components}}export{s as g,e as u};
|
package/valibot.cjs.js
CHANGED
|
@@ -1,13 +1 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
var valibotValidator = require('@hono/valibot-validator');
|
|
4
|
-
var index = require('./index.cjs2.js');
|
|
5
|
-
var toJsonSchema = require('@valibot/to-json-schema');
|
|
6
|
-
var valibot = require('valibot');
|
|
7
|
-
var utils = require('./utils.cjs.js');
|
|
8
|
-
require('json-schema-walker');
|
|
9
|
-
|
|
10
|
-
function resolver(schema){return {builder:async options=>({schema:await index.convert(toJsonSchema.toJsonSchema(schema))}),validator:async value=>{await valibot.parseAsync(schema,value);}}}function validator(target,schema,hook){const middleware=valibotValidator.vValidator(target,schema,hook);return Object.assign(middleware,{[utils.uniqueSymbol]:{resolver:async config=>utils.generateValidatorDocs(target,await resolver(schema).builder(config))}})}
|
|
11
|
-
|
|
12
|
-
exports.resolver = resolver;
|
|
13
|
-
exports.validator = validator;
|
|
1
|
+
"use strict";var e=require("@hono/valibot-validator"),r=require("./index.cjs2.js"),a=require("@valibot/to-json-schema"),i=require("valibot"),s=require("./utils.cjs.js");function t(e){return{builder:async i=>({schema:await r.convert(a.toJsonSchema(e))}),validator:async r=>{await i.parseAsync(e,r)}}}require("json-schema-walker"),exports.resolver=t,exports.validator=function(r,a,i){const o=e.vValidator(r,a,i);return Object.assign(o,{[s.uniqueSymbol]:{resolver:async e=>s.generateValidatorDocs(r,await t(a).builder(e))}})};
|
package/valibot.esm.js
CHANGED
|
@@ -1,10 +1 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { c as convert } from './index.esm2.js';
|
|
3
|
-
import { toJsonSchema } from '@valibot/to-json-schema';
|
|
4
|
-
import { parseAsync } from 'valibot';
|
|
5
|
-
import { u as uniqueSymbol, g as generateValidatorDocs } from './utils.esm.js';
|
|
6
|
-
import 'json-schema-walker';
|
|
7
|
-
|
|
8
|
-
function resolver(schema){return {builder:async options=>({schema:await convert(toJsonSchema(schema))}),validator:async value=>{await parseAsync(schema,value);}}}function validator(target,schema,hook){const middleware=vValidator(target,schema,hook);return Object.assign(middleware,{[uniqueSymbol]:{resolver:async config=>generateValidatorDocs(target,await resolver(schema).builder(config))}})}
|
|
9
|
-
|
|
10
|
-
export { resolver, validator };
|
|
1
|
+
import{vValidator as o}from"@hono/valibot-validator";import{c as a}from"./index.esm2.js";import{toJsonSchema as r}from"@valibot/to-json-schema";import{parseAsync as t}from"valibot";import{u as i,g as s}from"./utils.esm.js";import"json-schema-walker";function m(o){return{builder:async t=>({schema:await a(r(o))}),validator:async a=>{await t(o,a)}}}function e(a,r,t){const e=o(a,r,t);return Object.assign(e,{[i]:{resolver:async o=>s(a,await m(r).builder(o))}})}export{m as resolver,e as validator};
|
package/zod.cjs.js
CHANGED
|
@@ -1,10 +1 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
var zodValidator = require('@hono/zod-validator');
|
|
4
|
-
var zodOpenapi = require('zod-openapi');
|
|
5
|
-
var utils = require('./utils.cjs.js');
|
|
6
|
-
|
|
7
|
-
function resolver(schema){return {builder:options=>{const{version,...rest}=options??{};return zodOpenapi.createSchema(schema,options?{openapi:version,...rest}:undefined)},validator:schema.parse}}function validator(target,schema,hook){const middleware=zodValidator.zValidator(target,schema,hook);return Object.assign(middleware,{[utils.uniqueSymbol]:{resolver:async config=>utils.generateValidatorDocs(target,await resolver(schema).builder(config)),metadata:{schemaType:"input"}}})}
|
|
8
|
-
|
|
9
|
-
exports.resolver = resolver;
|
|
10
|
-
exports.validator = validator;
|
|
1
|
+
"use strict";var e=require("@hono/zod-validator"),r=require("zod-openapi"),a=require("./utils.cjs.js");function t(e){return{builder:a=>{const{version:t,...o}=a??{};return r.createSchema(e,a?{openapi:t,...o}:void 0)},validator:e.parse}}exports.resolver=t,exports.validator=function(r,o,i){const n=e.zValidator(r,o,i);return Object.assign(n,{[a.uniqueSymbol]:{resolver:async e=>a.generateValidatorDocs(r,await t(o).builder(e)),metadata:{schemaType:"input"}}})};
|
package/zod.esm.js
CHANGED
|
@@ -1,7 +1 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { createSchema } from 'zod-openapi';
|
|
3
|
-
import { u as uniqueSymbol, g as generateValidatorDocs } from './utils.esm.js';
|
|
4
|
-
|
|
5
|
-
function resolver(schema){return {builder:options=>{const{version,...rest}=options??{};return createSchema(schema,options?{openapi:version,...rest}:undefined)},validator:schema.parse}}function validator(target,schema,hook){const middleware=zValidator(target,schema,hook);return Object.assign(middleware,{[uniqueSymbol]:{resolver:async config=>generateValidatorDocs(target,await resolver(schema).builder(config)),metadata:{schemaType:"input"}}})}
|
|
6
|
-
|
|
7
|
-
export { resolver, validator };
|
|
1
|
+
import{zValidator as o}from"@hono/zod-validator";import{createSchema as r}from"zod-openapi";import{u as t,g as a}from"./utils.esm.js";function e(o){return{builder:t=>{const{version:a,...e}=t??{};return r(o,t?{openapi:a,...e}:void 0)},validator:o.parse}}function i(r,i,n){const s=o(r,i,n);return Object.assign(s,{[t]:{resolver:async o=>a(r,await e(i).builder(o)),metadata:{schemaType:"input"}}})}export{e as resolver,i as validator};
|