import type { StandardSchemaV1 } from '@standard-schema/spec' import type { Context, Env, Input, MiddlewareHandler, TypedResponse, ValidationTargets } from 'hono' import { validator } from 'hono/validator' type HasUndefined = undefined extends T ? true : false type TOrPromiseOfT = T | Promise type Hook< T, E extends Env, P extends string, Target extends keyof ValidationTargets = keyof ValidationTargets, O = {} > = ( result: ( | { success: true; data: T } | { success: false; error: ReadonlyArray; data: T } ) & { target: Target }, c: Context ) => TOrPromiseOfT> const sValidator = < Schema extends StandardSchemaV1, Target extends keyof ValidationTargets, E extends Env, P extends string, In = StandardSchemaV1.InferInput, Out = StandardSchemaV1.InferOutput, I extends Input = { in: HasUndefined extends true ? { [K in Target]?: In extends ValidationTargets[K] ? In : { [K2 in keyof In]?: ValidationTargets[K][K2] } } : { [K in Target]: In extends ValidationTargets[K] ? In : { [K2 in keyof In]: ValidationTargets[K][K2] } } out: { [K in Target]: Out } }, V extends I = I >( target: Target, schema: Schema, hook?: Hook, E, P, Target> ): MiddlewareHandler => // @ts-expect-error not typed well validator(target, async (value, c) => { const result = await schema['~standard'].validate(value) if (hook) { const hookResult = await hook( result.issues ? { data: value, error: result.issues, success: false, target } : { data: value, success: true, target }, c ) if (hookResult) { if (hookResult instanceof Response) { return hookResult } if ('response' in hookResult) { return hookResult.response } } } if (result.issues) { return c.json({ data: value, error: result.issues, success: false }, 400) } return result.value as StandardSchemaV1.InferOutput }) export type { Hook } export { sValidator }