@kamaalio/hono-standard-openapi 0.0.1
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/LICENSE +21 -0
- package/README.md +74 -0
- package/dist/app.d.ts +44 -0
- package/dist/app.d.ts.map +1 -0
- package/dist/app.js +169 -0
- package/dist/app.js.map +1 -0
- package/dist/errors.d.ts +17 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +29 -0
- package/dist/errors.js.map +1 -0
- package/dist/generator.d.ts +25 -0
- package/dist/generator.d.ts.map +1 -0
- package/dist/generator.js +231 -0
- package/dist/generator.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -0
- package/dist/json-schema.d.ts +65 -0
- package/dist/json-schema.d.ts.map +1 -0
- package/dist/json-schema.js +248 -0
- package/dist/json-schema.js.map +1 -0
- package/dist/registry.d.ts +44 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +78 -0
- package/dist/registry.js.map +1 -0
- package/dist/route.d.ts +24 -0
- package/dist/route.d.ts.map +1 -0
- package/dist/route.js +19 -0
- package/dist/route.js.map +1 -0
- package/dist/standard-schema.d.ts +17 -0
- package/dist/standard-schema.d.ts.map +1 -0
- package/dist/standard-schema.js +16 -0
- package/dist/standard-schema.js.map +1 -0
- package/dist/type-inference.d.ts +80 -0
- package/dist/type-inference.d.ts.map +1 -0
- package/dist/type-inference.js +2 -0
- package/dist/type-inference.js.map +1 -0
- package/dist/types.d.ts +54 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +8 -0
- package/dist/types.js.map +1 -0
- package/dist/validator.d.ts +30 -0
- package/dist/validator.d.ts.map +1 -0
- package/dist/validator.js +31 -0
- package/dist/validator.js.map +1 -0
- package/package.json +73 -0
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import type { Env, Handler, MiddlewareHandler, TypedResponse, ValidationTargets } from 'hono';
|
|
2
|
+
import type { StatusCode } from 'hono/utils/http-status';
|
|
3
|
+
import type { StandardSchemaV1 } from './standard-schema.ts';
|
|
4
|
+
import type { RouteConfigBase } from './types.ts';
|
|
5
|
+
type HasUndefined<T> = undefined extends T ? true : false;
|
|
6
|
+
/** Rewrites OpenAPI's `/users/{id}` into the `/users/:id` Hono routes with. */
|
|
7
|
+
export type ConvertPathType<T extends string> = T extends `${infer Start}/{${infer Param}}${infer Rest}` ? `${Start}/:${Param}${ConvertPathType<Rest>}` : T;
|
|
8
|
+
type RequestPart<R extends RouteConfigBase, Part extends string> = R extends {
|
|
9
|
+
request: infer Request;
|
|
10
|
+
} ? Part extends keyof Request ? Request[Part] : never : never;
|
|
11
|
+
type InputTypeBase<R extends RouteConfigBase, Part extends string, Type extends keyof ValidationTargets> = RequestPart<R, Part> extends infer Schema extends StandardSchemaV1 ? {
|
|
12
|
+
in: {
|
|
13
|
+
[K in Type]: HasUndefined<ValidationTargets[K]> extends true ? {
|
|
14
|
+
[K2 in keyof StandardSchemaV1.InferInput<Schema>]?: StandardSchemaV1.InferInput<Schema>[K2];
|
|
15
|
+
} : {
|
|
16
|
+
[K2 in keyof StandardSchemaV1.InferInput<Schema>]: StandardSchemaV1.InferInput<Schema>[K2];
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
out: {
|
|
20
|
+
[K in Type]: StandardSchemaV1.InferOutput<Schema>;
|
|
21
|
+
};
|
|
22
|
+
} : {};
|
|
23
|
+
type RequestContent<R extends RouteConfigBase> = R extends {
|
|
24
|
+
request: {
|
|
25
|
+
body: {
|
|
26
|
+
content: infer Content;
|
|
27
|
+
};
|
|
28
|
+
};
|
|
29
|
+
} ? Content : never;
|
|
30
|
+
type JsonMediaType<Content> = {
|
|
31
|
+
[K in keyof Content]: K extends `application/${string}json` ? K : never;
|
|
32
|
+
}[keyof Content];
|
|
33
|
+
type FormMediaType<Content> = {
|
|
34
|
+
[K in keyof Content]: K extends 'multipart/form-data' | 'application/x-www-form-urlencoded' ? K : never;
|
|
35
|
+
}[keyof Content];
|
|
36
|
+
type BodySchema<Content, MediaType> = MediaType extends keyof Content ? Content[MediaType] extends {
|
|
37
|
+
schema: infer Schema extends StandardSchemaV1;
|
|
38
|
+
} ? Schema : never : never;
|
|
39
|
+
type InputTypeBody<R extends RouteConfigBase, MediaType, Target extends 'json' | 'form'> = BodySchema<RequestContent<R>, MediaType> extends infer Schema extends StandardSchemaV1 ? {
|
|
40
|
+
in: {
|
|
41
|
+
[K in Target]: StandardSchemaV1.InferInput<Schema>;
|
|
42
|
+
};
|
|
43
|
+
out: {
|
|
44
|
+
[K in Target]: StandardSchemaV1.InferOutput<Schema>;
|
|
45
|
+
};
|
|
46
|
+
} : {};
|
|
47
|
+
/** Everything a handler can read off the request, derived from the route's schemas. */
|
|
48
|
+
export type ComputeInput<R extends RouteConfigBase> = InputTypeBase<R, 'params', 'param'> & InputTypeBase<R, 'query', 'query'> & InputTypeBase<R, 'headers', 'header'> & InputTypeBase<R, 'cookies', 'cookie'> & InputTypeBody<R, JsonMediaType<RequestContent<R>>, 'json'> & InputTypeBody<R, FormMediaType<RequestContent<R>>, 'form'>;
|
|
49
|
+
/**
|
|
50
|
+
* The status code a response key stands for.
|
|
51
|
+
*
|
|
52
|
+
* Keys can be written either way — `200` or `'200'` — so both forms resolve to the same code.
|
|
53
|
+
*/
|
|
54
|
+
type StatusFrom<Key> = Key extends StatusCode ? Key : Key extends `${infer Status extends number}` ? Status extends StatusCode ? Status : never : never;
|
|
55
|
+
type ResponseBody<Response, MediaType> = MediaType extends keyof Response ? Response[MediaType] extends {
|
|
56
|
+
schema: infer Schema extends StandardSchemaV1;
|
|
57
|
+
} ? StandardSchemaV1.InferOutput<Schema> : never : never;
|
|
58
|
+
type TypedResponseFor<Response, Status extends StatusCode> = Response extends {
|
|
59
|
+
content: infer Content;
|
|
60
|
+
} ? ResponseBody<Content, JsonMediaType<Content>> extends infer Body ? [Body] extends [never] ? TypedResponse<unknown, Status, 'text'> : TypedResponse<Body, Status, 'json'> : never : never;
|
|
61
|
+
/** The responses a handler is allowed to return, one per documented status code. */
|
|
62
|
+
export type RouteConfigToTypedResponse<R extends RouteConfigBase> = {
|
|
63
|
+
[Key in keyof R['responses']]: TypedResponseFor<R['responses'][Key], StatusFrom<Key>>;
|
|
64
|
+
}[keyof R['responses']];
|
|
65
|
+
type HasContentlessResponse<R extends RouteConfigBase> = {
|
|
66
|
+
[Key in keyof R['responses']]: R['responses'][Key] extends {
|
|
67
|
+
content: unknown;
|
|
68
|
+
} ? never : true;
|
|
69
|
+
}[keyof R['responses']];
|
|
70
|
+
/**
|
|
71
|
+
* What a handler may return.
|
|
72
|
+
*
|
|
73
|
+
* A route that documents a response without a body — a 204, say — can also answer with a plain
|
|
74
|
+
* `Response`, since there is no schema to satisfy.
|
|
75
|
+
*/
|
|
76
|
+
export type RouteHandlerResponse<R extends RouteConfigBase> = [HasContentlessResponse<R>] extends [never] ? RouteConfigToTypedResponse<R> | Promise<RouteConfigToTypedResponse<R>> : RouteConfigToTypedResponse<R> | Promise<RouteConfigToTypedResponse<R>> | Response | Promise<Response>;
|
|
77
|
+
export type RouteHandler<R extends RouteConfigBase, E extends Env = Env> = Handler<E, ConvertPathType<R['path']>, ComputeInput<R>, RouteHandlerResponse<R>>;
|
|
78
|
+
export type RouteMiddleware<E extends Env = Env> = MiddlewareHandler<E> | readonly MiddlewareHandler<E>[];
|
|
79
|
+
export {};
|
|
80
|
+
//# sourceMappingURL=type-inference.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"type-inference.d.ts","sourceRoot":"","sources":["../src/type-inference.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"type-inference.js","sourceRoot":"","sources":["../src/type-inference.ts"],"names":[],"mappings":""}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { HeadersObject, LinksObject, OperationObject, ParameterObject, ReferenceObject, RequestBodyObject, ResponsesObject, SchemaObject } from 'openapi3-ts/oas31';
|
|
2
|
+
import type { StandardSchema } from './standard-schema.ts';
|
|
3
|
+
export type { ReferenceObject, SchemaObject };
|
|
4
|
+
/** Either a schema to convert, or an already-written OpenAPI schema to pass through untouched. */
|
|
5
|
+
export type SchemaOrReference = StandardSchema | SchemaObject | ReferenceObject;
|
|
6
|
+
export interface MediaTypeObject {
|
|
7
|
+
readonly schema?: SchemaOrReference | undefined;
|
|
8
|
+
readonly example?: unknown;
|
|
9
|
+
readonly examples?: Record<string, unknown> | undefined;
|
|
10
|
+
readonly encoding?: Record<string, unknown> | undefined;
|
|
11
|
+
}
|
|
12
|
+
export type ContentObject = Record<string, MediaTypeObject>;
|
|
13
|
+
export interface RequestBody extends Omit<RequestBodyObject, 'content'> {
|
|
14
|
+
readonly content: ContentObject;
|
|
15
|
+
}
|
|
16
|
+
export interface ResponseConfig {
|
|
17
|
+
readonly description: string;
|
|
18
|
+
readonly headers?: StandardSchema | HeadersObject | undefined;
|
|
19
|
+
readonly links?: LinksObject | undefined;
|
|
20
|
+
readonly content?: ContentObject | undefined;
|
|
21
|
+
}
|
|
22
|
+
export interface RouteRequest {
|
|
23
|
+
readonly body?: RequestBody | undefined;
|
|
24
|
+
readonly params?: StandardSchema | undefined;
|
|
25
|
+
readonly query?: StandardSchema | undefined;
|
|
26
|
+
readonly cookies?: StandardSchema | undefined;
|
|
27
|
+
readonly headers?: StandardSchema | undefined;
|
|
28
|
+
}
|
|
29
|
+
export type RouteMethod = 'get' | 'post' | 'put' | 'delete' | 'patch' | 'head' | 'options' | 'trace';
|
|
30
|
+
export interface RouteConfigBase extends Omit<OperationObject, 'responses' | 'parameters'> {
|
|
31
|
+
readonly method: RouteMethod;
|
|
32
|
+
readonly path: string;
|
|
33
|
+
readonly request?: RouteRequest | undefined;
|
|
34
|
+
readonly parameters?: (ParameterObject | ReferenceObject)[] | undefined;
|
|
35
|
+
readonly responses: Record<string, ResponseConfig | ReferenceObject>;
|
|
36
|
+
}
|
|
37
|
+
export type { ResponsesObject };
|
|
38
|
+
/** Where a parameter lives in the request. */
|
|
39
|
+
export type ParameterLocation = 'path' | 'query' | 'header' | 'cookie';
|
|
40
|
+
/** The request keys that become parameters, in the order the document lists them. */
|
|
41
|
+
export declare const PARAMETER_SOURCES: readonly [{
|
|
42
|
+
readonly key: 'params';
|
|
43
|
+
readonly location: 'path';
|
|
44
|
+
}, {
|
|
45
|
+
readonly key: 'query';
|
|
46
|
+
readonly location: 'query';
|
|
47
|
+
}, {
|
|
48
|
+
readonly key: 'headers';
|
|
49
|
+
readonly location: 'header';
|
|
50
|
+
}, {
|
|
51
|
+
readonly key: 'cookies';
|
|
52
|
+
readonly location: 'cookie';
|
|
53
|
+
}];
|
|
54
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,aAAa,EACb,WAAW,EACX,eAAe,EACf,eAAe,EACf,eAAe,EACf,iBAAiB,EACjB,eAAe,EACf,YAAY,EACb,MAAM,mBAAmB,CAAC;AAE3B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAE3D,YAAY,EAAE,eAAe,EAAE,YAAY,EAAE,CAAC;AAE9C,kGAAkG;AAClG,MAAM,MAAM,iBAAiB,GAAG,cAAc,GAAG,YAAY,GAAG,eAAe,CAAC;AAEhF,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,MAAM,CAAC,EAAE,iBAAiB,GAAG,SAAS,CAAC;IAChD,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC;IACxD,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC;CACzD;AAED,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;AAE5D,MAAM,WAAW,WAAY,SAAQ,IAAI,CAAC,iBAAiB,EAAE,SAAS,CAAC;IACrE,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC;CACjC;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,OAAO,CAAC,EAAE,cAAc,GAAG,aAAa,GAAG,SAAS,CAAC;IAC9D,QAAQ,CAAC,KAAK,CAAC,EAAE,WAAW,GAAG,SAAS,CAAC;IACzC,QAAQ,CAAC,OAAO,CAAC,EAAE,aAAa,GAAG,SAAS,CAAC;CAC9C;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,IAAI,CAAC,EAAE,WAAW,GAAG,SAAS,CAAC;IACxC,QAAQ,CAAC,MAAM,CAAC,EAAE,cAAc,GAAG,SAAS,CAAC;IAC7C,QAAQ,CAAC,KAAK,CAAC,EAAE,cAAc,GAAG,SAAS,CAAC;IAC5C,QAAQ,CAAC,OAAO,CAAC,EAAE,cAAc,GAAG,SAAS,CAAC;IAC9C,QAAQ,CAAC,OAAO,CAAC,EAAE,cAAc,GAAG,SAAS,CAAC;CAC/C;AAED,MAAM,MAAM,WAAW,GAAG,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC;AAErG,MAAM,WAAW,eAAgB,SAAQ,IAAI,CAAC,eAAe,EAAE,WAAW,GAAG,YAAY,CAAC;IACxF,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,CAAC,EAAE,YAAY,GAAG,SAAS,CAAC;IAC5C,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC,eAAe,GAAG,eAAe,CAAC,EAAE,GAAG,SAAS,CAAC;IACxE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,GAAG,eAAe,CAAC,CAAC;CACtE;AAED,YAAY,EAAE,eAAe,EAAE,CAAC;AAEhC,8CAA8C;AAC9C,MAAM,MAAM,iBAAiB,GAAG,MAAM,GAAG,OAAO,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAEvE,qFAAqF;AACrF,eAAO,MAAM,iBAAiB;kBACrB,QAAQ;uBAAY,MAAM;;kBAC1B,OAAO;uBAAY,OAAO;;kBAC1B,SAAS;uBAAY,QAAQ;;kBAC7B,SAAS;uBAAY,QAAQ;EACkD,CAAC"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/** The request keys that become parameters, in the order the document lists them. */
|
|
2
|
+
export const PARAMETER_SOURCES = [
|
|
3
|
+
{ key: 'params', location: 'path' },
|
|
4
|
+
{ key: 'query', location: 'query' },
|
|
5
|
+
{ key: 'headers', location: 'header' },
|
|
6
|
+
{ key: 'cookies', location: 'cookie' },
|
|
7
|
+
];
|
|
8
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AA6DA,qFAAqF;AACrF,MAAM,CAAC,MAAM,iBAAiB,GAAG;IAC/B,EAAE,GAAG,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE;IACnC,EAAE,GAAG,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE;IACnC,EAAE,GAAG,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE;IACtC,EAAE,GAAG,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE;CACgD,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { Context, Env, MiddlewareHandler, ValidationTargets } from 'hono';
|
|
2
|
+
import type { StandardSchemaV1 } from './standard-schema.ts';
|
|
3
|
+
/** What a validation attempt produced, handed to a hook before the handler runs. */
|
|
4
|
+
export type ValidationResult<T> = {
|
|
5
|
+
readonly target: keyof ValidationTargets;
|
|
6
|
+
readonly success: true;
|
|
7
|
+
readonly data: T;
|
|
8
|
+
} | {
|
|
9
|
+
readonly target: keyof ValidationTargets;
|
|
10
|
+
readonly success: false;
|
|
11
|
+
readonly data: unknown;
|
|
12
|
+
readonly error: {
|
|
13
|
+
readonly issues: readonly StandardSchemaV1.Issue[];
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Runs before the handler, once per validated part of the request.
|
|
18
|
+
*
|
|
19
|
+
* Returning a `Response` (or throwing) takes over the request; returning nothing lets it continue,
|
|
20
|
+
* which is how a hook can log a failure without changing the outcome.
|
|
21
|
+
*/
|
|
22
|
+
export type Hook<T, E extends Env, P extends string, R> = (result: ValidationResult<T>, c: Context<E, P>) => R | undefined;
|
|
23
|
+
/**
|
|
24
|
+
* Validates one part of a request against a Standard Schema.
|
|
25
|
+
*
|
|
26
|
+
* Header names are matched case-insensitively against the schema's own property names, because HTTP
|
|
27
|
+
* header casing is not something a caller should have to get right.
|
|
28
|
+
*/
|
|
29
|
+
export declare function standardValidator<E extends Env, P extends string>(target: keyof ValidationTargets, schema: StandardSchemaV1, propertyNames: readonly string[], hook?: Hook<unknown, E, P, unknown>): MiddlewareHandler<E, P>;
|
|
30
|
+
//# sourceMappingURL=validator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validator.d.ts","sourceRoot":"","sources":["../src/validator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,MAAM,CAAC;AAG/E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAE7D,oFAAoF;AACpF,MAAM,MAAM,gBAAgB,CAAC,CAAC,IAC1B;IAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,iBAAiB,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAA;CAAE,GACtF;IACE,QAAQ,CAAC,MAAM,EAAE,MAAM,iBAAiB,CAAC;IACzC,QAAQ,CAAC,OAAO,EAAE,KAAK,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE;QAAE,QAAQ,CAAC,MAAM,EAAE,SAAS,gBAAgB,CAAC,KAAK,EAAE,CAAA;KAAE,CAAC;CACxE,CAAC;AAEN;;;;;GAKG;AACH,MAAM,MAAM,IAAI,CAAC,CAAC,EAAE,CAAC,SAAS,GAAG,EAAE,CAAC,SAAS,MAAM,EAAE,CAAC,IAAI,CACxD,MAAM,EAAE,gBAAgB,CAAC,CAAC,CAAC,EAC3B,CAAC,EAAE,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,KACb,CAAC,GAAG,SAAS,CAAC;AAEnB;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,SAAS,GAAG,EAAE,CAAC,SAAS,MAAM,EAC/D,MAAM,EAAE,MAAM,iBAAiB,EAC/B,MAAM,EAAE,gBAAgB,EACxB,aAAa,EAAE,SAAS,MAAM,EAAE,EAChC,IAAI,CAAC,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC,GAClC,iBAAiB,CAAC,CAAC,EAAE,CAAC,CAAC,CAkBzB"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { validator } from 'hono/validator';
|
|
2
|
+
/**
|
|
3
|
+
* Validates one part of a request against a Standard Schema.
|
|
4
|
+
*
|
|
5
|
+
* Header names are matched case-insensitively against the schema's own property names, because HTTP
|
|
6
|
+
* header casing is not something a caller should have to get right.
|
|
7
|
+
*/
|
|
8
|
+
export function standardValidator(target, schema, propertyNames, hook) {
|
|
9
|
+
return validator(target, async (value, c) => {
|
|
10
|
+
const candidate = target === 'header' ? withSchemaCasing(value, propertyNames) : value;
|
|
11
|
+
const result = await schema['~standard'].validate(candidate);
|
|
12
|
+
if (result.issues == null) {
|
|
13
|
+
const hooked = hook?.({ data: result.value, success: true, target }, c);
|
|
14
|
+
if (hooked instanceof Response)
|
|
15
|
+
return hooked;
|
|
16
|
+
return result.value;
|
|
17
|
+
}
|
|
18
|
+
const failure = { data: candidate, error: { issues: result.issues }, success: false, target };
|
|
19
|
+
const hooked = hook?.(failure, c);
|
|
20
|
+
if (hooked instanceof Response)
|
|
21
|
+
return hooked;
|
|
22
|
+
return c.json({ error: { issues: result.issues }, success: false }, 400);
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
function withSchemaCasing(value, propertyNames) {
|
|
26
|
+
if (typeof value !== 'object' || value == null || propertyNames.length === 0)
|
|
27
|
+
return value;
|
|
28
|
+
const casingByLowercased = new Map(propertyNames.map(name => [name.toLowerCase(), name]));
|
|
29
|
+
return Object.fromEntries(Object.entries(value).map(([key, entry]) => [casingByLowercased.get(key.toLowerCase()) ?? key, entry]));
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=validator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validator.js","sourceRoot":"","sources":["../src/validator.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAyB3C;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAC/B,MAA+B,EAC/B,MAAwB,EACxB,aAAgC,EAChC,IAAmC;IAEnC,OAAO,SAAS,CAAC,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;QAC1C,MAAM,SAAS,GAAG,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,gBAAgB,CAAC,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;QACvF,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;QAE7D,IAAI,MAAM,CAAC,MAAM,IAAI,IAAI,EAAE,CAAC;YAC1B,MAAM,MAAM,GAAG,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC;YACxE,IAAI,MAAM,YAAY,QAAQ;gBAAE,OAAO,MAAM,CAAC;YAE9C,OAAO,MAAM,CAAC,KAAK,CAAC;QACtB,CAAC;QAED,MAAM,OAAO,GAAG,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAW,CAAC;QACvG,MAAM,MAAM,GAAG,IAAI,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;QAClC,IAAI,MAAM,YAAY,QAAQ;YAAE,OAAO,MAAM,CAAC;QAE9C,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,GAAG,CAAC,CAAC;IAC3E,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,gBAAgB,CAAC,KAAc,EAAE,aAAgC;IACxE,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,IAAI,IAAI,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IAE3F,MAAM,kBAAkB,GAAG,IAAI,GAAG,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;IAE1F,OAAO,MAAM,CAAC,WAAW,CACvB,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC,kBAAkB,CAAC,GAAG,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC,IAAI,GAAG,EAAE,KAAK,CAAC,CAAC,CACvG,CAAC;AACJ,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@kamaalio/hono-standard-openapi",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Generate OpenAPI documents from any Standard Schema library, for Hono.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"hono",
|
|
7
|
+
"json-schema",
|
|
8
|
+
"openapi",
|
|
9
|
+
"standard-schema",
|
|
10
|
+
"validator"
|
|
11
|
+
],
|
|
12
|
+
"license": "MIT",
|
|
13
|
+
"author": "",
|
|
14
|
+
"files": [
|
|
15
|
+
"dist"
|
|
16
|
+
],
|
|
17
|
+
"type": "module",
|
|
18
|
+
"main": "dist/index.js",
|
|
19
|
+
"types": "dist/index.d.ts",
|
|
20
|
+
"exports": {
|
|
21
|
+
".": {
|
|
22
|
+
"types": "./dist/index.d.ts",
|
|
23
|
+
"default": "./dist/index.js"
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"publishConfig": {
|
|
27
|
+
"access": "public"
|
|
28
|
+
},
|
|
29
|
+
"scripts": {
|
|
30
|
+
"compile": "tsc -p tsconfig.build.json",
|
|
31
|
+
"format": "oxfmt",
|
|
32
|
+
"format:check": "oxfmt --check",
|
|
33
|
+
"lint": "oxlint",
|
|
34
|
+
"prepare": "husky",
|
|
35
|
+
"release": "sh scripts/publish.sh",
|
|
36
|
+
"test": "vitest run",
|
|
37
|
+
"test:watch": "vitest",
|
|
38
|
+
"test:cov": "vitest run --coverage",
|
|
39
|
+
"type-check": "tsc --noEmit"
|
|
40
|
+
},
|
|
41
|
+
"dependencies": {
|
|
42
|
+
"@standard-schema/spec": "^1.1.0",
|
|
43
|
+
"openapi3-ts": "^4.5.0"
|
|
44
|
+
},
|
|
45
|
+
"devDependencies": {
|
|
46
|
+
"@types/node": "^26.2.0",
|
|
47
|
+
"@vitest/coverage-v8": "^4.1.11",
|
|
48
|
+
"eslint-plugin-import": "^2.32.0",
|
|
49
|
+
"hono": "^4.13.1",
|
|
50
|
+
"husky": "^9.1.7",
|
|
51
|
+
"lint-staged": "^17.3.0",
|
|
52
|
+
"oxfmt": "^0.64.0",
|
|
53
|
+
"oxlint": "^1.79.0",
|
|
54
|
+
"oxlint-tsgolint": "^7.0.2001",
|
|
55
|
+
"typescript": "^7.0.2",
|
|
56
|
+
"vitest": "^4.1.11",
|
|
57
|
+
"zod": "^4.4.3"
|
|
58
|
+
},
|
|
59
|
+
"peerDependencies": {
|
|
60
|
+
"hono": ">=4.10.0"
|
|
61
|
+
},
|
|
62
|
+
"lint-staged": {
|
|
63
|
+
"*.{js,mjs,cjs,ts}": "pnpm run lint",
|
|
64
|
+
"*": "oxfmt --no-error-on-unmatched-pattern"
|
|
65
|
+
},
|
|
66
|
+
"devEngines": {
|
|
67
|
+
"packageManager": {
|
|
68
|
+
"name": "pnpm",
|
|
69
|
+
"version": "^11.6.0",
|
|
70
|
+
"onFail": "download"
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|