UNPKG

elysia

Version:

Ergonomic Framework for Human

1,294 lines 70 kB
"use strict"; var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf, __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: !0 }); }, __copyProps = (to, from, except, desc) => { if (from && typeof from == "object" || typeof from == "function") for (let key of __getOwnPropNames(from)) !__hasOwnProp.call(to, key) && key !== except && __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: !0 }) : target, mod )), __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: !0 }), mod); var index_exports = {}; __export(index_exports, { Cookie: () => import_cookies.Cookie, ELYSIA_FORM_DATA: () => import_utils4.ELYSIA_FORM_DATA, ELYSIA_REQUEST_ID: () => import_utils4.ELYSIA_REQUEST_ID, ELYSIA_TRACE: () => import_trace2.ELYSIA_TRACE, ERROR_CODE: () => import_error2.ERROR_CODE, Elysia: () => Elysia, ElysiaCustomStatusResponse: () => import_error2.ElysiaCustomStatusResponse, ElysiaFile: () => import_file.ElysiaFile, InternalServerError: () => import_error2.InternalServerError, InvalidCookieSignature: () => import_error2.InvalidCookieSignature, InvalidFileType: () => import_error2.InvalidFileType, InvertedStatusMap: () => import_utils4.InvertedStatusMap, NotFoundError: () => import_error2.NotFoundError, ParseError: () => import_error2.ParseError, StatusMap: () => import_utils4.StatusMap, TypeSystemPolicy: () => import_system.TypeSystemPolicy, ValidationError: () => import_error2.ValidationError, checksum: () => import_utils4.checksum, cloneInference: () => import_utils4.cloneInference, deduplicateChecksum: () => import_utils4.deduplicateChecksum, default: () => Elysia, env: () => import_env2.env, file: () => import_file.file, fileType: () => import_utils3.fileType, form: () => import_utils4.form, getResponseSchemaValidator: () => import_schema2.getResponseSchemaValidator, getSchemaValidator: () => import_schema2.getSchemaValidator, mapValueError: () => import_error2.mapValueError, mergeHook: () => import_utils4.mergeHook, mergeObjectArray: () => import_utils4.mergeObjectArray, redirect: () => import_utils4.redirect, replaceSchemaType: () => import_replace_schema2.replaceSchemaTypeFromManyOptions, replaceUrlPath: () => import_utils4.replaceUrlPath, serializeCookie: () => import_cookies.serializeCookie, sse: () => import_utils4.sse, status: () => import_error2.status, t: () => import_type_system2.t, validationDetail: () => import_utils3.validationDetail }); module.exports = __toCommonJS(index_exports); var import_memoirist = require("memoirist"), import_typebox = require("@sinclair/typebox"), import_fast_decode_uri_component = __toESM(require("fast-decode-uri-component")), import_type_system = require('./type-system/index.js'), import_sucrose = require('./sucrose.js'), import_bun = require('./adapter/bun/index.js'), import_web_standard = require('./adapter/web-standard/index.js'), import_env = require('./universal/env.js'), import_utils = require('./utils.js'), import_schema = require('./schema.js'), import_compose = require('./compose.js'), import_trace = require('./trace.js'), import_utils2 = require('./utils.js'), import_dynamic_handle = require('./dynamic-handle.js'), import_error = require('./error.js'), import_replace_schema = require('./replace-schema.js'), import_type_system2 = require('./type-system/index.js'), import_utils3 = require('./type-system/utils.js'), import_cookies = require('./cookies.js'), import_trace2 = require('./trace.js'), import_schema2 = require('./schema.js'), import_replace_schema2 = require('./replace-schema.js'), import_utils4 = require('./utils.js'), import_error2 = require('./error.js'), import_env2 = require('./universal/env.js'), import_file = require('./universal/file.js'), import_system = require("@sinclair/typebox/system"), _a; _a = Symbol.dispose; const _Elysia = class _Elysia { constructor(config = {}) { this.server = null; this.dependencies = {}; this["~Prefix"] = ""; this["~Singleton"] = null; this["~Definitions"] = null; this["~Metadata"] = null; this["~Ephemeral"] = null; this["~Volatile"] = null; this["~Routes"] = null; this.singleton = { decorator: {}, store: {}, derive: {}, resolve: {} }; this.definitions = { typebox: import_type_system.t.Module({}), type: {}, error: {} }; this.extender = { macro: {}, higherOrderFunctions: [] }; this.validator = { global: null, scoped: null, local: null, getCandidate() { return !this.global && !this.scoped && !this.local ? { body: void 0, headers: void 0, params: void 0, query: void 0, cookie: void 0, response: void 0 } : (0, import_utils.mergeSchemaValidator)( (0, import_utils.mergeSchemaValidator)(this.global, this.scoped), this.local ); } }; this.standaloneValidator = { global: null, scoped: null, local: null }; this.event = {}; this.router = { "~http": void 0, get http() { return this["~http"] || (this["~http"] = new import_memoirist.Memoirist({ lazy: !0, onParam: import_fast_decode_uri_component.default })), this["~http"]; }, "~dynamic": void 0, // Use in non-AOT mode get dynamic() { return this["~dynamic"] || (this["~dynamic"] = new import_memoirist.Memoirist({ onParam: import_fast_decode_uri_component.default })), this["~dynamic"]; }, // Static Router static: {}, // Native Static Response response: {}, history: [] }; this.routeTree = {}; this.inference = { body: !1, cookie: !1, headers: !1, query: !1, set: !1, server: !1, path: !1, route: !1, url: !1 }; this["~parser"] = {}; this.handle = async (request) => this.fetch(request); this.handleError = async (context, error) => (this.handleError = this.config.aot ? (0, import_compose.composeErrorHandler)(this) : (0, import_dynamic_handle.createDynamicErrorHandler)(this))(context, error); /** * ### listen * Assign current instance to port and start serving * * --- * @example * ```typescript * new Elysia() * .get("/", () => 'hi') * .listen(3000) * ``` */ this.listen = (options, callback) => (this["~adapter"].listen(this)(options, callback), this); /** * ### stop * Stop server from serving * * --- * @example * ```typescript * const app = new Elysia() * .get("/", () => 'hi') * .listen(3000) * * // Sometime later * app.stop() * ``` * * @example * ```typescript * const app = new Elysia() * .get("/", () => 'hi') * .listen(3000) * * app.stop(true) // Abruptly any requests inflight * ``` */ this.stop = async (closeActiveConnections) => (await this["~adapter"].stop?.(this, closeActiveConnections), this); this[_a] = () => { this.server && this.stop(); }; config.tags && (config.detail ? config.detail.tags = config.tags : config.detail = { tags: config.tags }), this.config = { aot: import_env.env.ELYSIA_AOT !== "false", nativeStaticResponse: !0, encodeSchema: !0, normalize: !0, ...config, prefix: config.prefix ? config.prefix.charCodeAt(0) === 47 ? config.prefix : `/${config.prefix}` : void 0, cookie: { path: "/", ...config?.cookie }, experimental: config?.experimental ?? {}, seed: config?.seed === void 0 ? "" : config?.seed }, this["~adapter"] = config.adapter ?? (typeof Bun < "u" ? import_bun.BunAdapter : import_web_standard.WebStandardAdapter), config?.analytic && (config?.name || config?.seed !== void 0) && (this.telemetry = { stack: new Error().stack }); } get store() { return this.singleton.store; } get decorator() { return this.singleton.decorator; } get routes() { return this.router.history; } getGlobalRoutes() { return this.router.history; } getGlobalDefinitions() { return this.definitions; } getServer() { return this.server; } getParent() { return null; } get promisedModules() { return this._promisedModules || (this._promisedModules = new import_utils.PromiseGroup(console.error, () => { })), this._promisedModules; } env(model, _env = import_env.env) { if ((0, import_schema.getSchemaValidator)(model, { modules: this.definitions.typebox, dynamic: !0, additionalProperties: !0, coerce: !0, sanitize: () => this.config.sanitize }).Check(_env) === !1) { const error = new import_error.ValidationError("env", model, _env); throw new Error(error.all.map((x) => x.summary).join(` `)); } return this; } /** * @private DO_NOT_USE_OR_YOU_WILL_BE_FIRED * @version 1.1.0 * * ! Do not use unless you know exactly what you are doing * ? Add Higher order function to Elysia.fetch */ wrap(fn) { return this.extender.higherOrderFunctions.push({ checksum: (0, import_utils2.checksum)( JSON.stringify({ name: this.config.name, seed: this.config.seed, content: fn.toString() }) ), fn }), this; } get models() { const models = {}; for (const name of Object.keys(this.definitions.type)) models[name] = (0, import_schema.getSchemaValidator)( this.definitions.typebox.Import(name), { models: this.definitions.type } ); return models.modules = this.definitions.typebox, models; } add(method, path, handle, localHook, options) { const skipPrefix = options?.skipPrefix ?? !1, allowMeta = options?.allowMeta ?? !1; localHook ??= {}, this.applyMacro(localHook); let standaloneValidators = []; if (localHook.standaloneValidator && (standaloneValidators = standaloneValidators.concat( localHook.standaloneValidator )), this.standaloneValidator.local && (standaloneValidators = standaloneValidators.concat( this.standaloneValidator.local )), this.standaloneValidator.scoped && (standaloneValidators = standaloneValidators.concat( this.standaloneValidator.scoped )), this.standaloneValidator.global && (standaloneValidators = standaloneValidators.concat( this.standaloneValidator.global )), path !== "" && path.charCodeAt(0) !== 47 && (path = "/" + path), this.config.prefix && !skipPrefix && (path = this.config.prefix + path), localHook?.type) switch (localHook.type) { case "text": localHook.type = "text/plain"; break; case "json": localHook.type = "application/json"; break; case "formdata": localHook.type = "multipart/form-data"; break; case "urlencoded": localHook.type = "application/x-www-form-urlencoded"; break; case "arrayBuffer": localHook.type = "application/octet-stream"; break; default: break; } const instanceValidator = this.validator.getCandidate(), cloned = { body: localHook?.body ?? instanceValidator?.body, headers: localHook?.headers ?? instanceValidator?.headers, params: localHook?.params ?? instanceValidator?.params, query: localHook?.query ?? instanceValidator?.query, cookie: localHook?.cookie ?? instanceValidator?.cookie, response: localHook?.response ?? instanceValidator?.response }, shouldPrecompile = this.config.precompile === !0 || typeof this.config.precompile == "object" && this.config.precompile.compose === !0, createValidator = () => { const models = this.definitions.type, dynamic = !this.config.aot, normalize = this.config.normalize, modules = this.definitions.typebox, sanitize = () => this.config.sanitize, cookieValidator = () => { if (cloned.cookie || standaloneValidators.find((x) => x.cookie)) return (0, import_schema.getCookieValidator)({ modules, validator: cloned.cookie, defaultConfig: this.config.cookie, normalize, config: cloned.cookie?.config ?? {}, dynamic, models, validators: standaloneValidators.map((x) => x.cookie), sanitize }); }; return shouldPrecompile ? { body: (0, import_schema.getSchemaValidator)(cloned.body, { modules, dynamic, models, normalize, additionalCoerce: (() => { const resolved = (0, import_schema.resolveSchema)( cloned.body, models, modules ); return resolved && import_typebox.Kind in resolved && ((0, import_schema.hasType)("File", resolved) || (0, import_schema.hasType)("Files", resolved)) ? (0, import_replace_schema.coerceFormData)() : (0, import_replace_schema.coercePrimitiveRoot)(); })(), validators: standaloneValidators.map((x) => x.body), sanitize }), headers: (0, import_schema.getSchemaValidator)(cloned.headers, { modules, dynamic, models, additionalProperties: !0, coerce: !0, additionalCoerce: (0, import_replace_schema.stringToStructureCoercions)(), validators: standaloneValidators.map( (x) => x.headers ), sanitize }), params: (0, import_schema.getSchemaValidator)(cloned.params, { modules, dynamic, models, coerce: !0, additionalCoerce: (0, import_replace_schema.stringToStructureCoercions)(), validators: standaloneValidators.map( (x) => x.params ), sanitize }), query: (0, import_schema.getSchemaValidator)(cloned.query, { modules, dynamic, models, normalize, coerce: !0, additionalCoerce: (0, import_replace_schema.queryCoercions)(), validators: standaloneValidators.map( (x) => x.query ), sanitize }), cookie: cookieValidator(), response: (0, import_schema.getResponseSchemaValidator)(cloned.response, { modules, dynamic, models, normalize, validators: standaloneValidators.map( (x) => x.response ), sanitize }) } : { createBody() { return this.body ? this.body : this.body = (0, import_schema.getSchemaValidator)( cloned.body, { modules, dynamic, models, normalize, additionalCoerce: (() => { const resolved = (0, import_schema.resolveSchema)( cloned.body, models, modules ); return resolved && import_typebox.Kind in resolved && ((0, import_schema.hasType)("File", resolved) || (0, import_schema.hasType)("Files", resolved)) ? (0, import_replace_schema.coerceFormData)() : (0, import_replace_schema.coercePrimitiveRoot)(); })(), validators: standaloneValidators.map( (x) => x.body ), sanitize } ); }, createHeaders() { return this.headers ? this.headers : this.headers = (0, import_schema.getSchemaValidator)( cloned.headers, { modules, dynamic, models, normalize, additionalProperties: !normalize, coerce: !0, additionalCoerce: (0, import_replace_schema.stringToStructureCoercions)(), validators: standaloneValidators.map( (x) => x.headers ), sanitize } ); }, createParams() { return this.params ? this.params : this.params = (0, import_schema.getSchemaValidator)( cloned.params, { modules, dynamic, models, normalize, coerce: !0, additionalCoerce: (0, import_replace_schema.stringToStructureCoercions)(), validators: standaloneValidators.map( (x) => x.params ), sanitize } ); }, createQuery() { return this.query ? this.query : this.query = (0, import_schema.getSchemaValidator)( cloned.query, { modules, dynamic, models, normalize, coerce: !0, additionalCoerce: (0, import_replace_schema.queryCoercions)(), validators: standaloneValidators.map( (x) => x.query ), sanitize } ); }, createCookie() { return this.cookie ? this.cookie : this.cookie = cookieValidator(); }, createResponse() { return this.response ? this.response : this.response = (0, import_schema.getResponseSchemaValidator)( cloned.response, { modules, dynamic, models, normalize, validators: standaloneValidators.map( (x) => x.response ), sanitize } ); } }; }; (instanceValidator.body || instanceValidator.cookie || instanceValidator.headers || instanceValidator.params || instanceValidator.query || instanceValidator.response) && (localHook = (0, import_utils2.mergeHook)(localHook, instanceValidator)), localHook.tags && (localHook.detail ? localHook.detail.tags = localHook.tags : localHook.detail = { tags: localHook.tags }), (0, import_utils.isNotEmpty)(this.config.detail) && (localHook.detail = (0, import_utils.mergeDeep)( Object.assign({}, this.config.detail), localHook.detail )); const hooks = (0, import_utils.isNotEmpty)(this.event) ? (0, import_utils2.mergeHook)(this.event, (0, import_utils.localHookToLifeCycleStore)(localHook)) : { ...(0, import_utils.lifeCycleToArray)((0, import_utils.localHookToLifeCycleStore)(localHook)) }; if (standaloneValidators.length && Object.assign(hooks, { standaloneValidator: standaloneValidators }), this.config.aot === !1) { const validator = createValidator(); this.router.dynamic.add(method, path, { validator, hooks, content: localHook?.type, handle, route: path }); const encoded = (0, import_utils.encodePath)(path, { dynamic: !0 }); if (path !== encoded && this.router.dynamic.add(method, encoded, { validator, hooks, content: localHook?.type, handle, route: path }), !this.config.strictPath) { const loosePath = (0, import_utils.getLoosePath)(path); this.router.dynamic.add(method, loosePath, { validator, hooks, content: localHook?.type, handle, route: path }); const encoded2 = (0, import_utils.encodePath)(loosePath); loosePath !== encoded2 && this.router.dynamic.add(method, loosePath, { validator, hooks, content: localHook?.type, handle, route: path }); } this.router.history.push({ method, path, composed: null, handler: handle, compile: void 0, hooks }); return; } const adapter = this["~adapter"].handler, nativeStaticHandler = typeof handle != "function" ? () => { const context = { redirect: import_utils.redirect, request: this["~adapter"].isWebStandard ? new Request(`http://ely.sia${path}`, { method }) : void 0, server: null, set: { headers: Object.assign({}, this.setHeaders) }, status: import_error.status, store: this.store }; try { this.event.request?.map((x) => { if (typeof x.fn == "function") return x.fn(context); if (typeof x == "function") return x(context); }); } catch (error) { let res; context.error = error, this.event.error?.some((x) => { if (typeof x.fn == "function") return res = x.fn(context); if (typeof x == "function") return res = x(context); }), res !== void 0 && (handle = res); } const fn = adapter.createNativeStaticHandler?.( handle, hooks, context.set ); return fn instanceof Promise ? fn.then((fn2) => { if (fn2) return fn2; }) : fn?.(); } : void 0, useNativeStaticResponse = this.config.nativeStaticResponse === !0, addResponsePath = (path2) => { !useNativeStaticResponse || !nativeStaticHandler || (import_utils.supportPerMethodInlineHandler ? this.router.response[path2] ? this.router.response[path2][method] = nativeStaticHandler() : this.router.response[path2] = { [method]: nativeStaticHandler() } : this.router.response[path2] = nativeStaticHandler()); }; addResponsePath(path); let _compiled; const compile = () => { if (_compiled) return _compiled; const compiled = (0, import_compose.composeHandler)({ app: this, path, method, hooks, validator: createValidator(), handler: typeof handle != "function" && typeof adapter.createStaticHandler != "function" ? () => handle : handle, allowMeta, inference: this.inference }); return this.router.history[index] && (_compiled = this.router.history[index].composed = compiled), compiled; }; let oldIndex; if (`${method}_${path}` in this.routeTree) for (let i = 0; i < this.router.history.length; i++) { const route2 = this.router.history[i]; if (route2.path === path && route2.method === method) { oldIndex = i; break; } } else this.routeTree[`${method}_${path}`] = this.router.history.length; const index = oldIndex ?? this.router.history.length, route = this.router.history, mainHandler = shouldPrecompile ? compile() : (ctx) => _compiled ? _compiled(ctx) : (route[index].composed = compile())(ctx); oldIndex !== void 0 ? this.router.history[oldIndex] = Object.assign( { method, path, composed: mainHandler, compile, handler: handle, hooks }, standaloneValidators.length ? { standaloneValidators } : void 0, localHook.webSocket ? { websocket: localHook.websocket } : void 0 ) : this.router.history.push( Object.assign( { method, path, composed: mainHandler, compile, handler: handle, hooks }, localHook.webSocket ? { websocket: localHook.websocket } : void 0 ) ); const handler = { handler: shouldPrecompile ? route[index].composed : void 0, compile() { return this.handler = compile(); } }, staticRouter = this.router.static, isStaticPath = path.indexOf(":") === -1 && path.indexOf("*") === -1; if (method === "WS") { if (isStaticPath) { path in staticRouter ? staticRouter[path][method] = index : staticRouter[path] = { [method]: index }; return; } this.router.http.add("WS", path, handler), this.config.strictPath || this.router.http.add("WS", (0, import_utils.getLoosePath)(path), handler); const encoded = (0, import_utils.encodePath)(path, { dynamic: !0 }); path !== encoded && this.router.http.add("WS", encoded, handler); return; } if (isStaticPath) path in staticRouter ? staticRouter[path][method] = index : staticRouter[path] = { [method]: index }, this.config.strictPath || addResponsePath((0, import_utils.getLoosePath)(path)); else { if (this.router.http.add(method, path, handler), !this.config.strictPath) { const loosePath = (0, import_utils.getLoosePath)(path); addResponsePath(loosePath), this.router.http.add(method, loosePath, handler); } const encoded = (0, import_utils.encodePath)(path, { dynamic: !0 }); path !== encoded && (this.router.http.add(method, encoded, handler), addResponsePath(encoded)); } } headers(header) { return header ? (this.setHeaders || (this.setHeaders = {}), this.setHeaders = (0, import_utils.mergeDeep)(this.setHeaders, header), this) : this; } /** * ### start | Life cycle event * Called after server is ready for serving * * --- * @example * ```typescript * new Elysia() * .onStart(({ server }) => { * console.log("Running at ${server?.url}:${server?.port}") * }) * .listen(3000) * ``` */ onStart(handler) { return this.on("start", handler), this; } onRequest(handler) { return this.on("request", handler), this; } onParse(options, handler) { return handler ? this.on( options, "parse", handler ) : typeof options == "string" ? this.on("parse", this["~parser"][options]) : this.on("parse", options); } /** * ### parse | Life cycle event * Callback function to handle body parsing * * If truthy value is returned, will be assigned to `context.body` * Otherwise will skip the callback and look for the next one. * * Equivalent to Express's body parser * * --- * @example * ```typescript * new Elysia() * .onParse((request, contentType) => { * if(contentType === "application/json") * return request.json() * }) * ``` */ parser(name, parser) { return this["~parser"][name] = parser, this; } onTransform(options, handler) { return handler ? this.on( options, "transform", handler ) : this.on("transform", options); } resolve(optionsOrResolve, resolve) { resolve || (resolve = optionsOrResolve, optionsOrResolve = { as: "local" }); const hook = { subType: "resolve", fn: resolve }; return this.onBeforeHandle(optionsOrResolve, hook); } mapResolve(optionsOrResolve, mapper) { mapper || (mapper = optionsOrResolve, optionsOrResolve = { as: "local" }); const hook = { subType: "mapResolve", fn: mapper }; return this.onBeforeHandle(optionsOrResolve, hook); } onBeforeHandle(options, handler) { return handler ? this.on( options, "beforeHandle", handler ) : this.on("beforeHandle", options); } onAfterHandle(options, handler) { return handler ? this.on( options, "afterHandle", handler ) : this.on("afterHandle", options); } mapResponse(options, handler) { return handler ? this.on( options, "mapResponse", handler ) : this.on("mapResponse", options); } onAfterResponse(options, handler) { return handler ? this.on( options, "afterResponse", handler ) : this.on("afterResponse", options); } /** * ### After Handle | Life cycle event * Intercept request **after** main handler is called. * * If truthy value is returned, will be assigned as `Response` * * --- * @example * ```typescript * new Elysia() * .onAfterHandle((context, response) => { * if(typeof response === "object") * return JSON.stringify(response) * }) * ``` */ trace(options, handler) { handler || (handler = options, options = { as: "local" }), Array.isArray(handler) || (handler = [handler]); for (const fn of handler) this.on( options, "trace", (0, import_trace.createTracer)(fn) ); return this; } error(name, error) { switch (typeof name) { case "string": return error.prototype[import_error.ERROR_CODE] = name, this.definitions.error[name] = error, this; case "function": return this.definitions.error = name(this.definitions.error), this; } for (const [code, error2] of Object.entries(name)) error2.prototype[import_error.ERROR_CODE] = code, this.definitions.error[code] = error2; return this; } /** * ### Error | Life cycle event * Called when error is thrown during processing request * * --- * @example * ```typescript * new Elysia() * .onError(({ code }) => { * if(code === "NOT_FOUND") * return "Path not found :(" * }) * ``` */ onError(options, handler) { return handler ? this.on( options, "error", handler ) : this.on("error", options); } /** * ### stop | Life cycle event * Called after server stop serving request * * --- * @example * ```typescript * new Elysia() * .onStop((app) => { * cleanup() * }) * ``` */ onStop(handler) { return this.on("stop", handler), this; } on(optionsOrType, typeOrHandlers, handlers) { let type; switch (typeof optionsOrType) { case "string": type = optionsOrType, handlers = typeOrHandlers; break; case "object": type = typeOrHandlers, !Array.isArray(typeOrHandlers) && typeof typeOrHandlers == "object" && (handlers = typeOrHandlers); break; } Array.isArray(handlers) ? handlers = (0, import_utils.fnToContainer)(handlers) : typeof handlers == "function" ? handlers = [ { fn: handlers } ] : handlers = [handlers]; const handles = handlers; for (const handle of handles) handle.scope = typeof optionsOrType == "string" ? "local" : optionsOrType?.as ?? "local", (type === "resolve" || type === "derive") && (handle.subType = type); type !== "trace" && (this.inference = (0, import_sucrose.sucrose)( { [type]: handles.map((x) => x.fn) }, this.inference, this.config.sucrose )); for (const handle of handles) { const fn = (0, import_utils2.asHookType)(handle, "global", { skipIfHasType: !0 }); switch (type) { case "start": this.event.start ??= [], this.event.start.push(fn); break; case "request": this.event.request ??= [], this.event.request.push(fn); break; case "parse": this.event.parse ??= [], this.event.parse.push(fn); break; case "transform": this.event.transform ??= [], this.event.transform.push(fn); break; // @ts-expect-error case "derive": this.event.transform ??= [], this.event.transform.push( (0, import_utils.fnToContainer)(fn, "derive") ); break; case "beforeHandle": this.event.beforeHandle ??= [], this.event.beforeHandle.push(fn); break; // @ts-expect-error // eslint-disable-next-line sonarjs/no-duplicated-branches case "resolve": this.event.beforeHandle ??= [], this.event.beforeHandle.push( (0, import_utils.fnToContainer)(fn, "resolve") ); break; case "afterHandle": this.event.afterHandle ??= [], this.event.afterHandle.push(fn); break; case "mapResponse": this.event.mapResponse ??= [], this.event.mapResponse.push(fn); break; case "afterResponse": this.event.afterResponse ??= [], this.event.afterResponse.push(fn); break; case "trace": this.event.trace ??= [], this.event.trace.push(fn); break; case "error": this.event.error ??= [], this.event.error.push(fn); break; case "stop": this.event.stop ??= [], this.event.stop.push(fn); break; } } return this; } as(type) { return (0, import_utils.promoteEvent)(this.event.parse, type), (0, import_utils.promoteEvent)(this.event.transform, type), (0, import_utils.promoteEvent)(this.event.beforeHandle, type), (0, import_utils.promoteEvent)(this.event.afterHandle, type), (0, import_utils.promoteEvent)(this.event.mapResponse, type), (0, import_utils.promoteEvent)(this.event.afterResponse, type), (0, import_utils.promoteEvent)(this.event.trace, type), (0, import_utils.promoteEvent)(this.event.error, type), type === "scoped" ? (this.validator.scoped = (0, import_utils.mergeSchemaValidator)( this.validator.scoped, this.validator.local ), this.validator.local = null, this.standaloneValidator.local !== null && (this.standaloneValidator.scoped ||= [], this.standaloneValidator.scoped.push( ...this.standaloneValidator.local ), this.standaloneValidator.local = null)) : type === "global" && (this.validator.global = (0, import_utils.mergeSchemaValidator)( this.validator.global, (0, import_utils.mergeSchemaValidator)( this.validator.scoped, this.validator.local ) ), this.validator.scoped = null, this.validator.local = null, this.standaloneValidator.local !== null && (this.standaloneValidator.scoped ||= [], this.standaloneValidator.scoped.push( ...this.standaloneValidator.local ), this.standaloneValidator.local = null), this.standaloneValidator.scoped !== null && (this.standaloneValidator.global ||= [], this.standaloneValidator.global.push( ...this.standaloneValidator.scoped ), this.standaloneValidator.scoped = null)), this; } /** * ### group * Encapsulate and group path with prefix * * --- * @example * ```typescript * new Elysia() * .group('/v1', app => app * .get('/', () => 'Hi') * .get('/name', () => 'Elysia') * }) * ``` */ group(prefix, schemaOrRun, run) { const instance = new _Elysia({ ...this.config, prefix: "" }); instance.singleton = { ...this.singleton }, instance.definitions = { ...this.definitions }, instance.getServer = () => this.getServer(), instance.inference = (0, import_utils.cloneInference)(this.inference), instance.extender = { ...this.extender }, instance["~parser"] = this["~parser"], instance.standaloneValidator = { local: [...this.standaloneValidator.local ?? []], scoped: [...this.standaloneValidator.scoped ?? []], global: [...this.standaloneValidator.global ?? []] }; const isSchema = typeof schemaOrRun == "object", sandbox = (isSchema ? run : schemaOrRun)(instance); return this.singleton = (0, import_utils.mergeDeep)(this.singleton, instance.singleton), this.definitions = (0, import_utils.mergeDeep)(this.definitions, instance.definitions), sandbox.event.request?.length && (this.event.request = [ ...this.event.request || [], ...sandbox.event.request || [] ]), sandbox.event.mapResponse?.length && (this.event.mapResponse = [ ...this.event.mapResponse || [], ...sandbox.event.mapResponse || [] ]), this.model(sandbox.definitions.type), Object.values(instance.router.history).forEach( ({ method, path, handler, hooks }) => { if (path = (isSchema ? "" : this.config.prefix ?? "") + prefix + path, isSchema) { const { body, headers, query, params, cookie, response, ...hook } = schemaOrRun, localHook = hooks; this.applyMacro(hook); const hasStandaloneSchema = body || headers || query || params || cookie || response; this.add( method, path, handler, (0, import_utils2.mergeHook)(hook, { ...localHook || {}, error: localHook.error ? Array.isArray(localHook.error) ? [ ...localHook.error ?? [], ...sandbox.event.error ?? [] ] : [ localHook.error, ...sandbox.event.error ?? [] ] : sandbox.event.error, // Merge macro's standaloneValidator with local and group schema standaloneValidator: hook.standaloneValidator || localHook.standaloneValidator || hasStandaloneSchema ? [ ...hook.standaloneValidator ?? [], ...localHook.standaloneValidator ?? [], ...hasStandaloneSchema ? [ { body, headers, query, params, cookie, response } ] : [] ] : void 0 }), void 0 ); } else this.add( method, path, handler, (0, import_utils2.mergeHook)(hooks, { error: sandbox.event.error }), { skipPrefix: !0 } ); } ), this; } /** * ### guard * Encapsulate and pass hook into all child handler * * --- * @example * ```typescript * import { t } from 'elysia' * * new Elysia() * .guard({ * body: t.Object({ * username: t.String(), * password: t.String() * }) * }, app => app * .get("/", () => 'Hi') * .get("/name", () => 'Elysia') * }) * ``` */ guard(hook, run) { if (!run) { if (typeof hook == "object") { this.applyMacro(hook), hook.detail && (this.config.detail ? this.config.detail = (0, import_utils.mergeDeep)( Object.assign({}, this.config.detail), hook.detail ) : this.config.detail = hook.detail), hook.tags && (this.config.detail ? this.config.detail.tags = hook.tags : this.config.detail = { tags: hook.tags }); const type = hook.as ?? "local"; if (hook.schema === "standalone") { this.standaloneValidator[type] || (this.standaloneValidator[type] = []); const response = hook?.response ? typeof hook.response == "string" || import_typebox.Kind in hook.response || "~standard" in hook.response ? { 200: hook.response } : hook?.response : void 0; this.standaloneValidator[type].push({ body: hook.body, headers: hook.headers, params: hook.params, query: hook.query, response, cookie: hook.cookie }); } else this.validator[type] = { body: hook.body ?? this.validator[type]?.body, headers: hook.headers ?? this.validator[type]?.headers, params: hook.params ?? this.validator[type]?.params, query: hook.query ?? this.validator[type]?.query, response: hook.response ?? this.validator[type]?.response, cookie: hook.cookie ?? this.validator[type]?.cookie }; return hook.parse && this.on({ as: type }, "parse", hook.parse), hook.transform && this.on({ as: type }, "transform", hook.transform), hook.derive && this.on({ as: type }, "derive", hook.derive), hook.beforeHandle && this.on({ as: type }, "beforeHandle", hook.beforeHandle), hook.resolve && this.on({ as: type }, "resolve", hook.resolve), hook.afterHandle && this.on({ as: type }, "afterHandle", hook.afterHandle), hook.mapResponse && this.on({ as: type }, "mapResponse", hook.mapResponse), hook.afterResponse && this.on({ as: type }, "afterResponse", hook.afterResponse), hook.error && this.on({ as: type }, "error", hook.error), this; } return this.guard({}, hook); } const instance = new _Elysia({ ...this.config, prefix: "" }); instance.singleton = { ...this.singleton }, instance.definitions = { ...this.definitions }, instance.inference = (0, import_utils.cloneInference)(this.inference), instance.extender = { ...this.extender }, instance.getServer = () => this.getServer(); const sandbox = run(instance); return this.singleton = (0, import_utils.mergeDeep)(this.singleton, instance.singleton), this.definitions = (0, import_utils.mergeDeep)(this.definitions, instance.definitions), sandbox.getServer = () => this.server, sandbox.event.request?.length && (this.event.request = [ ...this.event.request || [], ...sandbox.event.request || [] ]), sandbox.event.mapResponse?.length && (this.event.mapResponse = [ ...this.event.mapResponse || [], ...sandbox.event.mapResponse || [] ]), this.model(sandbox.definitions.type), Object.values(instance.router.history).forEach( ({ method, path, handler, hooks: localHook }) => { const { body, headers, query, params, cookie, response, ...guardHook } = hook, hasStandaloneSchema = body || headers || query || params || cookie || response; this.add( method, path, handler, (0, import_utils2.mergeHook)(guardHook, { ...localHook || {}, error: localHook.error ? Array.isArray(localHook.error) ? [ ...localHook.error ?? [], ...sandbox.event.error ?? [] ] : [ localHook.error, ...sandbox.event.error ?? [] ] : sandbox.event.error, standaloneValidator: hasStandaloneSchema ? [ ...localHook.standaloneValidator ?? [], { body, headers, query, params, cookie, response } ] : localHook.standaloneValidator }) ); } ), this; } /** * ### use * Merge separate logic of Elysia with current * * --- * @example * ```typescript * const plugin = (app: Elysia) => app * .get('/plugin', () => 'hi') * * new Elysia() * .use(plugin) * ``` */ use(plugin) { if (!plugin) return this; if (Array.isArray(plugin)) { let app = this; for (const p of plugin) app = app.use(p); return app; } return plugin instanceof Promise ? (this.promisedModules.add( plugin.then((plugin2) => { if (typeof plugin2 == "function") return plugin2(this); if (plugin2 instanceof _Elysia) return this._use(plugin2).compile(); if (plugin2.constructor?.name === "Elysia") return this._use( plugin2 ).compile(); if (typeof plugin2.default == "function") return plugin2.default(this); if (plugin2.default instanceof _Elysia) return this._use(plugin2.default); if (plugin2.constructor?.name === "Elysia") return this._use(plugin2.default); if (plugin2.constructor?.name === "_Elysia") return this._use(plugin2.default); try { return this._use(plugin2.default); } catch (error) { throw console.error( 'Invalid plugin type. Expected Elysia instance, function, or module with "default" as Elysia instance or function that returns Elysia instance.' ), error; } }).then((v) => (v && typeof v.compile == "function" && v.compile(), v)) ), this) : this._use(plugin); } propagatePromiseModules(plugin) { if (plugin.promisedModules.size <= 0) return this; for (const promise of plugin.promisedModules.promises) this.promisedModules.add( promise.then((v) => { if (!v) return; const t3 = this._use(v); return t3 instanceof Promise ? t3.then((v2) => { v2 ? v2.compile() : v.compile(); }) : v.compile(); }) ); return this; } _use(plugin) { if (typeof plugin == "function") { const instance = plugin(this); return instance instanceof Promise ? (this.promisedModules.add( instance.then((plugin2) => { if (plugin2 instanceof _Elysia) { plugin2.getServer = () => this.getServer(), plugin2.getGlobalRoutes = () => this.getGlobalRoutes(), plugin2.getGlobalDefinitions = () => this.getGlobalDefinitions(), plugin2.model(this.definitions.type), plugin2.error(this.definitions.error); for (const { method, path, handler, hooks } of Object.values(plugin2.router.history)) this.add( method, path, handler, hooks, void 0 ); return plugin2 === this ? void 0 : (this.propagatePromiseModules(plugin2), plugin2); } return typeof plugin2 == "function" ? plugin2( this ) : typeof plugin2.default == "function" ? plugin2.default( this ) : this._use(plugin2); }).then((v) => (v && typeof v.compile == "function" && v.compile(), v)) ), this) : instance; } this.propagatePromiseModules(plugin); const name = plugin.config.name, seed = plugin.config.seed; if (plugin.getParent = () => this, plugin.getServer = () => this.getServer(), plugin.getGlobalRoutes = () => this.getGlobalRoutes(), plugin.getGlobalDefinitions = () => this.getGlobalDefinitions(), plugin.standaloneValidator?.scoped && (this.standaloneValidator.local ? this.standaloneValidator.local = this.standaloneValidator.local.concat( plugin.standaloneValidator.scoped ) : this.standaloneValidator.local = plugin.standaloneValidator.scoped), plugin.standaloneValidator?.global && (this.standaloneValidator.global ? this.standaloneValidator.global = this.standaloneValidator.global.concat( plugin.standaloneValidator.global ) : this.standaloneValidator.global = plugin.standaloneValidator.global), (0, import_utils.isNotEmpty)(plugin["~parser"]) && (this["~parser"] = { ...plugin["~parser"], ...this["~parser"] }), plugin.setHeaders && this.headers(plugin.setHeaders), name) { name in this.dependencies || (this.dependencies[name] = []); const current = seed !== void 0 ? (0, import_utils2.checksum)(name + JSON.stringify(seed)) : 0; this.dependencies[name].some( ({ checksum: checksum3 }) => current === checksum3 ) || (this.extender.macro = { ...this.extender.macro, ...plugin.extender.macro }, this.extender.higherOrderFunctions = this.extender.higherOrderFunctions.concat( plugin.extender.higherOrderFunctions )); } else (0, import_utils.isNotEmpty)(plugin.extender.macro) && (this.extender.macro = { ...this.extender.macro, ...plugin.extender.macro }), plugin.extender.higherOrderFunctions.length && (this.extender.higherOrderFunctions = this.extender.higherOrderFunctions.concat( plugin.extender.higherOrderFunctions )); if (plugin.extender.higherOrderFunctions.length) { (0, import_utils.deduplicateChecksum)(this.extender.higherOrderFunctions); const hofHashes = []; for (let i = 0; i < this.extender.higherOrderFunctions.length; i++) { const hof = this.extender.higherOrderFunctions[i]; hof.checksum && (hofHashes.includes(hof.checksum) && (this.extender.higherOrderFunctions.splice(i, 1), i--), hofHashes.push(hof.checksum)); } hofHashes.length = 0; } this.inference = (0, import_sucrose.mergeInference)(this.inference, plugin.inference), (0, import_utils.isNotEmpty)(plugin.singleton.decorator) && this.decorate(plugin.singleton.decorator), (0, import_utils.isNotEmpty)(plugin.singleton.store) && this.state(plugin.singleton.store), (0, import_utils.isNotEmpty)(plugin.definitions.type) && this.model(plugin.definitions.type), (0, import_utils.isNotEmpty)(plugin.definitions.error) && this.error(plugin.definitions.error), (0, import_utils.isNotEmpty)(plugin.extender.macro) && (this.extender.macro = { ...this.extender.macro, ...plugin.extender.macro }); for (const { method, path, handler, hooks } of Object.values( plugin.router.history )) this.add(method, path, handler, hooks); if (name) { name in this.dependencies || (this.dependencies[name] = []); const current = seed !== void 0 ? (0, import_utils2.checksum)(name + JSON.stringify(seed)) : 0; if (this.dependencies[name].some( ({ checksum: checksum3 }) => current === checksum3 )) return this; this.dependencies[name].push( this.config?.analytic ? { name: plugin.config.name, seed: plugin.config.seed, checksum: current,