// https://github.com/remorses/elysia/blob/main/src/types.ts#L6 import { StandardSchemaV1 } from '@standard-schema/spec' import z from 'zod' import type { OpenAPIV3 } from 'openapi-types' import { ZodTypeAny } from 'zod' import type { Context, ErrorContext, MiddlewareContext } from './context.ts' import { SPICEFLOW_RESPONSE, ValidationError } from './error.ts' import { AnySpiceflow, Spiceflow } from './spiceflow.ts' export type MaybeArray = T | T[] export type MaybePromise = T | Promise export type MaybePromiseIterable = T | Promise | AsyncIterable export type ObjectValues = T[keyof T] type IsPathParameter = Part extends `:${infer Parameter}` ? Parameter : Part extends `*` ? '*' : never export type GetPathParameter = Path extends `${infer A}/${infer B}` ? IsPathParameter | GetPathParameter : IsPathParameter export type ResolvePath = Prettify< { [Param in GetPathParameter as Param extends `${string}?` ? never : Param]: string } & { [Param in GetPathParameter as Param extends `${infer OptionalParam}?` ? OptionalParam : never]?: string } > // https://twitter.com/mattpocockuk/status/1622730173446557697?s=20 export type Prettify = { [K in keyof T]: T[K] } & {} export type Prettify2 = { [K in keyof T]: Prettify } & {} export type Partial2 = { [K in keyof T]?: Partial } export type NeverKey = { [K in keyof T]?: T[K] } & {} type IsBothObject = A extends Record ? B extends Record ? IsClass extends false ? IsClass extends false ? true : false : false : false : false type IsClass = V extends abstract new (...args: any) => any ? true : false export type Reconcile< A extends Object, B extends Object, Override extends boolean = false, // Detect Stack limit, eg. circular dependency Stack extends number[] = [], > = Stack['length'] extends 16 ? A : Override extends true ? { [key in keyof A as key extends keyof B ? never : key]: A[key] } extends infer Collision ? {} extends Collision ? { [key in keyof B]: IsBothObject< // @ts-ignore trust me bro A[key], B[key] > extends true ? Reconcile< // @ts-ignore trust me bro A[key], B[key], Override, [0, ...Stack] > : B[key] } : Prettify< Collision & { [key in keyof B]: B[key] } > : never : { [key in keyof B as key extends keyof A ? never : key]: B[key] } extends infer Collision ? {} extends Collision ? { [key in keyof A]: IsBothObject< A[key], // @ts-ignore trust me bro B[key] > extends true ? Reconcile< // @ts-ignore trust me bro A[key], // @ts-ignore trust me bro B[key], Override, [0, ...Stack] > : A[key] } : Prettify< { [key in keyof A]: A[key] } & Collision > : never export interface SingletonBase { state: Record } export interface DefinitionBase { type: Record error: Record } export type RouteBase = Record export interface MetadataBase { schema: RouteSchema macro: BaseMacro macroFn: BaseMacroFn } export type RouteSchema = { body?: unknown request?: unknown query?: unknown params?: unknown response?: unknown } export type TypeSchema = StandardSchemaV1 export type TypeObject = StandardSchemaV1 export type UnwrapSchema< Schema extends TypeSchema | string | undefined, Definitions extends Record = {}, > = Schema extends undefined ? unknown : Schema extends StandardSchemaV1 ? StandardSchemaV1.InferOutput : Schema extends ZodTypeAny ? z.infer : Schema extends string ? Definitions extends Record ? NamedSchema : Definitions : unknown export type GetRequestSchema> = 'request' extends keyof Schema ? Schema['request'] : 'body' extends keyof Schema ? Schema['body'] : undefined export interface UnwrapRoute< in out Schema extends InputSchema, in out Definitions extends DefinitionBase['type'] = {}, > { request: UnwrapSchema, Definitions> query: UnwrapSchema params: UnwrapSchema response: Schema['response'] extends TypeSchema | string ? { 200: UnwrapSchema } : Schema['response'] extends Record ? { [k in keyof Schema['response']]: UnwrapSchema< Schema['response'][k], Definitions > } : unknown | void } export type LifeCycleEvent = | 'start' | 'request' | 'parse' | 'transform' | 'beforeHandle' | 'afterHandle' | 'response' | 'error' | 'stop' export type ContentType = MaybeArray< | (string & {}) // | 'none' // | 'text' // | 'json' // | 'formdata' // | 'urlencoded' // | 'arrayBuffer' | 'text/plain' | 'application/json' | 'multipart/form-data' | 'application/x-www-form-urlencoded' > export type HTTPMethod = | (string & {}) | 'ACL' | 'BIND' | 'CHECKOUT' | 'CONNECT' | 'COPY' | 'DELETE' | 'GET' | 'HEAD' | 'LINK' | 'LOCK' | 'M-SEARCH' | 'MERGE' | 'MKACTIVITY' | 'MKCALENDAR' | 'MKCOL' | 'MOVE' | 'NOTIFY' | 'OPTIONS' | 'PATCH' | 'POST' | 'PROPFIND' | 'PROPPATCH' | 'PURGE' | 'PUT' | 'REBIND' | 'REPORT' | 'SEARCH' | 'SOURCE' | 'SUBSCRIBE' | 'TRACE' | 'UNBIND' | 'UNLINK' | 'UNLOCK' | 'UNSUBSCRIBE' | 'ALL' | '*' export interface InputSchema { /** * @deprecated The 'body' property is deprecated, use request instead. */ body?: TypeSchema | Name request?: TypeSchema | Name query?: TypeObject | Name params?: TypeObject | Name response?: | TypeSchema | Record | Name | Record } export interface MergeSchema< in out A extends RouteSchema, in out B extends RouteSchema, > { request: undefined extends GetRequestSchema ? GetRequestSchema : GetRequestSchema query: undefined extends A['query'] ? B['query'] : A['query'] params: undefined extends A['params'] ? B['params'] : A['params'] response: {} extends A['response'] ? {} extends B['response'] ? {} : B['response'] : {} extends B['response'] ? A['response'] : A['response'] & Omit } export type Handler< in out Route extends RouteSchema = {}, in out Singleton extends SingletonBase = { state: {} }, Path extends string = '', > = ( context: Context, ) => MaybePromise< {} extends Route['response'] ? unknown : Route['response'][keyof Route['response']] > export type Replace = IsAny extends true ? Original : Original extends Record ? { [K in keyof Original]: Original[K] extends Target ? With : Original[K] } : Original extends Target ? With : Original export type IsAny = 0 extends 1 & T ? true : false export type CoExist = IsAny extends true ? Original : Original extends Record ? { [K in keyof Original]: Original[K] extends Target ? Original[K] | With : Original[K] } : Original extends Target ? Original | With : Original type ResponseLike = { status: number headers?: any body?: any } export type InlineHandler< This, Route extends RouteSchema = {}, Singleton extends SingletonBase = { state: {} }, Path extends string = '', MacroContext = {}, > = ( this: This, context: MacroContext extends Record ? Prettify> : Context, ) => | ResponseLike | MaybePromiseIterable< {} extends Route['response'] ? unknown : | (Route['response'] extends { 200: any } ? Route['response'] : string | number | boolean | Object) | Route['response'][keyof Route['response']] | { [Status in keyof Route['response']]: { _type: Record [SPICEFLOW_RESPONSE]: Status } }[keyof Route['response']] > export type OptionalHandler< in out Route extends RouteSchema = {}, in out Singleton extends SingletonBase = { state: {} }, Path extends string = '', > = Handler extends ( context: infer Context, ) => infer Returned ? (context: Context) => Returned | MaybePromise : never export type AfterHandler< in out Route extends RouteSchema = {}, in out Singleton extends SingletonBase = { state: {} }, Path extends string = '', > = Handler extends ( context: infer Context, ) => infer Returned ? ( context: Prettify< { response: Route['response'] } & Context >, ) => Returned | MaybePromise : never export type MapResponse< in out Route extends RouteSchema = {}, in out Singleton extends SingletonBase = { state: {} }, Path extends string = '', > = Handler< Omit & { response: MaybePromise }, Singleton & { derive: { response: Route['response'] } }, Path > export type VoidHandler< in out Route extends RouteSchema = {}, in out Singleton extends SingletonBase = { state: {} }, > = (context: Context) => MaybePromise export type TransformHandler< in out Route extends RouteSchema = {}, in out Singleton extends SingletonBase = { state: {} }, BasePath extends string = '', > = { ( context: Prettify< Context< Route, Omit & { resolve: {} }, BasePath > >, ): MaybePromise } export type BodyHandler< in out Route extends RouteSchema = {}, in out Singleton extends SingletonBase = { state: {} }, Path extends string = '', > = ( context: Prettify< { contentType: string } & Context >, contentType: string, ) => MaybePromise export type MiddlewareHandler< in out Route extends RouteSchema = {}, in out Singleton extends SingletonBase = any, > = ( context: MiddlewareContext, next: () => Promise, ) => MaybePromise export type AfterResponseHandler< in out Route extends RouteSchema = {}, in out Singleton extends SingletonBase = { state: {} }, > = ( context: Prettify< Context & { response: Route['response'] } >, ) => MaybePromise // export type GracefulHandler< // in Instance extends AnySpiceflow, // > = (data: Instance) => any export type ErrorHandler< in out T extends Record = {}, in out Route extends RouteSchema = {}, in out Singleton extends SingletonBase = { state: {} }, > = ( context: ErrorContext< Route, { state: Singleton['state'] } > & ( | Prettify< { request: Request code: 'UNKNOWN' error: Readonly } & Partial > | Prettify< { request: Request code: 'VALIDATION' error: Readonly } & Singleton['state'] > // | Prettify< // { // request: Request // code: 'NOT_FOUND' // error: Readonly // } & NeverKey // > // Removed ParseError and InternalServerError from here | Prettify< { [K in keyof T]: { request: Request code: K error: Readonly } }[keyof T] & Partial > ), ) => any | Promise export type Isolate = { [P in keyof T]: T[P] } export type DocumentDecoration = Partial & { /** * Pass `true` to hide route from OpenAPI/swagger document * */ hide?: boolean // 'x-fern-type-name'?: string 'x-fern-sdk-group-name'?: string | string[] 'x-fern-sdk-method-name'?: string 'x-fern-webhook'?: boolean } export type LocalHook< LocalSchema extends InputSchema, Schema extends RouteSchema, Singleton extends SingletonBase, Errors extends Record, Extension extends BaseMacro, Path extends string = '', TypedRoute extends RouteSchema = Schema extends { params: Record } ? Schema : Schema & { params: undefined extends Schema['params'] ? ResolvePath : Schema['params'] }, > = (LocalSchema extends {} ? LocalSchema : Isolate) & Extension & { detail?: DocumentDecoration bodyType?: ContentType type?: ContentType } export type ComposedHandler = (context: Context) => MaybePromise export interface InternalRoute { method: HTTPMethod path: string composed: ComposedHandler | Response | null handler: Handler hooks: LocalHook } export type AddPrefix = { [K in keyof T as Prefix extends string ? `${Prefix}${K & string}` : K]: T[K] } export type AddPrefixCapitalize = { [K in keyof T as `${Prefix}${Capitalize}`]: T[K] } export type AddSuffix = { [K in keyof T as `${K & string}${Suffix}`]: T[K] } export type AddSuffixCapitalize = { [K in keyof T as `${K & string}${Capitalize}`]: T[K] } export type BaseMacro = Record< string, string | number | boolean | Object | undefined | null > export type BaseMacroFn = Record unknown> type _CreateClient< Path extends string, Property extends Record = {}, > = Path extends `${infer Start}/${infer Rest}` ? { [x in Start]: _CreateClient } : { [x in Path]: Property } export type CreateClient< Path extends string, Property extends Record = {}, > = Path extends `/${infer Rest}` ? _CreateClient : Path extends '' ? _CreateClient<'index', Property> : _CreateClient export type ComposeSpiceflowResponse = Handle extends ( ...a: any[] ) => infer A ? _ComposeSpiceflowResponse> : _ComposeSpiceflowResponse> type _ComposeSpiceflowResponse = Prettify< {} extends Response ? { 200: Exclude } & { [ErrorResponse in Extract< Handle, { response: any } > as ErrorResponse extends { [SPICEFLOW_RESPONSE]: infer Status extends number } ? Status : never]: ErrorResponse['response'] } : Response > export type MergeSpiceflowInstances< Instances extends AnySpiceflow[] = [], Prefix extends string = '', Scoped extends boolean = false, Singleton extends SingletonBase = { state: {} }, Definitions extends DefinitionBase = { type: {} error: {} }, Metadata extends MetadataBase = { schema: {} macro: {} macroFn: {} }, Routes extends RouteBase = {}, > = Instances extends [ infer Current extends AnySpiceflow, ...infer Rest extends AnySpiceflow[], ] ? Current['_types']['Scoped'] extends true ? MergeSpiceflowInstances< Rest, Prefix, Scoped, Singleton, Definitions, Metadata, Routes > : MergeSpiceflowInstances< Rest, Prefix, Scoped, Singleton & Current['_types']['Singleton'], Definitions & Current['_types']['Definitions'], Metadata & Current['_types']['Metadata'], Routes & (Prefix extends `` ? Current['_types']['ClientRoutes'] : AddPrefix) > : Spiceflow< Prefix, Scoped, { state: Prettify }, { type: Prettify error: Prettify }, { schema: Prettify macro: Prettify macroFn: Prettify }, Routes > export type LifeCycleType = 'global' | 'local' | 'scoped' export type UnionToIntersect = ( U extends unknown ? (arg: U) => 0 : never ) extends (arg: infer I) => 0 ? I : never export type ContextAppendType = 'append' | 'override' export type HTTPHeaders = Record & { // Authentication 'www-authenticate'?: string authorization?: string 'proxy-authenticate'?: string 'proxy-authorization'?: string // Caching age?: string 'cache-control'?: string 'clear-site-data'?: string expires?: string 'no-vary-search'?: string pragma?: string // Conditionals 'last-modified'?: string etag?: string 'if-match'?: string 'if-none-match'?: string 'if-modified-since'?: string 'if-unmodified-since'?: string vary?: string // Connection management connection?: string 'keep-alive'?: string // Content negotiation accept?: string 'accept-encoding'?: string 'accept-language'?: string // Controls expect?: string 'max-forwards'?: string // Cokies cookie?: string 'set-cookie'?: string | string[] // CORS 'access-control-allow-origin'?: string 'access-control-allow-credentials'?: string 'access-control-allow-headers'?: string 'access-control-allow-methods'?: string 'access-control-expose-headers'?: string 'access-control-max-age'?: string 'access-control-request-headers'?: string 'access-control-request-method'?: string origin?: string 'timing-allow-origin'?: string // Downloads 'content-disposition'?: string // Message body information 'content-length'?: string 'content-type'?: string 'content-encoding'?: string 'content-language'?: string 'content-location'?: string // Proxies forwarded?: string via?: string // Redirects location?: string refresh?: string // Request context // from?: string // host?: string // referer?: string // 'user-agent'?: string // Response context allow?: string server?: 'spiceflow' | (string & {}) // Range requests 'accept-ranges'?: string range?: string 'if-range'?: string 'content-range'?: string // Security 'content-security-policy'?: string 'content-security-policy-report-only'?: string 'cross-origin-embedder-policy'?: string 'cross-origin-opener-policy'?: string 'cross-origin-resource-policy'?: string 'expect-ct'?: string 'permission-policy'?: string 'strict-transport-security'?: string 'upgrade-insecure-requests'?: string 'x-content-type-options'?: string 'x-frame-options'?: string 'x-xss-protection'?: string // Server-sent events 'last-event-id'?: string 'ping-from'?: string 'ping-to'?: string 'report-to'?: string // Transfer coding te?: string trailer?: string 'transfer-encoding'?: string // Other 'alt-svg'?: string 'alt-used'?: string date?: string dnt?: string 'early-data'?: string 'large-allocation'?: string link?: string 'retry-after'?: string 'service-worker-allowed'?: string 'source-map'?: string upgrade?: string // Non-standard 'x-dns-prefetch-control'?: string 'x-forwarded-for'?: string 'x-forwarded-host'?: string 'x-forwarded-proto'?: string 'x-powered-by'?: 'spiceflow' | (string & {}) 'x-request-id'?: string 'x-requested-with'?: string 'x-robots-tag'?: string 'x-ua-compatible'?: string } export type JoinPath = `${A}${B extends '/' ? '/index' : B extends '' ? B : B extends `/${string}` ? B : B}` export type PartialWithRequired = Partial> & Pick export type GetPathsFromRoutes> = Routes extends Record ? (K extends string ? K : never) : never export type ExtractParamsFromPath = Path extends `${string}:${infer Param}/${infer Rest}` ? { [K in Param]: string } & ExtractParamsFromPath<`/${Rest}`> : Path extends `${string}:${infer Param}` ? { [K in Param]: string } : Path extends `${string}*${infer StarRest}` ? { ['*']: string } : undefined