UNPKG

elysia

Version:

Ergonomic Framework for Human

958 lines (957 loc) 47.1 kB
import type { Elysia, AnyElysia } from '.'; import type { ElysiaFile } from './universal/file'; import type { Serve } from './universal/server'; import { TSchema, TAnySchema, OptionalKind, TModule, TImport, TProperties } from '@sinclair/typebox'; import type { TypeCheck, ValueError } from '@sinclair/typebox/compiler'; import type { OpenAPIV3 } from 'openapi-types'; import type { ElysiaAdapter } from './adapter'; import type { ElysiaTypeCheck } from './schema'; import type { Context, ErrorContext, PreContext } from './context'; import type { ComposerGeneralHandlerOptions } from './compose'; import type { CookieOptions } from './cookies'; import type { TraceHandler } from './trace'; import type { ElysiaCustomStatusResponse, InternalServerError, InvalidCookieSignature, InvalidFileType, NotFoundError, ParseError, ValidationError } from './error'; import type { AnyWSLocalHook } from './ws/types'; import type { WebSocketHandler } from './ws/bun'; import type { Instruction as ExactMirrorInstruction } from 'exact-mirror'; type PartialServe = Partial<Serve>; export type IsNever<T> = [T] extends [never] ? true : false; export interface ElysiaConfig<Prefix extends string | undefined> { /** * @default BunAdapter * @since 1.1.11 */ adapter?: ElysiaAdapter; /** * Path prefix of the instance * * @default ''' */ prefix?: Prefix; /** * Name of the instance for debugging, and plugin deduplication purpose */ name?: string; /** * Seed for generating checksum for plugin deduplication * * @see https://elysiajs.com/essential/plugin.html#plugin-deduplication */ seed?: unknown; /** * Bun serve * * @see https://bun.sh/docs/api/http */ serve?: PartialServe; /** * OpenAPI documentation (use in Swagger) * * @see https://swagger.io/specification/ */ detail?: DocumentDecoration; /** * OpenAPI tags * * current instance' routes with tags * * @see https://swagger.io/specification/#tag-object */ tags?: DocumentDecoration['tags']; /** * Warm up Elysia before starting the server * * This will perform Ahead of Time compilation and generate code for route handlers * * If set to false, Elysia will perform Just in Time compilation * * Only required for root instance (instance which use listen) to effect * * ! If performing a benchmark, it's recommended to set this to `true` * * @default false */ precompile?: boolean | { /** * Perform dynamic code generation for route handlers before starting the server * * @default false */ compose?: boolean; /** * Perform Ahead of Time compilation for schema before starting the server * * @default false */ schema?: boolean; }; /** * Enable Ahead of Time compilation * * Trade significant performance with slightly faster startup time and reduced memory usage */ aot?: boolean; /** * Whether should Elysia tolerate suffix '/' or vice-versa * * @default false */ strictPath?: boolean; /** * Override websocket configuration * * @see https://bun.sh/docs/api/websockets */ websocket?: Omit<WebSocketHandler<any>, 'open' | 'close' | 'message' | 'drain'>; cookie?: CookieOptions & { /** * Specified cookie name to be signed globally */ sign?: true | string | string[]; }; /** * Capture more detail information for each dependencies */ analytic?: boolean; /** * If enabled, the schema with `t.Transform` will call `Encode` before sending the response * * @default true * @since 1.3.0 * @since 1.2.16 (experimental) **/ encodeSchema?: boolean; /** * Enable experimental features */ experimental?: {}; /** * If enabled, Elysia will attempt to coerce value to defined type on incoming and outgoing bodies. * * This allows for sending unknown or disallowed properties in the bodies. These will simply be filtered out instead of failing the request. * This has no effect when the schemas allow additional properties. * Since this uses dynamic schema it may have an impact on performance. * * options: * - true: use 'exactMirror' * - false: do not normalize the value * - 'exactMirror': use Elysia's custom exact-mirror which precompile a schema * - 'typebox': Since this uses dynamic Value.Clean, it have performance impact * * @default true */ normalize?: boolean | 'exactMirror' | 'typebox'; handler?: ComposerGeneralHandlerOptions; /** * Enable Bun static response * * @default true * @since 1.1.11 */ nativeStaticResponse?: boolean; /** * Use runtime/framework provided router if possible * * @default true * @since 1.3.0 */ systemRouter?: boolean; /** * Array of callback function to transform a string value defined in a schema * * This option only works when `sanitlize` is `exactMirror` * * This only works when set on the main instance * * @default true * @since 1.3.0 */ sanitize?: ExactMirrorInstruction['sanitize']; } export interface ValidatorLayer { global: SchemaValidator | null; scoped: SchemaValidator | null; local: SchemaValidator | null; getCandidate(): SchemaValidator; } export interface StandaloneInputSchema<Name extends string = string> { body?: TSchema | Name | `${Name}[]`; headers?: TSchema | Name | `${Name}[]`; query?: TSchema | Name | `${Name}[]`; params?: TSchema | Name | `${Name}[]`; cookie?: TSchema | Name | `${Name}[]`; response?: { [status in number]: `${Name}[]` | Name | TSchema; }; } export interface StandaloneValidator { global: InputSchema[] | null; scoped: InputSchema[] | null; local: InputSchema[] | null; } export type MaybeArray<T> = T | T[]; export type MaybeReadonlyArray<T> = T | readonly T[]; export type MaybePromise<T> = T | Promise<T>; export type ObjectValues<T extends object> = T[keyof T]; type IsPathParameter<Part extends string> = Part extends `:${infer Parameter}` ? Parameter : Part extends `*` ? '*' : never; export type GetPathParameter<Path extends string> = Path extends `${infer A}/${infer B}` ? IsPathParameter<A> | GetPathParameter<B> : IsPathParameter<Path>; export type ResolvePath<Path extends string> = Prettify<{ [Param in GetPathParameter<Path> as Param extends `${string}?` ? never : Param]: string; } & { [Param in GetPathParameter<Path> as Param extends `${infer OptionalParam}?` ? OptionalParam : never]?: string; }>; export type Or<T1 extends boolean, T2 extends boolean> = T1 extends true ? true : T2 extends true ? true : false; export type Prettify<T> = { [K in keyof T]: T[K]; } & {}; export type Prettify2<T> = { [K in keyof T]: T extends { [key in keyof any]: unknown; } ? Prettify<T[K]> : T[K]; } & {}; export type Partial2<T> = { [K in keyof T]?: Partial<T[K]>; }; export type NeverKey<T> = { [K in keyof T]?: T[K]; } & {}; type IsBothObject<A, B> = A extends Record<keyof any, any> ? B extends Record<keyof any, any> ? IsClass<A> extends false ? IsClass<B> extends false ? true : false : false : false : false; type IsClass<V> = V extends abstract new (...args: any) => any ? true : false; export type Reconcile<A extends Object, B extends Object, Override extends boolean = false, 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<A[key], B[key]> extends true ? Reconcile<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], B[key]> extends true ? Reconcile<A[key], B[key], Override, [ 0, ...Stack ]> : A[key]; } : Prettify<{ [key in keyof A]: A[key]; } & Collision> : never; export interface SingletonBase { decorator: Record<string, unknown>; store: Record<string, unknown>; derive: Record<string, unknown>; resolve: Record<string, unknown>; } export interface EphemeralType { derive: SingletonBase['derive']; resolve: SingletonBase['resolve']; schema: MetadataBase['schema']; standaloneSchema: MetadataBase['schema']; } export interface DefinitionBase { typebox: Record<string, TAnySchema>; error: Record<string, Error>; } export type RouteBase = Record<string, unknown>; export interface MetadataBase { schema: RouteSchema; standaloneSchema: MetadataBase['schema']; macro: BaseMacro; macroFn: BaseMacroFn; parser: Record<string, BodyHandler<any, any>>; } export interface RouteSchema { body?: unknown; headers?: unknown; query?: unknown; params?: unknown; cookie?: unknown; response?: unknown; } interface OptionalField { [OptionalKind]: 'Optional'; } type TrimArrayName<T extends string> = T extends `${infer Name}[]` ? Name : T; export type UnwrapSchema<Schema extends TSchema | string | undefined, Definitions extends DefinitionBase['typebox'] = {}> = undefined extends Schema ? unknown : Schema extends TSchema ? Schema extends OptionalField ? Partial<TImport<Definitions & { readonly __elysia: Schema; }, '__elysia'>['static']> : TImport<Definitions & { readonly __elysia: Schema; }, '__elysia'>['static'] : Schema extends `${infer Key}[]` ? Definitions extends Record<Key, infer NamedSchema extends TAnySchema> ? NamedSchema['static'][] : TImport<Definitions, TrimArrayName<Schema>>['static'][] : Schema extends string ? Definitions extends keyof Schema ? NamedSchema['static'] : TImport<Definitions, Schema>['static'] : unknown; export type UnwrapBodySchema<Schema extends TSchema | string | undefined, Definitions extends DefinitionBase['typebox'] = {}> = undefined extends Schema ? unknown : Schema extends TSchema ? Schema extends OptionalField ? Partial<TImport<Definitions & { readonly __elysia: Schema; }, '__elysia'>['static']> | null : TImport<Definitions & { readonly __elysia: Schema; }, '__elysia'>['static'] : Schema extends `${infer Key}[]` ? Definitions extends Record<Key, infer NamedSchema extends TAnySchema> ? NamedSchema['static'][] : TImport<Definitions, TrimArrayName<Schema>>['static'][] : Schema extends string ? Definitions extends keyof Schema ? NamedSchema['static'] : TImport<Definitions, Schema>['static'] : unknown; export interface UnwrapRoute<in out Schema extends InputSchema<any>, in out Definitions extends DefinitionBase['typebox'] = {}, Path extends string = ''> { body: UnwrapBodySchema<Schema['body'], Definitions>; headers: UnwrapSchema<Schema['headers'], Definitions>; query: UnwrapSchema<Schema['query'], Definitions>; params: {} extends Schema['params'] ? ResolvePath<Path> : InputSchema<never> extends Schema ? ResolvePath<Path> : UnwrapSchema<Schema['params'], Definitions>; cookie: UnwrapSchema<Schema['cookie'], Definitions>; response: Schema['response'] extends TSchema | string ? { 200: CoExist<UnwrapSchema<Schema['response'], Definitions>, File, ElysiaFile | Blob>; } : Schema['response'] extends { [status in number]: TAnySchema | string; } ? { [k in keyof Schema['response']]: CoExist<UnwrapSchema<Schema['response'][k], Definitions>, File, ElysiaFile | Blob>; } : unknown | void; } export interface UnwrapGroupGuardRoute<in out Schema extends InputSchema<any>, in out Definitions extends DefinitionBase['typebox'] = {}, Path extends string | undefined = undefined> { body: UnwrapBodySchema<Schema['body'], Definitions>; headers: UnwrapSchema<Schema['headers'], Definitions> extends infer A extends Record<string, any> ? A : undefined; query: UnwrapSchema<Schema['query'], Definitions> extends infer A extends Record<string, any> ? A : undefined; params: UnwrapSchema<Schema['params'], Definitions> extends infer A extends Record<string, any> ? A : Path extends `${string}/${':' | '*'}${string}` ? Record<GetPathParameter<Path>, string> : never; cookie: UnwrapSchema<Schema['cookie'], Definitions> extends infer A extends Record<string, any> ? A : undefined; response: Schema['response'] extends TSchema | string ? UnwrapSchema<Schema['response'], Definitions> : Schema['response'] extends { [k in string]: TSchema | string; } ? UnwrapSchema<Schema['response'][keyof Schema['response']], Definitions> : unknown | void; } export type HookContainer<T extends Function = Function> = { checksum?: number; scope?: LifeCycleType; subType?: 'derive' | 'resolve' | 'mapDerive' | 'mapResolve' | (string & {}); fn: T; isAsync?: boolean; hasReturn?: boolean; }; export interface LifeCycleStore { type?: ContentType; start: HookContainer<GracefulHandler<any>>[]; request: HookContainer<PreHandler<any, any>>[]; parse: HookContainer<BodyHandler<any, any>>[]; transform: HookContainer<TransformHandler<any, any>>[]; beforeHandle: HookContainer<OptionalHandler<any, any>>[]; afterHandle: HookContainer<OptionalHandler<any, any>>[]; mapResponse: HookContainer<MapResponse<any, any>>[]; afterResponse: HookContainer<AfterResponseHandler<any, any>>[]; trace: HookContainer<TraceHandler<any, any>>[]; error: HookContainer<ErrorHandler<any, any, any>>[]; stop: HookContainer<GracefulHandler<any>>[]; } export type LifeCycleEvent = 'start' | 'request' | 'parse' | 'transform' | 'beforeHandle' | 'afterHandle' | 'response' | 'error' | 'stop'; export type ContentType = MaybeArray<'none' | 'text' | 'json' | 'formdata' | 'urlencoded' | 'arrayBuffer' | 'text/plain' | 'application/json' | 'multipart/form-data' | 'application/x-www-form-urlencoded' | 'application/octet-stream'>; 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<Name extends string = string> { body?: TSchema | Name | `${Name}[]`; headers?: TSchema | Name | `${Name}[]`; query?: TSchema | Name | `${Name}[]`; params?: TSchema | Name | `${Name}[]`; cookie?: TSchema | Name | `${Name}[]`; response?: TSchema | { [status in number]: TSchema; } | Name | `${Name}[]` | { [status in number]: `${Name}[]` | Name | TSchema; }; } export interface PrettifySchema<in out A extends RouteSchema> { body: unknown extends A['body'] ? A['body'] : Prettify<A['body']>; headers: unknown extends A['headers'] ? A['headers'] : Prettify<A['headers']>; query: unknown extends A['query'] ? A['query'] : Prettify<A['query']>; params: unknown extends A['params'] ? A['params'] : Prettify<A['params']>; cookie: unknown extends A['cookie'] ? A['cookie'] : Prettify<A['cookie']>; response: unknown extends A['response'] ? A['response'] : Prettify<A['response']>; } export interface MergeSchema<in out A extends RouteSchema, in out B extends RouteSchema, Path extends string = ''> { body: undefined extends A['body'] ? B['body'] : A['body']; headers: undefined extends A['headers'] ? B['headers'] : A['headers']; query: undefined extends A['query'] ? B['query'] : A['query']; params: IsNever<keyof A['params']> extends true ? IsNever<keyof B['params']> extends true ? ResolvePath<Path> : B['params'] : IsNever<keyof B['params']> extends true ? A['params'] : Prettify<B['params'] & Omit<A['params'], keyof B['params']>>; cookie: undefined extends A['cookie'] ? B['cookie'] : A['cookie']; response: {} extends A['response'] ? {} extends B['response'] ? {} : B['response'] : {} extends B['response'] ? A['response'] : A['response'] & Omit<B['response'], keyof A['response']>; } export interface MergeStandaloneSchema<in out A extends RouteSchema, in out B extends RouteSchema, Path extends string = ''> { body: undefined extends A['body'] ? undefined extends B['body'] ? undefined : B['body'] : undefined extends B['body'] ? A['body'] : Prettify<A['body'] & B['body']>; headers: undefined extends A['headers'] ? undefined extends B['headers'] ? undefined : B['headers'] : undefined extends B['headers'] ? A['headers'] : Prettify<A['headers'] & B['headers']>; query: undefined extends A['query'] ? undefined extends B['query'] ? undefined : B['query'] : undefined extends B['query'] ? A['query'] : Prettify<A['query'] & B['query']>; params: IsNever<keyof A['params']> extends true ? IsNever<keyof B['params']> extends true ? ResolvePath<Path> : B['params'] : IsNever<keyof B['params']> extends true ? A['params'] : Prettify<A['params'] & B['params']>; cookie: undefined extends A['cookie'] ? undefined extends B['cookie'] ? undefined : B['cookie'] : undefined extends B['cookie'] ? A['cookie'] : Prettify<A['cookie'] & B['cookie']>; response: {} extends A['response'] ? {} extends B['response'] ? {} : B['response'] : {} extends B['response'] ? A['response'] : Prettify<A['response'] & B['response']>; } export type Handler<in out Route extends RouteSchema = {}, in out Singleton extends SingletonBase = { decorator: {}; store: {}; derive: {}; resolve: {}; }, Path extends string | undefined = undefined> = (context: Context<Route, Singleton, Path>) => MaybePromise<{} extends Route['response'] ? unknown : Route['response'][keyof Route['response']]>; export type IsAny<T> = 0 extends 1 & T ? true : false; export type Replace<Original, Target, With> = IsAny<Target> extends true ? Original : Original extends Record<string, unknown> ? { [K in keyof Original]: Original[K] extends Target ? With : Original[K]; } : Original extends Target ? With : Original; export type CoExist<Original, Target, With> = IsAny<Target> extends true ? Original : Original extends Record<string, unknown> ? { [K in keyof Original]: Original[K] extends Target ? Original[K] | With : Original[K]; } : Original extends Target ? Original | With : Original; export type MacroContextBlacklistKey = 'type' | 'detail' | 'parse' | 'transform' | 'resolve' | 'beforeHandle' | 'afterHandle' | 'mapResponse' | 'afterResponse' | 'error' | 'tags' | keyof RouteSchema; type ReturnTypeIfPossible<T> = T extends AnyContextFn ? ReturnType<T> : T; type AnyElysiaCustomStatusResponse = ElysiaCustomStatusResponse<any, any, any>; type MacroResolveLike = MaybeArray<(...v: any) => MaybePromise<Record<keyof any, unknown> | void | AnyElysiaCustomStatusResponse>>; type ResolveMacroPropertyLike = { resolve: MacroResolveLike; }; type ResolveMacroFnLike = (...v: any[]) => ResolveMacroPropertyLike; type MergeAllMacroContext<T> = UnionToIntersection<T[keyof T]> extends infer O ? { [K in keyof O]: O[K]; } : never; type UnionToIntersection<U> = (U extends any ? (x: U) => any : never) extends (x: infer I) => any ? I : never; type ExtractMacroContext<A> = IsNever<A> extends true ? {} : Exclude<Awaited<A>, AnyElysiaCustomStatusResponse | void>; export type MacroToContext<MacroFn extends BaseMacroFn = {}, SelectedMacro extends MetadataBase['macro'] = {}> = {} extends SelectedMacro ? {} : MergeAllMacroContext<{ [key in keyof SelectedMacro as MacroFn[key] extends ResolveMacroFnLike ? key : MacroFn[key] extends ResolveMacroPropertyLike ? true extends SelectedMacro[key] ? key : never : never]: ExtractMacroContext<ResolveResolutions<ReturnTypeIfPossible<MacroFn[key]>['resolve']>>; }>; type InlineHandlerResponse<Route extends RouteSchema['response']> = { [Status in keyof Route]: ElysiaCustomStatusResponse<Status, Route[Status]>; }[keyof Route]; export type InlineHandler<Route extends RouteSchema = {}, Singleton extends SingletonBase = { decorator: {}; store: {}; derive: {}; resolve: {}; }, Path extends string | undefined = undefined> = ((context: Context<Route, Singleton, Path>) => Response | MaybePromise<{} extends Route['response'] ? unknown : (Route['response'] extends { 200: any; } ? Route['response'][200] : unknown) | Route['response'][keyof Route['response']] | InlineHandlerResponse<Route['response']>>) | ({} extends Route['response'] ? string | number | boolean | object : Route['response'] extends { 200: any; } ? Route['response'][200] : string | number | boolean | object) | ElysiaCustomStatusResponse<any, any>; export type OptionalHandler<in out Route extends RouteSchema = {}, in out Singleton extends SingletonBase = { decorator: {}; store: {}; derive: {}; resolve: {}; }, Path extends string | undefined = undefined> = (context: Context<Route, Singleton, Path>) => MaybePromise<{} extends Route['response'] ? unknown : Route['response'][keyof Route['response']] | void>; export type AfterHandler<in out Route extends RouteSchema = {}, in out Singleton extends SingletonBase = { decorator: {}; store: {}; derive: {}; resolve: {}; }, Path extends string | undefined = undefined> = (context: Context<Route, Singleton, Path> & { response: {} extends Route['response'] ? unknown : Route['response'][keyof Route['response']]; }) => MaybePromise<{} extends Route['response'] ? unknown : Route['response'][keyof Route['response']] | void>; export type MapResponse<in out Route extends RouteSchema = {}, in out Singleton extends SingletonBase = { decorator: {}; store: {}; derive: {}; resolve: {}; }, Path extends string | undefined = undefined> = (context: Context<Omit<Route, 'response'>, Singleton & { derive: { response: {} extends Route['response'] ? unknown : Route['response']; }; }, Path>) => MaybePromise<Response | void>; export type VoidHandler<in out Route extends RouteSchema = {}, in out Singleton extends SingletonBase = { decorator: {}; store: {}; derive: {}; resolve: {}; }> = (context: Context<Route, Singleton>) => MaybePromise<void>; export type TransformHandler<in out Route extends RouteSchema = {}, in out Singleton extends SingletonBase = { decorator: {}; store: {}; derive: {}; resolve: {}; }, Path extends string | undefined = undefined> = (context: Prettify<Context<Route, Omit<Singleton, 'resolve'> & { resolve: {}; }, Path>>) => MaybePromise<void>; export type BodyHandler<in out Route extends RouteSchema = {}, in out Singleton extends SingletonBase = { decorator: {}; store: {}; derive: {}; resolve: {}; }, Path extends string | undefined = undefined> = (context: Prettify<{ contentType: string; } & Context<Route, Singleton, Path>>, /** * @deprecated * * use `context.contentType` instead * * @example * ```ts * new Elysia() * .onParse(({ contentType, request }) => { * if (contentType === 'application/json') * return request.json() * }) * ``` */ contentType: string) => MaybePromise<any>; export type PreHandler<in out Route extends RouteSchema = {}, in out Singleton extends SingletonBase = { decorator: {}; store: {}; derive: {}; resolve: {}; }> = (context: PreContext<Singleton>) => MaybePromise<Route['response'] | void>; export type AfterResponseHandler<in out Route extends RouteSchema = {}, in out Singleton extends SingletonBase = { decorator: {}; store: {}; derive: {}; resolve: {}; }> = (context: Context<Route, Singleton> & { response: {} extends Route['response'] ? unknown : Route['response'][keyof Route['response']]; }) => MaybePromise<unknown>; export type GracefulHandler<in Instance extends AnyElysia> = (data: Instance) => any; export type ErrorHandler<in out T extends Record<string, Error> = {}, in out Route extends RouteSchema = {}, in out Singleton extends SingletonBase = { decorator: {}; store: {}; derive: {}; resolve: {}; }, in out Ephemeral extends EphemeralType = { derive: {}; resolve: {}; schema: {}; standaloneSchema: {}; }, in out Volatile extends EphemeralType = { derive: {}; resolve: {}; schema: {}; standaloneSchema: {}; }> = (context: ErrorContext<Route, { store: Singleton['store']; decorator: Singleton['decorator']; derive: {}; resolve: {}; }> & (Prettify<{ request: Request; code: 'UNKNOWN'; error: Readonly<Error>; set: Context['set']; } & Partial<Singleton['derive'] & Ephemeral['derive'] & Volatile['derive'] & Singleton['resolve'] & Ephemeral['resolve'] & Volatile['resolve']>> | Prettify<{ request: Request; code: 'VALIDATION'; error: Readonly<ValidationError>; set: Context['set']; } & Singleton['derive'] & Ephemeral['derive'] & Volatile['derive'] & NeverKey<Singleton['resolve'] & Ephemeral['resolve'] & Volatile['resolve']>> | Prettify<{ request: Request; code: 'NOT_FOUND'; error: Readonly<NotFoundError>; set: Context['set']; } & NeverKey<Singleton['derive'] & Ephemeral['derive'] & Volatile['derive'] & Singleton['resolve'] & Ephemeral['resolve'] & Volatile['resolve']>> | Prettify<{ request: Request; code: 'PARSE'; error: Readonly<ParseError>; set: Context['set']; } & Singleton['derive'] & Ephemeral['derive'] & Volatile['derive'] & NeverKey<Singleton['resolve'] & Ephemeral['resolve'] & Volatile['resolve']>> | Prettify<{ request: Request; code: 'INTERNAL_SERVER_ERROR'; error: Readonly<InternalServerError>; set: Context['set']; } & Partial<Singleton['derive'] & Ephemeral['derive'] & Volatile['derive'] & Singleton['resolve'] & Ephemeral['resolve'] & Volatile['resolve']>> | Prettify<{ request: Request; code: 'INVALID_COOKIE_SIGNATURE'; error: Readonly<InvalidCookieSignature>; set: Context['set']; } & NeverKey<Singleton['derive'] & Ephemeral['derive'] & Volatile['derive'] & Singleton['resolve'] & Ephemeral['resolve'] & Volatile['resolve']>> | Prettify<{ request: Request; code: 'INVALID_FILE_TYPE'; error: Readonly<InvalidFileType>; set: Context['set']; } & Singleton['derive'] & Ephemeral['derive'] & Volatile['derive'] & NeverKey<Singleton['resolve'] & Ephemeral['resolve'] & Volatile['resolve']>> | Prettify<{ request: Request; code: number; error: Readonly<ElysiaCustomStatusResponse<number>>; set: Context['set']; } & Partial<Singleton['derive'] & Ephemeral['derive'] & Volatile['derive'] & Singleton['resolve'] & Ephemeral['resolve'] & Volatile['resolve']>> | Prettify<{ [K in keyof T]: { request: Request; code: K; error: Readonly<T[K]>; set: Context['set']; }; }[keyof T] & Partial<Singleton['derive'] & Ephemeral['derive'] & Volatile['derive'] & Singleton['resolve'] & Ephemeral['resolve'] & Volatile['resolve']>>)) => any | Promise<any>; export type DocumentDecoration = Partial<OpenAPIV3.OperationObject> & { /** * Pass `true` to hide route from OpenAPI/swagger document * */ hide?: boolean; }; export type ResolveHandler<in out Route extends RouteSchema, in out Singleton extends SingletonBase, Derivative extends Record<string, unknown> | AnyElysiaCustomStatusResponse | void = Record<string, unknown> | AnyElysiaCustomStatusResponse | void> = (context: Context<Route, Singleton>) => MaybePromise<Derivative>; type AnyContextFn = (context?: any) => any; export type ResolveDerivativesArray<T extends any[], Carry extends Record<keyof any, unknown> = {}> = T extends [infer Fn extends AnyContextFn, ...infer Rest] ? ReturnType<Fn> extends infer Value extends Record<keyof any, unknown> ? ResolveDerivativesArray<Rest, Value & Carry> : ResolveDerivativesArray<Rest, Carry> : Prettify<Carry>; export type ResolveResolutions<T extends MaybeArray<unknown>> = any[] extends T ? {} : IsNever<keyof T> extends true ? any[] extends T ? {} : ReturnType<// @ts-ignore Trust me bro T> : ResolveResolutionsArray<// @ts-ignore Trust me bro T>; export type ResolveResolutionsArray<T extends any[], Carry extends Record<keyof any, unknown> = {}> = T extends [infer Fn extends AnyContextFn, ...infer Rest] ? ReturnType<Fn> extends infer Value extends Record<keyof any, unknown> ? ResolveResolutionsArray<Rest, Value & Carry> : ResolveResolutionsArray<Rest, Carry> : Prettify<Carry>; export type AnyLocalHook = LocalHook<any, any, any, any, any, any>; export type LocalHook<LocalSchema extends InputSchema, Schema extends RouteSchema, Singleton extends SingletonBase, Errors extends { [key in string]: Error; }, Macro extends BaseMacro, Parser extends keyof any = ''> = Prettify<Macro> & (LocalSchema extends any ? LocalSchema : Prettify<LocalSchema>) & { detail?: DocumentDecoration; /** * Short for 'Content-Type' * * Available: * - 'none': do not parse body * - 'text' / 'text/plain': parse body as string * - 'json' / 'application/json': parse body as json * - 'formdata' / 'multipart/form-data': parse body as form-data * - 'urlencoded' / 'application/x-www-form-urlencoded: parse body as urlencoded * - 'arraybuffer': parse body as readable stream */ parse?: MaybeArray<BodyHandler<Schema, Singleton> | ContentType | Parser>; /** * Transform context's value */ transform?: MaybeArray<TransformHandler<Schema, Singleton>>; /** * Execute before main handler */ beforeHandle?: MaybeArray<OptionalHandler<Schema, Singleton>>; /** * Execute after main handler */ afterHandle?: MaybeArray<AfterHandler<Schema, Singleton>>; /** * Execute after main handler */ mapResponse?: MaybeArray<MapResponse<Schema, Singleton>>; /** * Execute after response is sent */ afterResponse?: MaybeArray<AfterResponseHandler<Schema, Singleton>>; /** * Catch error */ error?: MaybeArray<ErrorHandler<Errors, Schema, Singleton>>; tags?: DocumentDecoration['tags']; }; export type ComposedHandler = (context: Context) => MaybePromise<Response>; export interface InternalRoute { method: HTTPMethod; path: string; composed: ComposedHandler | Response | null; compile(): ComposedHandler; handler: Handler; hooks: AnyLocalHook; websocket?: AnyWSLocalHook; standaloneValidators?: InputSchema[]; } export interface SchemaValidator { createBody?(): ElysiaTypeCheck<any>; createHeaders?(): ElysiaTypeCheck<any>; createQuery?(): ElysiaTypeCheck<any>; createParams?(): ElysiaTypeCheck<any>; createCookie?(): ElysiaTypeCheck<any>; createResponse?(): Record<number, ElysiaTypeCheck<any>>; body?: ElysiaTypeCheck<any>; headers?: ElysiaTypeCheck<any>; query?: ElysiaTypeCheck<any>; params?: ElysiaTypeCheck<any>; cookie?: ElysiaTypeCheck<any>; response?: Record<number, ElysiaTypeCheck<any>>; } export type AddPrefix<Prefix extends string, T> = { [K in keyof T as Prefix extends string ? `${Prefix}${K & string}` : K]: T[K]; }; export type AddPrefixCapitalize<Prefix extends string, T> = { [K in keyof T as `${Prefix}${Capitalize<K & string>}`]: T[K]; }; export type AddSuffix<Suffix extends string, T> = { [K in keyof T as `${K & string}${Suffix}`]: T[K]; }; export type AddSuffixCapitalize<Suffix extends string, T> = { [K in keyof T as `${K & string}${Capitalize<Suffix>}`]: T[K]; }; export interface Checksum { name?: string; seed?: unknown; checksum: number; stack?: string; routes?: InternalRoute[]; decorators?: SingletonBase['decorator']; store?: SingletonBase['store']; error?: DefinitionBase['error']; dependencies?: Record<string, Checksum[]>; derive?: { fn: string; stack: string; }[]; resolve?: { fn: string; stack: string; }[]; } export type BaseMacro = Record<string, string | number | boolean | Object | undefined | null>; export type BaseMacroFn<in out TypedRoute extends RouteSchema = {}, in out Singleton extends SingletonBase = { decorator: {}; store: {}; derive: {}; resolve: {}; }, in out Errors extends Record<string, Error> = {}> = { [K in keyof any]: (...a: any) => void | { onParse?(fn: MaybeArray<BodyHandler<TypedRoute, Singleton>>): unknown; onParse?(options: MacroOptions, fn: MaybeArray<BodyHandler<TypedRoute, Singleton>>): unknown; onTransform?(fn: MaybeArray<VoidHandler<TypedRoute, Singleton>>): unknown; onTransform?(options: MacroOptions, fn: MaybeArray<VoidHandler<TypedRoute, Singleton>>): unknown; onBeforeHandle?(fn: MaybeArray<OptionalHandler<TypedRoute, Singleton>>): unknown; onBeforeHandle?(options: MacroOptions, fn: MaybeArray<OptionalHandler<TypedRoute, Singleton>>): unknown; onAfterHandle?(fn: MaybeArray<AfterHandler<TypedRoute, Singleton>>): unknown; onAfterHandle?(options: MacroOptions, fn: MaybeArray<AfterHandler<TypedRoute, Singleton>>): unknown; onError?(fn: MaybeArray<ErrorHandler<Errors, TypedRoute, Singleton>>): unknown; onError?(options: MacroOptions, fn: MaybeArray<ErrorHandler<Errors, TypedRoute, Singleton>>): unknown; mapResponse?(fn: MaybeArray<MapResponse<TypedRoute, Singleton>>): unknown; mapResponse?(options: MacroOptions, fn: MaybeArray<MapResponse<TypedRoute, Singleton>>): unknown; onAfterResponse?(fn: MaybeArray<AfterResponseHandler<TypedRoute, Singleton>>): unknown; onAfterResponse?(options: MacroOptions, fn: MaybeArray<AfterResponseHandler<TypedRoute, Singleton>>): unknown; }; }; export type HookMacroFn<in out TypedRoute extends RouteSchema = {}, in out Singleton extends SingletonBase = { decorator: {}; store: {}; derive: {}; resolve: {}; }, in out Errors extends Record<string, Error> = {}> = { [K in keyof any]: { parse?: MaybeArray<BodyHandler<TypedRoute, Singleton>>; transform?: MaybeArray<VoidHandler<TypedRoute, Singleton>>; beforeHandle?: MaybeArray<OptionalHandler<TypedRoute, Singleton>>; afterHandle?: MaybeArray<AfterHandler<TypedRoute, Singleton>>; error?: MaybeArray<ErrorHandler<Errors, TypedRoute, Singleton>>; mapResponse?: MaybeArray<MapResponse<TypedRoute, Singleton>>; afterResponse?: MaybeArray<AfterResponseHandler<TypedRoute, Singleton>>; resolve?: MaybeArray<ResolveHandler<TypedRoute, Singleton>>; } | ((...a: any) => { parse?: MaybeArray<BodyHandler<TypedRoute, Singleton>>; transform?: MaybeArray<VoidHandler<TypedRoute, Singleton>>; beforeHandle?: MaybeArray<OptionalHandler<TypedRoute, Singleton>>; afterHandle?: MaybeArray<AfterHandler<TypedRoute, Singleton>>; error?: MaybeArray<ErrorHandler<Errors, TypedRoute, Singleton>>; mapResponse?: MaybeArray<MapResponse<TypedRoute, Singleton>>; afterResponse?: MaybeArray<AfterResponseHandler<TypedRoute, Singleton>>; resolve?: MaybeArray<ResolveHandler<TypedRoute, Singleton>>; } | void); }; export type MacroToProperty<in out T extends BaseMacroFn | HookMacroFn<any, any, any>> = Prettify<{ [K in keyof T]: T[K] extends Function ? T[K] extends (a: infer Params) => any ? Params : boolean : boolean; }>; interface MacroOptions { insert?: 'before' | 'after'; stack?: 'global' | 'local'; } export interface MacroManager<in out TypedRoute extends RouteSchema = {}, in out Singleton extends SingletonBase = { decorator: {}; store: {}; derive: {}; resolve: {}; }, in out Errors extends Record<string, Error> = {}> { onParse(fn: MaybeArray<BodyHandler<TypedRoute, Singleton>>): unknown; onParse(options: MacroOptions, fn: MaybeArray<BodyHandler<TypedRoute, Singleton>>): unknown; onTransform(fn: MaybeArray<VoidHandler<TypedRoute, Singleton>>): unknown; onTransform(options: MacroOptions, fn: MaybeArray<VoidHandler<TypedRoute, Singleton>>): unknown; onBeforeHandle(fn: MaybeArray<OptionalHandler<TypedRoute, Singleton>>): unknown; onBeforeHandle(options: MacroOptions, fn: MaybeArray<OptionalHandler<TypedRoute, Singleton>>): unknown; onAfterHandle(fn: MaybeArray<AfterHandler<TypedRoute, Singleton>>): unknown; onAfterHandle(options: MacroOptions, fn: MaybeArray<AfterHandler<TypedRoute, Singleton>>): unknown; onError(fn: MaybeArray<ErrorHandler<Errors, TypedRoute, Singleton>>): unknown; onError(options: MacroOptions, fn: MaybeArray<ErrorHandler<Errors, TypedRoute, Singleton>>): unknown; mapResponse(fn: MaybeArray<MapResponse<TypedRoute, Singleton>>): unknown; mapResponse(options: MacroOptions, fn: MaybeArray<MapResponse<TypedRoute, Singleton>>): unknown; onAfterResponse(fn: MaybeArray<AfterResponseHandler<TypedRoute, Singleton>>): unknown; onAfterResponse(options: MacroOptions, fn: MaybeArray<AfterResponseHandler<TypedRoute, Singleton>>): unknown; events: { global: Partial<Prettify<LifeCycleStore & RouteSchema>>; local: Partial<Prettify<LifeCycleStore & RouteSchema>>; }; } export type MacroQueue = HookContainer<(manager: MacroManager<any, any, any>) => unknown>; type _CreateEden<Path extends string, Property extends Record<string, unknown> = {}> = Path extends `${infer Start}/${infer Rest}` ? { [x in Start]: _CreateEden<Rest, Property>; } : Path extends '' ? Property : { [x in Path]: Property; }; type RemoveStartinSlash<T> = T extends `/${infer Rest}` ? Rest : T; export type CreateEden<Path extends string, Property extends Record<string, unknown> = {}> = Path extends '' | '/' ? Property : _CreateEden<RemoveStartinSlash<Path>, Property>; export type ComposeElysiaResponse<Schema extends RouteSchema, Handle> = Handle extends (...a: any[]) => infer A ? _ComposeElysiaResponse<Schema, Awaited<A>> : _ComposeElysiaResponse<Schema, Awaited<Handle>>; export type EmptyRouteSchema = { body: unknown; headers: unknown; query: unknown; params: {}; cookie: unknown; response: {}; }; type _ComposeElysiaResponse<Schema extends RouteSchema, Handle> = Prettify<(Schema['response'] extends { 200: any; } ? { 200: Replace<Schema['response'][200], ElysiaFile, File>; } : { 200: Handle extends AnyElysiaCustomStatusResponse ? Exclude<Handle, AnyElysiaCustomStatusResponse> | Extract<Handle, ElysiaCustomStatusResponse<200, any, 200>>['response'] : Handle extends Generator<infer A, infer B, infer C> ? AsyncGenerator<A, B, C> : Replace<Handle, ElysiaFile, File>; }) & ExtractErrorFromHandle<Handle> & ({} extends Omit<Schema['response'], 200> ? {} : Omit<Schema['response'], 200>) & (EmptyRouteSchema extends Schema ? {} : { 422: { type: 'validation'; on: string; summary?: string; message?: string; found?: unknown; property?: string; expected?: string; }; })>; type ExtractErrorFromHandle<Handle> = { [ErrorResponse in Extract<Handle, AnyElysiaCustomStatusResponse> as ErrorResponse extends AnyElysiaCustomStatusResponse ? ErrorResponse['code'] : never]: ErrorResponse['response']; }; export type MergeElysiaInstances<Instances extends AnyElysia[] = [], Prefix extends string = '', Singleton extends SingletonBase = { decorator: {}; store: {}; derive: {}; resolve: {}; }, Definitions extends DefinitionBase = { typebox: {}; error: {}; }, Metadata extends MetadataBase = { schema: {}; standaloneSchema: {}; macro: {}; macroFn: {}; parser: {}; }, Ephemeral extends EphemeralType = { derive: {}; resolve: {}; schema: {}; standaloneSchema: {}; }, Volatile extends EphemeralType = { derive: {}; resolve: {}; schema: {}; standaloneSchema: {}; }, Routes extends RouteBase = {}> = Instances extends [ infer Current extends AnyElysia, ...infer Rest extends AnyElysia[] ] ? MergeElysiaInstances<Rest, Prefix, Singleton & Current['~Singleton'], Definitions & Current['~Definitions'], Metadata & Current['~Metadata'], Ephemeral, Volatile & Current['~Ephemeral'], Routes & (Prefix extends `` ? Current['~Routes'] : AddPrefix<Prefix, Current['~Routes']>)> : Elysia<Prefix, Prettify2<Singleton>, Definitions, Prettify2<Metadata>, Routes, Ephemeral, Prettify2<Volatile>>; export type LifeCycleType = 'global' | 'local' | 'scoped'; export type GuardSchemaType = 'override' | 'standalone'; export type ExcludeElysiaResponse<T> = Exclude<undefined extends Awaited<T> ? Partial<Awaited<T>> : Awaited<T>, AnyElysiaCustomStatusResponse>; export type InferContext<T extends AnyElysia, Path extends string = T['~Prefix'], Schema extends RouteSchema = T['~Metadata']['schema']> = Context<MergeSchema<Schema, T['~Metadata']['schema']>, T['~Singleton'] & { derive: T['~Ephemeral']['derive'] & T['~Volatile']['derive']; resolve: T['~Ephemeral']['resolve'] & T['~Volatile']['resolve']; }, Path>; export type InferHandler<T extends AnyElysia, Path extends string = T['~Prefix'], Schema extends RouteSchema = T['~Metadata']['schema']> = InlineHandler<MergeSchema<Schema, T['~Metadata']['schema']>, T['~Singleton'] & { derive: T['~Ephemeral']['derive'] & T['~Volatile']['derive']; resolve: T['~Ephemeral']['resolve'] & T['~Volatile']['resolve']; }, Path>; export interface ModelValidatorError extends ValueError { summary: string; } export interface ModelValidator<T> extends TypeCheck<T> { parse(a: T): T; safeParse(a: T): { success: true; data: T; error: null; } | { success: true; data: null; error: string; errors: ModelValidatorError[]; }; } export type UnionToIntersect<U> = (U extends unknown ? (arg: U) => 0 : never) extends (arg: infer I) => 0 ? I : never; export type ResolveMacroContext<Macro extends BaseMacro, MacroFn extends BaseMacroFn> = UnionToIntersect<{ [K in keyof Macro]-?: undefined extends Macro[K] ? never : K extends keyof MacroFn ? ReturnType<MacroFn[K]> extends infer A extends { [K in keyof any]: any; } ? A : never : never; }[keyof Macro]>; export type ContextAppendType = 'append' | 'override'; export type HigherOrderFunction<T extends (...arg: unknown[]) => Function = (...arg: unknown[]) => Function> = (fn: T, request: Request) => ReturnType<T>; type SetContentType = 'application/octet-stream' | 'application/vnd.ms-fontobject' | 'application/epub+zip' | 'application/gzip' | 'application/json' | 'application/ld+json' | 'application/ogg' | 'application/pdf' | 'application/rtf' | 'application/wasm' | 'application/xhtml+xml' | 'application/xml' | 'application/zip' | 'text/css' | 'text/csv' | 'text/html' | 'text/calendar' | 'text/javascript' | 'text/plain' | 'text/xml' | 'image/avif' | 'image/bmp' | 'image/gif' | 'image/x-icon' | 'image/jpeg' | 'image/png' | 'image/svg+xml' | 'image/tiff' | 'image/webp' | 'multipart/mixed' | 'multipart/alternative' | 'multipart/form-data' | 'audio/aac' | 'audio/x-midi' | 'audio/mpeg' | 'audio/ogg' | 'audio/opus' | 'audio/webm' | 'video/x-msvideo' | 'video/quicktime' | 'video/x-ms-wmv' | 'video/x-msvideo' | 'video/x-flv' | 'video/av1' | 'video/mp4' | 'video/mpeg' | 'video/ogg' | 'video/mp2t' | 'video/webm' | 'video/3gpp' | 'video/3gpp2' | 'font/otf' | 'font/ttf' | 'font/woff' | 'font/woff2' | 'model/gltf+json' | 'model/gltf-binary'; export type HTTPHeaders = Record<string, string | number> & { 'www-authenticate'?: string; authorization?: string; 'proxy-authenticate'?: string; 'proxy-authorization'?: string; age?: string; 'cache-control'?: string; 'clear-site-data'?: string; expires?: string; 'no-vary-search'?: string; pragma?: string; 'last-modified'?: string; etag?: string; 'if-match'?: string; 'if-none-match'?: string; 'if-modified-since'?: string; 'if-unmodified-since'?: string; vary?: string; connection?: string; 'keep-alive'?: string; accept?: string; 'accept-encoding'?: string; 'accept-language'?: string; expect?: string; 'max-forwards'?: string; cookie?: string; 'set-cookie'?: string | string[]; '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; 'content-disposition'?: string; 'content-length'?: string | number; 'content-type'?: SetContentType | (string & {}); 'content-encoding'?: string; 'content-language'?: string; 'content-location'?: string; forwarded?: string; via?: string; location?: string; refresh?: string; allow?: string; server?: 'Elysia' | (string & {}); 'accept-ranges'?: string; range?: string; 'if-range'?: string; 'content-range'?: string; '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; 'last-event-id'?: string; 'ping-from'?: string; 'ping-to'?: string; 'report-to'?: string; te?: string; trailer?: string; 'transfer-encoding'?: string; '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; 'x-dns-prefetch-control'?: string; 'x-forwarded-for'?: string; 'x-forwarded-host'?: string; 'x-forwarded-proto'?: string; 'x-powered-by'?: 'Elysia' | (string & {}); 'x-request-id'?: string; 'x-requested-with'?: string; 'x-robots-tag'?: string; 'x-ua-compatible'?: string; }; export type JoinPath<A extends string, B extends string> = `${A}${B}`; export type UnwrapTypeModule<Module extends TModule<any, any>> = Module extends TModule<infer Type extends TProperties, any> ? Type : {}; export type MergeTypeModule<A extends TModule<any, any>, B extends TModule<any, any>> = TModule<Prettify<UnwrapTypeModule<A> & UnwrapTypeModule<B>>>; export type SSEPayload = { /** id of the event */ id?: string | number | null; /** event name */ event?: string; /** retry in millisecond */ retry?: number; /** data to send */ data?: unknown; }; export {};