Compare commits
5 Commits
ed23aff757
...
dcb13d10b2
Author | SHA1 | Date |
---|---|---|
|
dcb13d10b2 | |
|
247f7705b3 | |
|
8ed99d9d79 | |
|
b9fa57530a | |
|
215f376d4b |
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
'@hono/oidc-auth': minor
|
||||
---
|
||||
|
||||
Support empty OIDC_CLIENT_SECRET
|
|
@ -67,7 +67,7 @@ export function ajvValidator<
|
|||
T,
|
||||
Target extends keyof ValidationTargets,
|
||||
E extends Env = Env,
|
||||
P extends string = string
|
||||
P extends string = string,
|
||||
>(
|
||||
target: Target,
|
||||
schema: JSONSchemaType<T>,
|
||||
|
|
|
@ -23,7 +23,7 @@ export const arktypeValidator = <
|
|||
} = {
|
||||
in: HasUndefined<I> extends true ? { [K in Target]?: I } : { [K in Target]: I }
|
||||
out: { [K in Target]: O }
|
||||
}
|
||||
},
|
||||
>(
|
||||
target: Target,
|
||||
schema: T,
|
||||
|
|
|
@ -225,7 +225,7 @@ export function SessionProvider(props: SessionProviderProps) {
|
|||
}
|
||||
return updatedSession
|
||||
},
|
||||
} as SessionContextValue),
|
||||
}) as SessionContextValue,
|
||||
[session, loading, setSession]
|
||||
)
|
||||
|
||||
|
|
|
@ -64,7 +64,7 @@ type Hook<
|
|||
E extends Env,
|
||||
P extends string,
|
||||
Target extends keyof ValidationTargets = keyof ValidationTargets,
|
||||
O = object
|
||||
O = object,
|
||||
> = (
|
||||
result: ({ success: true } | { success: false; errors: ValidationError[] }) & {
|
||||
data: T
|
||||
|
@ -131,7 +131,7 @@ export const classValidator = <
|
|||
}
|
||||
out: { [K in Target]: Output }
|
||||
},
|
||||
V extends I = I
|
||||
V extends I = I,
|
||||
>(
|
||||
target: Target,
|
||||
dataType: T,
|
||||
|
|
|
@ -32,7 +32,7 @@ export const conformValidator = <
|
|||
form: { [K in keyof In]: FormTargetValue }
|
||||
}
|
||||
out: { form: GetSuccessSubmission<Out> }
|
||||
}
|
||||
},
|
||||
>(
|
||||
parse: F,
|
||||
hook?: Hook<F, E, P>
|
||||
|
|
|
@ -30,7 +30,7 @@ export const effectValidator = <
|
|||
: { [K2 in keyof In]: ValidationTargets[K][K2] }
|
||||
}
|
||||
out: { [K in Target]: Out }
|
||||
}
|
||||
},
|
||||
>(
|
||||
target: Target,
|
||||
schema: S.Schema<Type, Encoded, never>
|
||||
|
|
|
@ -35,7 +35,7 @@ export interface Emitter<EPMap extends EventPayloadMap> {
|
|||
export const defineHandler = <
|
||||
EPMap extends EventPayloadMap,
|
||||
Key extends keyof EPMap,
|
||||
E extends Env = Env
|
||||
E extends Env = Env,
|
||||
>(
|
||||
handler: EventHandler<EPMap[Key], E>
|
||||
): EventHandler<EPMap[Key], E> => {
|
||||
|
|
|
@ -162,7 +162,7 @@ export interface TwitchUserResponse {
|
|||
view_count: number
|
||||
email: string
|
||||
created_at: string
|
||||
}
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
|
|
|
@ -167,7 +167,14 @@ export const getClient = (c: Context): oauth2.Client => {
|
|||
const env = getOidcAuthEnv(c)
|
||||
let client = c.get('oidcClient')
|
||||
if (client === undefined) {
|
||||
client = {
|
||||
client =
|
||||
env.OIDC_CLIENT_SECRET === ''
|
||||
? {
|
||||
// No client secret provided, use 'none' auth method
|
||||
client_id: env.OIDC_CLIENT_ID,
|
||||
token_endpoint_auth_method: 'none',
|
||||
}
|
||||
: {
|
||||
client_id: env.OIDC_CLIENT_ID,
|
||||
client_secret: env.OIDC_CLIENT_SECRET,
|
||||
token_endpoint_auth_method: 'client_secret_basic',
|
||||
|
|
|
@ -44,7 +44,7 @@ const getMetricConstructor = (type: MetricOptions['type']) =>
|
|||
({
|
||||
counter: Counter,
|
||||
histogram: Histogram,
|
||||
}[type])
|
||||
})[type]
|
||||
|
||||
export const createStandardMetrics = ({
|
||||
registry,
|
||||
|
|
|
@ -9,9 +9,8 @@ import * as zodSchemas from './__schemas__/zod'
|
|||
import { sValidator } from '.'
|
||||
|
||||
type ExtractSchema<T> = T extends Hono<infer _, infer S> ? S : never
|
||||
type MergeDiscriminatedUnion<U> = UnionToIntersection<U> extends infer O
|
||||
? { [K in keyof O]: O[K] }
|
||||
: never
|
||||
type MergeDiscriminatedUnion<U> =
|
||||
UnionToIntersection<U> extends infer O ? { [K in keyof O]: O[K] } : never
|
||||
|
||||
const libs = ['valibot', 'zod', 'arktype'] as const
|
||||
const schemasByLibrary = {
|
||||
|
|
|
@ -10,7 +10,7 @@ type Hook<
|
|||
E extends Env,
|
||||
P extends string,
|
||||
Target extends keyof ValidationTargets = keyof ValidationTargets,
|
||||
O = {}
|
||||
O = {},
|
||||
> = (
|
||||
result: (
|
||||
| { success: true; data: T }
|
||||
|
@ -42,7 +42,7 @@ const sValidator = <
|
|||
}
|
||||
out: { [K in Target]: Out }
|
||||
},
|
||||
V extends I = I
|
||||
V extends I = I,
|
||||
>(
|
||||
target: Target,
|
||||
schema: Schema,
|
||||
|
|
|
@ -148,7 +148,7 @@ export const renderSwaggerUIOptions = (options: DistSwaggerUIOptions) => {
|
|||
return ''
|
||||
}
|
||||
})
|
||||
.filter(item => item !== '')
|
||||
.filter((item) => item !== '')
|
||||
.join(',')
|
||||
|
||||
return optionsStrings
|
||||
|
|
|
@ -68,7 +68,7 @@ export function tbValidator<
|
|||
V extends {
|
||||
in: { [K in Target]: Static<T> }
|
||||
out: { [K in Target]: ExcludeResponseType<Static<T>> }
|
||||
}
|
||||
},
|
||||
>(
|
||||
target: Target,
|
||||
schema: T,
|
||||
|
|
|
@ -19,7 +19,8 @@ type BaseType<T> = T extends string
|
|||
: T extends bigint
|
||||
? bigint
|
||||
: T
|
||||
type Parsed<T> = T extends Record<string | number, any>
|
||||
type Parsed<T> =
|
||||
T extends Record<string | number, any>
|
||||
? {
|
||||
[K in keyof T]-?: T[K] extends (infer U)[]
|
||||
? (BaseType<U> | null | undefined)[] | undefined
|
||||
|
@ -31,7 +32,8 @@ export type QueryValidation<O extends Record<string | number, any> = any> = (
|
|||
input: string | URLSearchParams
|
||||
) => IValidation<O>
|
||||
export type QueryOutputType<T> = T extends QueryValidation<infer O> ? O : never
|
||||
type QueryStringify<T> = T extends Record<string | number, any>
|
||||
type QueryStringify<T> =
|
||||
T extends Record<string | number, any>
|
||||
? {
|
||||
// Suppress to split union types
|
||||
[K in keyof T]: [T[K]] extends [bigint | number | boolean]
|
||||
|
@ -47,7 +49,8 @@ export type HeaderValidation<O extends Record<string | number, any> = any> = (
|
|||
input: Record<string, string | string[] | undefined>
|
||||
) => IValidation<O>
|
||||
export type HeaderOutputType<T> = T extends HeaderValidation<infer O> ? O : never
|
||||
type HeaderStringify<T> = T extends Record<string | number, any>
|
||||
type HeaderStringify<T> =
|
||||
T extends Record<string | number, any>
|
||||
? {
|
||||
// Suppress to split union types
|
||||
[K in keyof T]: [T[K]] extends [bigint | number | boolean]
|
||||
|
@ -82,7 +85,7 @@ interface TypiaValidator {
|
|||
V extends { in: { query: QueryStringify<O> }; out: { query: O } } = {
|
||||
in: { query: QueryStringify<O> }
|
||||
out: { query: O }
|
||||
}
|
||||
},
|
||||
>(
|
||||
target: 'query',
|
||||
validate: T,
|
||||
|
@ -97,7 +100,7 @@ interface TypiaValidator {
|
|||
V extends { in: { header: HeaderStringify<O> }; out: { header: O } } = {
|
||||
in: { header: HeaderStringify<O> }
|
||||
out: { header: O }
|
||||
}
|
||||
},
|
||||
>(
|
||||
target: 'header',
|
||||
validate: T,
|
||||
|
@ -116,7 +119,7 @@ interface TypiaValidator {
|
|||
} = {
|
||||
in: { [K in Target]: O }
|
||||
out: { [K in Target]: O }
|
||||
}
|
||||
},
|
||||
>(
|
||||
target: Target,
|
||||
validate: T,
|
||||
|
|
|
@ -23,7 +23,7 @@ export const typiaValidator = <
|
|||
} = {
|
||||
in: { [K in Target]: O }
|
||||
out: { [K in Target]: O }
|
||||
}
|
||||
},
|
||||
>(
|
||||
target: Target,
|
||||
validate: T,
|
||||
|
|
|
@ -14,7 +14,7 @@ export type Hook<
|
|||
E extends Env,
|
||||
P extends string,
|
||||
Target extends keyof ValidationTargets = keyof ValidationTargets,
|
||||
O = {}
|
||||
O = {},
|
||||
> = (
|
||||
result: SafeParseResult<T> & {
|
||||
target: Target
|
||||
|
@ -45,7 +45,7 @@ export const vValidator = <
|
|||
}
|
||||
out: { [K in Target]: Out }
|
||||
},
|
||||
V extends I = I
|
||||
V extends I = I,
|
||||
>(
|
||||
target: Target,
|
||||
schema: T,
|
||||
|
|
|
@ -1,5 +1,12 @@
|
|||
# @hono/zod-openapi
|
||||
|
||||
## 0.19.6
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`8ed99d9d791ed6bd8b897c705289b0464947e632`](https://github.com/honojs/middleware/commit/8ed99d9d791ed6bd8b897c705289b0464947e632)]:
|
||||
- @hono/zod-validator@0.5.0
|
||||
|
||||
## 0.19.5
|
||||
|
||||
### Patch Changes
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@hono/zod-openapi",
|
||||
"version": "0.19.5",
|
||||
"version": "0.19.6",
|
||||
"description": "A wrapper class of Hono which supports OpenAPI.",
|
||||
"type": "module",
|
||||
"module": "dist/index.js",
|
||||
|
|
|
@ -73,7 +73,7 @@ type IsForm<T> = T extends string
|
|||
type ReturnJsonOrTextOrResponse<
|
||||
ContentType,
|
||||
Content,
|
||||
Status extends keyof StatusCodeRangeDefinitions | StatusCode
|
||||
Status extends keyof StatusCodeRangeDefinitions | StatusCode,
|
||||
> = ContentType extends string
|
||||
? ContentType extends `application/${infer Start}json${infer _End}`
|
||||
? Start extends '' | `${string}+` | `vnd.${string}+`
|
||||
|
@ -101,7 +101,7 @@ type HasUndefined<T> = undefined extends T ? true : false
|
|||
type InputTypeBase<
|
||||
R extends RouteConfig,
|
||||
Part extends string,
|
||||
Type extends keyof ValidationTargets
|
||||
Type extends keyof ValidationTargets,
|
||||
> = R['request'] extends RequestTypes
|
||||
? RequestPart<R, Part> extends ZodType
|
||||
? {
|
||||
|
@ -265,11 +265,8 @@ export type DeepSimplify<T> = {
|
|||
/**
|
||||
* Helper to infer generics from {@link MiddlewareHandler}
|
||||
*/
|
||||
export type OfHandlerType<T extends MiddlewareHandler> = T extends MiddlewareHandler<
|
||||
infer E,
|
||||
infer P,
|
||||
infer I
|
||||
>
|
||||
export type OfHandlerType<T extends MiddlewareHandler> =
|
||||
T extends MiddlewareHandler<infer E, infer P, infer I>
|
||||
? {
|
||||
env: E
|
||||
path: P
|
||||
|
@ -285,7 +282,7 @@ export type OfHandlerType<T extends MiddlewareHandler> = T extends MiddlewareHan
|
|||
export type MiddlewareToHandlerType<M extends MiddlewareHandler<any, any, any>[]> = M extends [
|
||||
infer First,
|
||||
infer Second,
|
||||
...infer Rest
|
||||
...infer Rest,
|
||||
]
|
||||
? First extends MiddlewareHandler<any, any, any>
|
||||
? Second extends MiddlewareHandler<any, any, any>
|
||||
|
@ -297,7 +294,7 @@ export type MiddlewareToHandlerType<M extends MiddlewareHandler<any, any, any>[]
|
|||
OfHandlerType<First>['path'], // Keep path from First
|
||||
OfHandlerType<First>['input'] // Keep input from First
|
||||
>,
|
||||
...Rest
|
||||
...Rest,
|
||||
]
|
||||
>
|
||||
: never
|
||||
|
@ -311,9 +308,8 @@ type RouteMiddlewareParams<R extends RouteConfig> = OfHandlerType<
|
|||
MiddlewareToHandlerType<AsArray<R['middleware']>>
|
||||
>
|
||||
|
||||
export type RouteConfigToEnv<R extends RouteConfig> = RouteMiddlewareParams<R> extends never
|
||||
? Env
|
||||
: RouteMiddlewareParams<R>['env']
|
||||
export type RouteConfigToEnv<R extends RouteConfig> =
|
||||
RouteMiddlewareParams<R> extends never ? Env : RouteMiddlewareParams<R>['env']
|
||||
|
||||
export type RouteHandler<
|
||||
R extends RouteConfig,
|
||||
|
@ -324,7 +320,7 @@ export type RouteHandler<
|
|||
InputTypeCookie<R> &
|
||||
InputTypeForm<R> &
|
||||
InputTypeJson<R>,
|
||||
P extends string = ConvertPathType<R['path']>
|
||||
P extends string = ConvertPathType<R['path']>,
|
||||
> = Handler<
|
||||
E,
|
||||
P,
|
||||
|
@ -352,7 +348,7 @@ export type RouteHook<
|
|||
InputTypeCookie<R> &
|
||||
InputTypeForm<R> &
|
||||
InputTypeJson<R>,
|
||||
P extends string = ConvertPathType<R['path']>
|
||||
P extends string = ConvertPathType<R['path']>,
|
||||
> = Hook<
|
||||
I,
|
||||
E,
|
||||
|
@ -371,7 +367,7 @@ export type OpenAPIObjectConfigure<E extends Env, P extends string> =
|
|||
export class OpenAPIHono<
|
||||
E extends Env = Env,
|
||||
S extends Schema = {},
|
||||
BasePath extends string = '/'
|
||||
BasePath extends string = '/',
|
||||
> extends Hono<E, S, BasePath> {
|
||||
openAPIRegistry: OpenAPIRegistry
|
||||
defaultHook?: OpenAPIHonoOptions<E>['defaultHook']
|
||||
|
@ -421,7 +417,7 @@ export class OpenAPIHono<
|
|||
InputTypeCookie<R> &
|
||||
InputTypeForm<R> &
|
||||
InputTypeJson<R>,
|
||||
P extends string = ConvertPathType<R['path']>
|
||||
P extends string = ConvertPathType<R['path']>,
|
||||
>(
|
||||
{ middleware: routeMiddleware, hide, ...route }: R,
|
||||
handler: Handler<
|
||||
|
@ -609,7 +605,7 @@ export class OpenAPIHono<
|
|||
SubPath extends string,
|
||||
SubEnv extends Env,
|
||||
SubSchema extends Schema,
|
||||
SubBasePath extends string
|
||||
SubBasePath extends string,
|
||||
>(
|
||||
path: SubPath,
|
||||
app: Hono<SubEnv, SubSchema, SubBasePath>
|
||||
|
@ -619,7 +615,7 @@ export class OpenAPIHono<
|
|||
SubPath extends string,
|
||||
SubEnv extends Env,
|
||||
SubSchema extends Schema,
|
||||
SubBasePath extends string
|
||||
SubBasePath extends string,
|
||||
>(
|
||||
path: SubPath,
|
||||
app?: Hono<SubEnv, SubSchema, SubBasePath>
|
||||
|
|
|
@ -1,5 +1,11 @@
|
|||
# @hono/zod-validator
|
||||
|
||||
## 0.5.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- [#1140](https://github.com/honojs/middleware/pull/1140) [`8ed99d9d791ed6bd8b897c705289b0464947e632`](https://github.com/honojs/middleware/commit/8ed99d9d791ed6bd8b897c705289b0464947e632) Thanks [@yusukebe](https://github.com/yusukebe)! - feat: add `validationFunction` option
|
||||
|
||||
## 0.4.3
|
||||
|
||||
### Patch Changes
|
||||
|
|
|
@ -68,6 +68,30 @@ app.post(
|
|||
)
|
||||
```
|
||||
|
||||
### Custom validation function
|
||||
|
||||
By default, this Validator validates values using `.safeParseAsync`.
|
||||
|
||||
```ts
|
||||
await schema.safeParseAsync(value)
|
||||
```
|
||||
|
||||
But, if you want to use the [`.passthrough`](https://zod.dev/?id=passthrough), you can specify your own function in `validationFunction`.
|
||||
|
||||
```ts
|
||||
app.post(
|
||||
'/',
|
||||
zValidator('json', schema, undefined, {
|
||||
validationFunction: async (schema, value) => {
|
||||
return await schema.passthrough().safeParseAsync(value)
|
||||
},
|
||||
}),
|
||||
(c) => {
|
||||
// ...
|
||||
}
|
||||
)
|
||||
```
|
||||
|
||||
## Author
|
||||
|
||||
Yusuke Wada <https://github.com/yusukebe>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@hono/zod-validator",
|
||||
"version": "0.4.3",
|
||||
"version": "0.5.0",
|
||||
"description": "Validator middleware using Zod",
|
||||
"type": "module",
|
||||
"main": "dist/index.js",
|
||||
|
|
|
@ -378,3 +378,85 @@ describe('Case-Insensitive Headers', () => {
|
|||
type verify = Expect<Equal<Expected, Actual>>
|
||||
})
|
||||
})
|
||||
|
||||
describe('With options + validationFunction', () => {
|
||||
const app = new Hono()
|
||||
const jsonSchema = z.object({
|
||||
name: z.string(),
|
||||
age: z.number(),
|
||||
})
|
||||
|
||||
const route = app
|
||||
.post('/', zValidator('json', jsonSchema), (c) => {
|
||||
const data = c.req.valid('json')
|
||||
return c.json({
|
||||
success: true,
|
||||
data,
|
||||
})
|
||||
})
|
||||
.post(
|
||||
'/extended',
|
||||
zValidator('json', jsonSchema, undefined, {
|
||||
validationFunction: async (schema, value) => {
|
||||
return await schema.passthrough().safeParseAsync(value)
|
||||
},
|
||||
}),
|
||||
(c) => {
|
||||
const data = c.req.valid('json')
|
||||
return c.json({
|
||||
success: true,
|
||||
data,
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
it('Should be ok due to passthrough schema', async () => {
|
||||
const req = new Request('http://localhost/extended', {
|
||||
body: JSON.stringify({
|
||||
name: 'Superman',
|
||||
age: 20,
|
||||
length: 170,
|
||||
weight: 55,
|
||||
}),
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
})
|
||||
const res = await app.request(req)
|
||||
expect(res).not.toBeNull()
|
||||
expect(res.status).toBe(200)
|
||||
expect(await res.json()).toEqual({
|
||||
success: true,
|
||||
data: {
|
||||
name: 'Superman',
|
||||
age: 20,
|
||||
length: 170,
|
||||
weight: 55,
|
||||
},
|
||||
})
|
||||
})
|
||||
it('Should be ok due to required schema', async () => {
|
||||
const req = new Request('http://localhost', {
|
||||
body: JSON.stringify({
|
||||
name: 'Superman',
|
||||
age: 20,
|
||||
}),
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
})
|
||||
const res = await app.request(req)
|
||||
|
||||
expect(res).not.toBeNull()
|
||||
expect(res.status).toBe(200)
|
||||
expect(await res.json()).toEqual({
|
||||
success: true,
|
||||
data: {
|
||||
name: 'Superman',
|
||||
age: 20,
|
||||
},
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
import type { Context, Env, Input, MiddlewareHandler, TypedResponse, ValidationTargets } from 'hono'
|
||||
import { validator } from 'hono/validator'
|
||||
import { ZodObject } from 'zod'
|
||||
import type { ZodError, ZodSchema, z } from 'zod'
|
||||
import type { SafeParseReturnType, ZodError, ZodSchema, z } from 'zod'
|
||||
|
||||
export type Hook<
|
||||
T,
|
||||
E extends Env,
|
||||
P extends string,
|
||||
Target extends keyof ValidationTargets = keyof ValidationTargets,
|
||||
O = {}
|
||||
O = {},
|
||||
> = (
|
||||
result: ({ success: true; data: T } | { success: false; error: ZodError; data: T }) & {
|
||||
target: Target
|
||||
|
@ -39,11 +39,18 @@ export const zValidator = <
|
|||
}
|
||||
out: { [K in Target]: Out }
|
||||
},
|
||||
V extends I = I
|
||||
V extends I = I,
|
||||
>(
|
||||
target: Target,
|
||||
schema: T,
|
||||
hook?: Hook<z.infer<T>, E, P, Target>
|
||||
hook?: Hook<z.infer<T>, E, P, Target>,
|
||||
options?: {
|
||||
validationFunction: (
|
||||
schema: T,
|
||||
value: ValidationTargets[Target]
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
) => SafeParseReturnType<any, any> | Promise<SafeParseReturnType<any, any>>
|
||||
}
|
||||
): MiddlewareHandler<E, P, V> =>
|
||||
// @ts-expect-error not typed well
|
||||
validator(target, async (value, c) => {
|
||||
|
@ -63,7 +70,10 @@ export const zValidator = <
|
|||
)
|
||||
}
|
||||
|
||||
const result = await schema.safeParseAsync(validatorValue)
|
||||
const result =
|
||||
options && options.validationFunction
|
||||
? await options.validationFunction(schema, validatorValue)
|
||||
: await schema.safeParseAsync(validatorValue)
|
||||
|
||||
if (hook) {
|
||||
const hookResult = await hook({ data: validatorValue, ...result, target }, c)
|
||||
|
|
Loading…
Reference in New Issue