import type { Pipe, Strings, Tuples } from 'hotscript'; import type { FromSchema as FromSchemaOriginal, JSONSchema as JSONSchemaOrBoolean } from 'json-schema-to-ts'; import type { ErrorHandler, FetchAPI, ServerAdapter, ServerAdapterOptions, ServerAdapterPlugin, ServerAdapterRequestHandler } from '@whatwg-node/server'; import type { ClientTypedResponsePromise } from './client/clientResponse.js'; import type { ClientRequestInit } from './client/types.js'; import type { SwaggerUIOpts } from './plugins/openapi.js'; import type { HTTPMethod, StatusCode, TypedRequest, TypedResponse, TypedResponseWithJSONStatusMap } from './typed-fetch.js'; export { TypedRequest as RouterRequest }; export type Simplify = { [KeyType in keyof T]: Simplify; } & {}; export type JSONSerializer = (obj: any) => string; export type JSONSchema = Exclude; export interface OpenAPIInfo { title?: string; description?: string; version?: string; license?: { name?: string; url?: string; }; termsOfService?: string; contact?: { name?: string; url?: string; email?: string; }; } export type OpenAPIPathObject = Record & { parameters?: OpenAPIParameterObject[]; }; export interface OpenAPIParameterObject { name: string; in: 'path' | 'query' | 'header' | 'cookie'; required?: boolean; schema?: any; } export interface OpenAPIRequestBodyObject { content?: Record; } export interface OpenAPIOperationObject { operationId?: string; description?: string; tags?: string[]; parameters?: OpenAPIParameterObject[]; requestBody?: OpenAPIRequestBodyObject; responses?: Record; security?: any[]; } export interface OpenAPIResponseObject { description?: string; content?: Record; } export interface OpenAPIMediaTypeObject { schema?: any; } export type OpenAPIDocument = { openapi?: string; info?: OpenAPIInfo; servers?: { url: string; }[] | string[]; paths?: Record; components?: unknown; }; export interface RouterOpenAPIOptions extends OpenAPIDocument { endpoint?: string | false; components?: TComponents; includeValidationErrors?: boolean; } export interface RouterSwaggerUIOptions extends SwaggerUIOpts { endpoint?: string | false; } export interface RouterOptions extends ServerAdapterOptions { base?: string; plugins?: RouterPlugin[]; openAPI?: RouterOpenAPIOptions; swaggerUI?: RouterSwaggerUIOptions; landingPage?: boolean; onError?: ErrorHandler; } export type RouterComponentsBase = { schemas?: Record; securitySchemes?: Record; }; export type BasicAuthSecurityScheme = { type: 'http'; scheme: 'basic'; }; export type BearerAuthSecurityScheme = { type: 'http'; scheme: 'bearer'; }; export type ApiKeySecurityScheme = { type: 'apiKey'; name: string; in: 'header' | 'query' | 'cookie'; }; export type SecurityScheme = BasicAuthSecurityScheme | BearerAuthSecurityScheme | ApiKeySecurityScheme; export type Circular = TJSONSchema extends { properties: { [key: string]: JSONSchema; }; } ? TJSONSchema extends PropertyValue> ? true : [Extract>, { $id: string; }>] extends [never] ? [ArrayItemValue>>] extends [never] ? Circular>> : ArrayItemValue>> extends TJSONSchema ? true : Circular>> : true : false; export type Property = keyof TJSONSchema['properties']; export type PropertyValue = TJSONSchema['properties'][TProperty]; export type ArrayItemValue = TJSONSchema extends { items: infer TItems extends JSONSchema; } ? TItems : never; type HasCircularAnyOfRef = T extends { properties: Record; } ? true extends { [K in keyof T['properties']]: PropIntroducesCycle; }[keyof T['properties']] ? true : false : false; type PropIntroducesCycle = S extends { anyOf: infer Items extends readonly JSONSchema[]; } ? TupleIntroducesCycle : S extends { oneOf: infer Items extends readonly JSONSchema[]; } ? TupleIntroducesCycle : S extends { items: infer I extends JSONSchema; } ? PropIntroducesCycle : S extends { $id: string; } ? false : S extends { properties: infer P extends Record; } ? true extends { [K in keyof P]: PropIntroducesCycle; }[keyof P] ? true : AdditionalPropertiesCycle : AdditionalPropertiesCycle; type AdditionalPropertiesCycle = S extends { additionalProperties: infer AP extends JSONSchema; } ? PropIntroducesCycle : false; type TupleIntroducesCycle = Items extends readonly [ infer Head extends JSONSchema, ...infer Tail extends readonly JSONSchema[] ] ? MemberIntroducesCycle extends true ? true : TupleIntroducesCycle : false; type MemberIntroducesCycle = Item extends { $id: string; } ? [Item] extends [Root] ? true : HasSelfCircularAnyOf : false; type HasSelfCircularAnyOf = T extends { properties: Record; } ? true extends { [K in keyof T['properties']]: DirectSelfAnyOf; }[keyof T['properties']] ? true : false : false; type DirectSelfAnyOf = S extends { anyOf: infer Items extends readonly JSONSchema[]; } ? TupleHasSelf : S extends { oneOf: infer Items extends readonly JSONSchema[]; } ? TupleHasSelf : S extends { items: infer I extends JSONSchema; } ? DirectSelfAnyOf : S extends { $id: string; } ? false : S extends { properties: infer P extends Record; } ? true extends { [K in keyof P]: DirectSelfAnyOf; }[keyof P] ? true : AdditionalPropertiesSelf : AdditionalPropertiesSelf; type AdditionalPropertiesSelf = S extends { additionalProperties: infer AP extends JSONSchema; } ? DirectSelfAnyOf : false; type TupleHasSelf = Items extends readonly [ infer Head extends JSONSchema, ...infer Tail extends readonly JSONSchema[] ] ? [Head] extends [Root] ? true : TupleHasSelf : false; export type DirectType = T extends { nullable: true; } ? DirectTypeValue | null : DirectTypeValue; type DirectTypeValue = T extends { static: infer U; } ? U : T extends { anyOf: infer Items extends readonly JSONSchema[]; } ? DirectUnionType : T extends { oneOf: infer Items extends readonly JSONSchema[]; } ? DirectUnionType : T extends { allOf: infer Items extends readonly JSONSchema[]; } ? DirectIntersectionType : T extends { type: 'array'; items: infer Items extends JSONSchema; } ? DirectType[] : T extends { type: 'string'; enum: infer Vals extends readonly string[]; } ? Vals[number] : T extends { type: 'string'; format: 'binary'; } ? File : T extends { type: 'string'; } ? string : T extends { type: 'integer' | 'number'; format: 'int64'; } ? number | bigint : T extends { type: 'integer' | 'number'; } ? number : T extends { type: 'boolean'; } ? boolean : T extends { type: 'null'; } ? null : T extends { type: 'object'; properties: infer Props extends Record; required: infer Req extends readonly string[]; additionalProperties: infer AP; } ? DirectNamedProps & DirectIndexSignature : T extends { type: 'object'; properties: infer Props extends Record; additionalProperties: infer AP; } ? DirectNamedProps & DirectIndexSignature : T extends { type: 'object'; properties: infer Props extends Record; required: infer Req extends readonly string[]; } ? DirectNamedProps : T extends { type: 'object'; properties: infer Props extends Record; } ? DirectNamedProps : T extends { type: 'object'; additionalProperties: infer AP; } ? AP extends false ? Record : DirectIndexSignature : T extends { type: 'object'; } ? Record : unknown; type DirectNamedProps, Req extends readonly string[] | undefined = undefined> = [Req] extends [readonly string[]] ? { [K in Extract]: DirectType; } & { [K in Exclude]?: DirectType; } : { [K in keyof Props]?: DirectType; }; type DirectIndexSignature = AP extends false ? unknown : AP extends true ? Record : AP extends JSONSchema ? Record> : Record; type DirectUnionType = Items extends readonly [ infer Head extends JSONSchema, ...infer Tail extends readonly JSONSchema[] ] ? DirectType | DirectUnionType : never; type DirectIntersectionType = Items extends readonly [ infer Head extends JSONSchema, ...infer Tail extends readonly JSONSchema[] ] ? DirectType & DirectIntersectionType : unknown; type UseDirectType = HasCircularAnyOfRef extends true ? true : Circular extends true ? true : false; export type FromSchema = T extends { static: infer U; } ? U : T extends JSONSchema ? UseDirectType extends true ? DirectType : FromSchemaOriginal : never; export type FromRouterComponentSchema, TName extends string> = TRouter extends Router ? TComponents extends Required ? FromSchema : never : never; export type PromiseOrValue = T | Promise; export type StatusCodeMap = { [TKey in StatusCode]?: T; }; export interface RouterBaseObject> { openAPIDocument: OpenAPIDocument; handle: ServerAdapterRequestHandler; route, TTypedResponse extends TypedResponseFromRouteSchemas>(opts: RouteWithSchemasOpts): Router>; route, Record, TMethod, any, Record, string>>, TTypedResponse extends TypedResponse>(opts: RouteWithTypesOpts): Router>; use>(subRouter: Router): Router; use>(prefix: TPrefix, subRouter: Router): Router; __client: TRouterSDK; __onRouterInitHooks: OnRouterInitHook[]; __routes: RouteWithSchemasOpts[]; __base: string; } export type Router> = ServerAdapter>; export type OnRouteHook = (payload: OnRouteHookPayload) => void; export type OnRouteHandleHook = (payload: OnRouteHandleHookPayload) => void; export interface OnRouteHandleHookPayload { request: TypedRequest; route: RouteWithSchemasOpts; } export type RouteHandler = ( /** * The request object represents the incoming HTTP request. * This object implements [Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) interface. */ request: TTypedRequest, context: TServerContext) => PromiseOrValue; export type OnRouteHookPayload = { basePath: string; openAPIDocument: OpenAPIDocument; routeByPatternByMethod: Map>>; routeByPathByMethod: Map>>; route: RouteWithSchemasOpts; fetchAPI: FetchAPI; }; export type OnRouterInitHook = (router: Router) => void; export type RouterPlugin = ServerAdapterPlugin & { onRouterInit?: OnRouterInitHook; onRoute?: OnRouteHook; onRouteHandle?: OnRouteHandleHook; }; type ObjectSchemaWithPrimitiveProperties = JSONSchema & { type: 'object'; properties: Record; }; type ObjectSchema = JSONSchema & { type: 'object'; }; export type RouteSchemas = { request?: { headers?: ObjectSchemaWithPrimitiveProperties; params?: ObjectSchemaWithPrimitiveProperties; query?: ObjectSchema; json?: JSONSchema; formData?: ObjectSchema; }; responses?: StatusCodeMap; }; export type RouterSDKOpts = TTypedRequest extends TypedRequest ? Simplify<(Partial extends TJSONBody ? { json?: TJSONBody; } : { json: TJSONBody; }) & (Partial extends THeaders ? { headers?: THeaders; } : { headers: THeaders; }) & (Partial extends TQueryParams ? { query?: TQueryParams; } : { query: TQueryParams; }) & (Partial extends TPathParam ? { params?: TPathParam; } : { params: TPathParam; })> & (Partial extends TFormData ? { formData?: TFormData; } : { formData: TFormData; }) : never; export type RouterSDK = { [TPathKey in TPath]: { [TMethod in Lowercase]: Partial> extends RouterSDKOpts ? (opts?: RouterSDKOpts & ClientRequestInit) => ClientTypedResponsePromise> : (opts: RouterSDKOpts & ClientRequestInit) => ClientTypedResponsePromise>; }; }; export type FromSchemaWithComponents = TComponents extends { schemas: Record; } ? FromSchema<{ components: TComponents; } & TSchema> : FromSchema; export type TypedRequestFromRouteSchemas = TRouteSchemas extends { request: Required['request']; } ? TypedRequest : {}, TRouteSchemas['request'] extends { formData: JSONSchema; } ? FromSchemaWithComponents extends Record ? FromSchemaWithComponents : never : {}, TRouteSchemas['request'] extends { headers: JSONSchema; } ? FromSchemaWithComponents extends Record ? FromSchemaWithComponents : never : {}, TMethod, TRouteSchemas['request'] extends { query: JSONSchema; } ? FromSchemaWithComponents : {}, TRouteSchemas['request'] extends { params: JSONSchema; } ? FromSchemaWithComponents extends Record ? FromSchemaWithComponents : never : Record, string>> : TypedRequest>, Partial>, TMethod, any, Record, string>>; export type TypedResponseFromRouteSchemas = TRouteSchemas extends { responses: StatusCodeMap; } ? TypedResponseWithJSONStatusMap<{ [TStatusCode in keyof TRouteSchemas['responses']]: TRouteSchemas['responses'][TStatusCode] extends JSONSchema ? FromSchemaWithComponents : never; }> : TypedResponse; export type RouteWithSchemasOpts, TTypedResponse extends TypedResponseFromRouteSchemas> = { schemas: TRouteSchemas; security?: SecuritySchemeRefsFromComponents[]; } & RouteWithTypesOpts; export type SecuritySchemeRefsFromComponents = TComponents extends { securitySchemes: Record; } ? Record : never; export type RouteWithTypesOpts, Record, TMethod, any, Record, string>>, TTypedResponse extends TypedResponse> = { operationId?: string; description?: string; method?: TMethod; tags?: string[]; internal?: boolean; path: TPath; handler: RouteHandler; }; export type RouteInput, TPath extends string, TMethod extends Lowercase = 'post', TParamType extends keyof RouterSDKOpts = 'json'> = TRouter extends Router ? TRouterSDK[TPath][TMethod] extends (requestParams?: infer TRequestParams) => any ? TRequestParams extends { [TParamTypeKey in TParamType]?: infer TParamTypeValue; } ? TParamTypeValue : never : never : never; export type RouteOutput, TPath extends string, TMethod extends Lowercase = 'post', TStatusCode extends StatusCode = 200> = TRouter extends Router ? TRouterSDK extends RouterSDK ? TRouterSDK[TPath][TMethod] extends (...args: any[]) => Promise ? TTypedResponse extends TypedResponse ? TJSONBody : never : never : never : never; export type RouterClient> = TRouter['__client']; export type RouterInput> = { [TPath in keyof RouterClient]: { [TMethod in keyof RouterClient[TPath]]: RouterClient[TPath][TMethod] extends (requestParams?: infer TRequestParams) => any ? Required : never; }; }; export type RouterJsonPostInput> = { [TPath in keyof RouterClient]: { [TMethod in keyof RouterClient[TPath]]: RouterInput[TPath][TMethod] extends { json: infer TJSON; } ? TJSON : never; }['post']; }; export type RouterJsonPostSuccessOutput> = { [TPath in keyof RouterClient]: { [TMethod in keyof RouterClient[TPath]]: RouterOutput[TPath][TMethod][200]; }['post']; }; export type RouterOutput> = { [TPath in keyof RouterClient]: { [TMethod in keyof RouterClient[TPath]]: RouterClient[TPath][TMethod] extends (requestParams?: any) => Promise ? { [TStatusCode in StatusCode]: TTypedResponse extends TypedResponse ? TJSONBody : never; } : never; }; }; export type RouterComponentSchema, TName extends string> = TRouter extends Router ? TComponents extends { schemas: Record; } ? FromSchema : never : never; type SplitByDelimiter = T extends `${infer P}${D}${infer Q}` ? [P, ...SplitByDelimiter] : [T]; type IsPathParameter = T extends `{${infer U}}` ? U : never; type ExtractPathParametersFromSegment = IsPathParameter; type ExtractPathParameters = { [K in keyof T]: ExtractPathParametersFromSegment; }; type TupleToUnion = T extends any[] ? T[number] : never; type ExtractSegments = SplitByDelimiter; type ExtractSubSegments = { [K in keyof T]: SplitByDelimiter; }; export type ExtractPathParamsWithBrackets = TupleToUnion>[number]>>; export type ExtractPathParamsWithPattern = Pipe, Tuples.Filter>, Tuples.Map>, Tuples.ToUnion ]>;