import type { Hono } from '../hono'; import type { HonoBase } from '../hono-base'; import type { Endpoint, ResponseFormat, Schema } from '../types'; import type { StatusCode, SuccessStatusCode } from '../utils/http-status'; import type { HasRequiredKeys } from '../utils/types'; type HonoRequest = (typeof Hono.prototype)["request"]; export type ClientRequestOptions = { fetch?: typeof fetch | HonoRequest; webSocket?: (...args: ConstructorParameters) => WebSocket; /** * Standard `RequestInit`, caution that this take highest priority * and could be used to overwrite things that Hono sets for you, like `body | method | headers`. * * If you want to add some headers, use in `headers` instead of `init` */ init?: RequestInit; } & (keyof T extends never ? { headers?: Record | (() => Record | Promise>); } : { headers: T | (() => T | Promise); }); export type ClientRequest = { [M in keyof S]: S[M] extends Endpoint & { input: infer R; } ? R extends object ? HasRequiredKeys extends true ? (args: R, options?: ClientRequestOptions) => Promise> : (args?: R, options?: ClientRequestOptions) => Promise> : never : never; } & { $url: (arg?: S[keyof S] extends { input: infer R; } ? R extends { param: infer P; } ? R extends { query: infer Q; } ? { param: P; query: Q; } : { param: P; } : R extends { query: infer Q; } ? { query: Q; } : {} : {}) => URL; } & (S["$get"] extends { outputFormat: "ws"; } ? S["$get"] extends { input: infer I; } ? { $ws: (args?: I) => WebSocket; } : {} : {}); type ClientResponseOfEndpoint = T extends { output: infer O; outputFormat: infer F; status: infer S; } ? ClientResponse : never; export interface ClientResponse extends globalThis.Response { readonly body: ReadableStream | null; readonly bodyUsed: boolean; ok: U extends SuccessStatusCode ? true : U extends Exclude ? false : boolean; status: U; statusText: string; headers: Headers; url: string; redirect(url: string, status: number): Response; clone(): Response; json(): F extends "text" ? Promise : F extends "json" ? Promise : Promise; text(): F extends "text" ? (T extends string ? Promise : Promise) : Promise; blob(): Promise; formData(): Promise; arrayBuffer(): Promise; } export interface Response extends ClientResponse { } export type Fetch = (args?: InferRequestType, opt?: ClientRequestOptions) => Promise>>; type InferEndpointType = T extends (args: infer R, options: any | undefined) => Promise ? U extends ClientResponse ? { input: NonNullable; output: O; outputFormat: F; status: S; } extends Endpoint ? { input: NonNullable; output: O; outputFormat: F; status: S; } : never : never : never; export type InferResponseType = InferResponseTypeFromEndpoint, U>; type InferResponseTypeFromEndpoint = T extends { output: infer O; status: infer S; } ? S extends U ? O : never : never; export type InferRequestType = T extends (args: infer R, options: any | undefined) => Promise> ? NonNullable : never; export type InferRequestOptionsType = T extends (args: any, options: infer R) => Promise> ? NonNullable : never; /** * Filter a ClientResponse type so it only includes responses of specific status codes. */ export type FilterClientResponseByStatusCode, U extends number = StatusCode> = T extends ClientResponse ? RC extends U ? ClientResponse : never : never; type PathToChain = Path extends `/${infer P}` ? PathToChain : Path extends `${infer P}/${infer R}` ? { [K in P]: PathToChain; } : { [K in Path extends "" ? "index" : Path]: ClientRequest ? E[Original] : never>; }; export type Client = T extends HonoBase ? S extends Record ? K extends string ? PathToChain : never : never : never; export type Callback = (opts: CallbackOptions) => unknown; interface CallbackOptions { path: string[]; args: any[]; } export type ObjectType = { [key: string]: T; }; export {};