UNPKG

elysia

Version:

Ergonomic Framework for Human

1,418 lines (1,407 loc) 142 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); // src/adapter/bun/index.ts var bun_exports = {}; __export(bun_exports, { BunAdapter: () => BunAdapter }); module.exports = __toCommonJS(bun_exports); // src/cookies.ts var import_cookie = require("cookie"), import_fast_decode_uri_component = __toESM(require("fast-decode-uri-component")); // src/universal/utils.ts var isBun = typeof Bun < "u"; // src/universal/file.ts var mime2 = { aac: "audio/aac", abw: "application/x-abiword", ai: "application/postscript", arc: "application/octet-stream", avi: "video/x-msvideo", azw: "application/vnd.amazon.ebook", bin: "application/octet-stream", bz: "application/x-bzip", bz2: "application/x-bzip2", csh: "application/x-csh", css: "text/css", csv: "text/csv", doc: "application/msword", dll: "application/octet-stream", eot: "application/vnd.ms-fontobject", epub: "application/epub+zip", gif: "image/gif", htm: "text/html", html: "text/html", ico: "image/x-icon", ics: "text/calendar", jar: "application/java-archive", jpeg: "image/jpeg", jpg: "image/jpeg", js: "application/javascript", json: "application/json", mid: "audio/midi", midi: "audio/midi", mp2: "audio/mpeg", mp3: "audio/mpeg", mp4: "video/mp4", mpa: "video/mpeg", mpe: "video/mpeg", mpeg: "video/mpeg", mpkg: "application/vnd.apple.installer+xml", odp: "application/vnd.oasis.opendocument.presentation", ods: "application/vnd.oasis.opendocument.spreadsheet", odt: "application/vnd.oasis.opendocument.text", oga: "audio/ogg", ogv: "video/ogg", ogx: "application/ogg", otf: "font/otf", png: "image/png", pdf: "application/pdf", ppt: "application/vnd.ms-powerpoint", rar: "application/x-rar-compressed", rtf: "application/rtf", sh: "application/x-sh", svg: "image/svg+xml", swf: "application/x-shockwave-flash", tar: "application/x-tar", tif: "image/tiff", tiff: "image/tiff", ts: "application/typescript", ttf: "font/ttf", txt: "text/plain", vsd: "application/vnd.visio", wav: "audio/x-wav", weba: "audio/webm", webm: "video/webm", webp: "image/webp", woff: "font/woff", woff2: "font/woff2", xhtml: "application/xhtml+xml", xls: "application/vnd.ms-excel", xlsx: "application/vnd.ms-excel", xlsx_OLD: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", xml: "application/xml", xul: "application/vnd.mozilla.xul+xml", zip: "application/zip", "3gp": "video/3gpp", "3gp_DOES_NOT_CONTAIN_VIDEO": "audio/3gpp", "3gp2": "video/3gpp2", "3gp2_DOES_NOT_CONTAIN_VIDEO": "audio/3gpp2", "7z": "application/x-7z-compressed" }, getFileExtension = (path) => { let index = path.lastIndexOf("."); return index === -1 ? "" : path.slice(index + 1); }; var createReadStream, stat, ElysiaFile = class { constructor(path) { this.path = path; if (isBun) this.value = Bun.file(path); else if (typeof window < "u") console.warn("Browser environment does not support file"); else if (!createReadStream || !stat) try { this.value = import("fs").then((fs) => (createReadStream = fs.createReadStream, fs.createReadStream(path))), this.stats = import("fs/promises").then((fs) => (stat = fs.stat, fs.stat(path))); } catch { } else this.value = createReadStream(path), this.stats = stat(path); } get type() { return ( // @ts-ignore mime2[getFileExtension(this.path)] || "application/octet-stream" ); } get length() { return isBun ? this.value.size : this.stats?.then((x) => x.size) ?? 0; } }; // src/utils.ts var hasHeaderShorthand = "toJSON" in new Headers(); var primitiveHooks = [ "start", "request", "parse", "transform", "resolve", "beforeHandle", "afterHandle", "mapResponse", "afterResponse", "trace", "error", "stop", "body", "headers", "params", "query", "response", "type", "detail" ], primitiveHookMap = primitiveHooks.reduce( (acc, x) => (acc[x] = !0, acc), {} ); var isBun2 = typeof Bun < "u", hasBunHash = isBun2 && typeof Bun.hash == "function", checksum = (s) => { if (hasBunHash) return Bun.hash(s); let h = 9; for (let i = 0; i < s.length; ) h = Math.imul(h ^ s.charCodeAt(i++), 9 ** 9); return h = h ^ h >>> 9; }; var StatusMap = { Continue: 100, "Switching Protocols": 101, Processing: 102, "Early Hints": 103, OK: 200, Created: 201, Accepted: 202, "Non-Authoritative Information": 203, "No Content": 204, "Reset Content": 205, "Partial Content": 206, "Multi-Status": 207, "Already Reported": 208, "Multiple Choices": 300, "Moved Permanently": 301, Found: 302, "See Other": 303, "Not Modified": 304, "Temporary Redirect": 307, "Permanent Redirect": 308, "Bad Request": 400, Unauthorized: 401, "Payment Required": 402, Forbidden: 403, "Not Found": 404, "Method Not Allowed": 405, "Not Acceptable": 406, "Proxy Authentication Required": 407, "Request Timeout": 408, Conflict: 409, Gone: 410, "Length Required": 411, "Precondition Failed": 412, "Payload Too Large": 413, "URI Too Long": 414, "Unsupported Media Type": 415, "Range Not Satisfiable": 416, "Expectation Failed": 417, "I'm a teapot": 418, "Misdirected Request": 421, "Unprocessable Content": 422, Locked: 423, "Failed Dependency": 424, "Too Early": 425, "Upgrade Required": 426, "Precondition Required": 428, "Too Many Requests": 429, "Request Header Fields Too Large": 431, "Unavailable For Legal Reasons": 451, "Internal Server Error": 500, "Not Implemented": 501, "Bad Gateway": 502, "Service Unavailable": 503, "Gateway Timeout": 504, "HTTP Version Not Supported": 505, "Variant Also Negotiates": 506, "Insufficient Storage": 507, "Loop Detected": 508, "Not Extended": 510, "Network Authentication Required": 511 }, InvertedStatusMap = Object.fromEntries( Object.entries(StatusMap).map(([k, v]) => [v, k]) ); var encoder = new TextEncoder(); var parseNumericString = (message) => { if (typeof message == "number") return message; if (message.length < 16) { if (message.trim().length === 0) return null; let length = Number(message); return Number.isNaN(length) ? null : length; } if (message.length === 16) { if (message.trim().length === 0) return null; let number = Number(message); return Number.isNaN(number) || number.toString() !== message ? null : number; } return null; }, isNumericString = (message) => parseNumericString(message) !== null; var redirect = (url, status2 = 302) => Response.redirect(url, status2), ELYSIA_FORM_DATA = Symbol("ElysiaFormData"), ELYSIA_REQUEST_ID = Symbol("ElysiaRequestId"), form = (items) => { let formData = new FormData(); if (formData[ELYSIA_FORM_DATA] = {}, items) for (let [key, value] of Object.entries(items)) { if (Array.isArray(value)) { formData[ELYSIA_FORM_DATA][key] = []; for (let v of value) value instanceof File ? formData.append(key, value, value.name) : value instanceof ElysiaFile ? formData.append(key, value.value, value.value?.name) : formData.append(key, value), formData[ELYSIA_FORM_DATA][key].push(value); continue; } value instanceof File ? formData.append(key, value, value.name) : value instanceof ElysiaFile ? formData.append(key, value.value, value.value?.name) : formData.append(key, value), formData[ELYSIA_FORM_DATA][key] = value; } return formData; }, randomId = () => { let uuid = crypto.randomUUID(); return uuid.slice(0, 8) + uuid.slice(24, 32); }; var isNotEmpty = (obj) => { if (!obj) return !1; for (let _ in obj) return !0; return !1; }; var supportPerMethodInlineHandler = (() => { if (typeof Bun > "u") return !0; let semver = Bun.version.split("."); return !(+semver[0] < 1 || +semver[1] < 2 || +semver[2] < 14); })(); // src/error.ts var import_value = require("@sinclair/typebox/value"); var env = typeof Bun < "u" ? Bun.env : typeof process < "u" ? process?.env : void 0, ERROR_CODE = Symbol("ElysiaErrorCode"), isProduction = (env?.NODE_ENV ?? env?.ENV) === "production", emptyHttpStatus = { 101: void 0, 204: void 0, 205: void 0, 304: void 0, 307: void 0, 308: void 0 }, ElysiaCustomStatusResponse = class { constructor(code, response) { let res = response ?? (code in InvertedStatusMap ? ( // @ts-expect-error Always correct InvertedStatusMap[code] ) : code); this.code = StatusMap[code] ?? code, code in emptyHttpStatus ? this.response = void 0 : this.response = res; } }, status = (code, response) => new ElysiaCustomStatusResponse(code, response); var mapValueError = (error) => { if (!error) return { summary: void 0 }; let { message, path, value, type } = error, property = path.slice(1).replaceAll("/", "."), isRoot = path === ""; switch (type) { case 42: return { ...error, summary: isRoot ? "Value should not be provided" : `Property '${property}' should not be provided` }; case 45: return { ...error, summary: isRoot ? "Value is missing" : `Property '${property}' is missing` }; case 50: let quoteIndex = message.indexOf("'"), format = message.slice( quoteIndex + 1, message.indexOf("'", quoteIndex + 1) ); return { ...error, summary: isRoot ? "Value should be an email" : `Property '${property}' should be ${format}` }; case 54: return { ...error, summary: `${message.slice(0, 9).trim()} property '${property}' to be ${message.slice(8).trim()} but found: ${value}` }; case 62: let union = error.schema.anyOf.map((x) => `'${x?.format ?? x.type}'`).join(", "); return { ...error, summary: isRoot ? `Value should be one of ${union}` : `Property '${property}' should be one of: ${union}` }; default: return { summary: message, ...error }; } }; var ValidationError = class _ValidationError extends Error { constructor(type, validator, value, errors) { value && typeof value == "object" && value instanceof ElysiaCustomStatusResponse && (value = value.response); let error = errors?.First() || (isProduction ? void 0 : "Errors" in validator ? validator.Errors(value).First() : import_value.Value.Errors(validator, value).First()), customError = error?.schema?.message || error?.schema?.error !== void 0 ? typeof error.schema.error == "function" ? error.schema.error({ type, validator, value, get errors() { return [...validator.Errors(value)].map( mapValueError ); } }) : error.schema.error : void 0, accessor = error?.path || "root", message = ""; if (customError !== void 0) message = typeof customError == "object" ? JSON.stringify(customError) : customError + ""; else if (isProduction) message = JSON.stringify({ type: "validation", on: type, summary: mapValueError(error).summary, message: error?.message, found: value }); else { let schema = validator?.schema ?? validator, errors2 = "Errors" in validator ? [...validator.Errors(value)].map(mapValueError) : [...import_value.Value.Errors(validator, value)].map(mapValueError), expected; try { expected = import_value.Value.Create(schema); } catch (error2) { expected = { type: "Could not create expected value", // @ts-expect-error message: error2?.message, error: error2 }; } message = JSON.stringify( { type: "validation", on: type, summary: mapValueError(error).summary, property: accessor, message: error?.message, expected, found: value, errors: errors2 }, null, 2 ); } super(message); this.type = type; this.validator = validator; this.value = value; this.code = "VALIDATION"; this.status = 422; Object.setPrototypeOf(this, _ValidationError.prototype); } get all() { return "Errors" in this.validator ? [...this.validator.Errors(this.value)].map(mapValueError) : ( // @ts-ignore [...import_value.Value.Errors(this.validator, this.value)].map(mapValueError) ); } static simplifyModel(validator) { let model = "schema" in validator ? validator.schema : validator; try { return import_value.Value.Create(model); } catch { return model; } } get model() { return _ValidationError.simplifyModel(this.validator); } toResponse(headers) { return new Response(this.message, { status: 400, headers: { ...headers, "content-type": "application/json" } }); } }; // src/cookies.ts var Cookie = class { constructor(name, jar, initial = {}) { this.name = name; this.jar = jar; this.initial = initial; } get cookie() { return this.jar[this.name] ?? this.initial; } set cookie(jar) { this.name in this.jar || (this.jar[this.name] = this.initial), this.jar[this.name] = jar; } get setCookie() { return this.name in this.jar || (this.jar[this.name] = this.initial), this.jar[this.name]; } set setCookie(jar) { this.cookie = jar; } get value() { return this.cookie.value; } set value(value) { this.setCookie.value = value; } get expires() { return this.cookie.expires; } set expires(expires) { this.setCookie.expires = expires; } get maxAge() { return this.cookie.maxAge; } set maxAge(maxAge) { this.setCookie.maxAge = maxAge; } get domain() { return this.cookie.domain; } set domain(domain) { this.setCookie.domain = domain; } get path() { return this.cookie.path; } set path(path) { this.setCookie.path = path; } get secure() { return this.cookie.secure; } set secure(secure) { this.setCookie.secure = secure; } get httpOnly() { return this.cookie.httpOnly; } set httpOnly(httpOnly) { this.setCookie.httpOnly = httpOnly; } get sameSite() { return this.cookie.sameSite; } set sameSite(sameSite) { this.setCookie.sameSite = sameSite; } get priority() { return this.cookie.priority; } set priority(priority) { this.setCookie.priority = priority; } get partitioned() { return this.cookie.partitioned; } set partitioned(partitioned) { this.setCookie.partitioned = partitioned; } get secrets() { return this.cookie.secrets; } set secrets(secrets) { this.setCookie.secrets = secrets; } update(config) { return this.setCookie = Object.assign( this.cookie, typeof config == "function" ? config(this.cookie) : config ), this; } set(config) { return this.setCookie = Object.assign( { ...this.initial, value: this.value }, typeof config == "function" ? config(this.cookie) : config ), this; } remove() { if (this.value !== void 0) return this.set({ expires: /* @__PURE__ */ new Date(0), maxAge: 0, value: "" }), this; } toString() { return typeof this.value == "object" ? JSON.stringify(this.value) : this.value?.toString() ?? ""; } }; var serializeCookie = (cookies) => { if (!cookies || !isNotEmpty(cookies)) return; let set2 = []; for (let [key, property] of Object.entries(cookies)) { if (!key || !property) continue; let value = property.value; value != null && set2.push( (0, import_cookie.serialize)( key, typeof value == "object" ? JSON.stringify(value) : value + "", property ) ); } if (set2.length !== 0) return set2.length === 1 ? set2[0] : set2; }; // src/adapter/utils.ts var handleFile = (response, set2) => { if (!isBun && response instanceof Promise) return response.then((res) => handleFile(res, set2)); let size = response.size, immutable = set2 && (set2.status === 206 || set2.status === 304 || set2.status === 412 || set2.status === 416), defaultHeader = immutable ? { "transfer-encoding": "chunked" } : { "accept-ranges": "bytes", "content-range": size ? `bytes 0-${size - 1}/${size}` : void 0, "transfer-encoding": "chunked" }; if (!set2 && !size) return new Response(response); if (!set2) return new Response(response, { headers: defaultHeader }); if (set2.headers instanceof Headers) { let setHeaders = defaultHeader; if (hasHeaderShorthand) setHeaders = set2.headers.toJSON(); else { setHeaders = {}; for (let [key, value] of set2.headers.entries()) key in set2.headers && (setHeaders[key] = value); } return immutable && (delete set2.headers["content-length"], delete set2.headers["accept-ranges"]), new Response(response, { status: set2.status, headers: setHeaders }); } return isNotEmpty(set2.headers) ? new Response(response, { status: set2.status, headers: Object.assign(defaultHeader, set2.headers) }) : new Response(response, { status: set2.status, headers: defaultHeader }); }, parseSetCookies = (headers, setCookie) => { if (!headers) return headers; headers.delete("set-cookie"); for (let i = 0; i < setCookie.length; i++) { let index = setCookie[i].indexOf("="); headers.append( "set-cookie", `${setCookie[i].slice(0, index)}=${setCookie[i].slice(index + 1) || ""}` ); } return headers; }, responseToSetHeaders = (response, set2) => { if (set2?.headers) { if (response) if (hasHeaderShorthand) Object.assign(set2.headers, response.headers.toJSON()); else for (let [key, value] of response.headers.entries()) key in set2.headers && (set2.headers[key] = value); return set2.status === 200 && (set2.status = response.status), set2.headers["content-encoding"] && delete set2.headers["content-encoding"], set2; } if (!response) return { headers: {}, status: set2?.status ?? 200 }; if (hasHeaderShorthand) return set2 = { headers: response.headers.toJSON(), status: set2?.status ?? 200 }, set2.headers["content-encoding"] && delete set2.headers["content-encoding"], set2; set2 = { headers: {}, status: set2?.status ?? 200 }; for (let [key, value] of response.headers.entries()) key !== "content-encoding" && key in set2.headers && (set2.headers[key] = value); return set2; }, createStreamHandler = ({ mapResponse: mapResponse3, mapCompactResponse: mapCompactResponse3 }) => async (generator, set2, request) => { let init = generator.next(); if (init instanceof Promise && (init = await init), typeof init?.done > "u" || init?.done) return set2 ? mapResponse3(init.value, set2, request) : mapCompactResponse3(init.value, request); let contentType = ( // @ts-ignore init.value && typeof init.value?.stream ? "text/event-stream" : init.value && typeof init.value == "object" ? "application/json" : "text/plain" ); return set2?.headers ? (set2.headers["transfer-encoding"] || (set2.headers["transfer-encoding"] = "chunked"), set2.headers["content-type"] || (set2.headers["content-type"] = contentType), set2.headers["cache-control"] || (set2.headers["cache-control"] = "no-cache")) : set2 = { status: 200, headers: { "content-type": contentType, "transfer-encoding": "chunked", "cache-control": "no-cache", connection: "keep-alive" } }, new Response( new ReadableStream({ async start(controller) { let end = !1; if (request?.signal?.addEventListener("abort", () => { end = !0; try { controller.close(); } catch { } }), init.value !== void 0 && init.value !== null) if (init.value.toStream) controller.enqueue(init.value.toStream()); else if (typeof init.value == "object") try { controller.enqueue( Buffer.from(JSON.stringify(init.value)) ); } catch { controller.enqueue( Buffer.from(init.value.toString()) ); } else controller.enqueue( Buffer.from(init.value.toString()) ); for await (let chunk of generator) { if (end) break; if (chunk != null) { if (chunk.toStream) controller.enqueue(chunk.toStream()); else if (typeof chunk == "object") try { controller.enqueue( Buffer.from(JSON.stringify(chunk)) ); } catch { controller.enqueue( Buffer.from(chunk.toString()) ); } else controller.enqueue(Buffer.from(chunk.toString())); await new Promise( (resolve) => setTimeout(() => resolve(), 0) ); } } try { controller.close(); } catch { } } }), set2 ); }; async function* streamResponse(response) { let body = response.body; if (!body) return; let reader = body.getReader(), decoder = new TextDecoder(); try { for (; ; ) { let { done, value } = await reader.read(); if (done) break; yield decoder.decode(value); } } finally { reader.releaseLock(); } } var handleSet = (set2) => { if (typeof set2.status == "string" && (set2.status = StatusMap[set2.status]), set2.cookie && isNotEmpty(set2.cookie)) { let cookie = serializeCookie(set2.cookie); cookie && (set2.headers["set-cookie"] = cookie); } set2.headers["set-cookie"] && Array.isArray(set2.headers["set-cookie"]) && (set2.headers = parseSetCookies( new Headers(set2.headers), set2.headers["set-cookie"] )); }, createResponseHandler = (handler) => { let handleStream3 = createStreamHandler(handler); return (response, set2, request) => { let isCookieSet = !1; if (set2.headers instanceof Headers) for (let key of set2.headers.keys()) if (key === "set-cookie") { if (isCookieSet) continue; isCookieSet = !0; for (let cookie of set2.headers.getSetCookie()) response.headers.append("set-cookie", cookie); } else response.headers.append(key, set2.headers?.get(key) ?? ""); else for (let key in set2.headers) response.headers.append( key, set2.headers[key] ); let status2 = set2.status ?? 200; return response.status !== status2 && status2 !== 200 && (response.status <= 300 || response.status > 400) ? response.text().then((value) => { let newResponse = new Response(value, { headers: response.headers, status: set2.status }); return !newResponse.headers.has("content-length") && newResponse.headers.get( "transfer-encoding" ) === "chunked" ? handleStream3( streamResponse(newResponse), responseToSetHeaders(newResponse, set2), request ) : newResponse; }) : !response.headers.has("content-length") && response.headers.get("transfer-encoding") === "chunked" ? handleStream3( streamResponse(response), responseToSetHeaders(response, set2), request ) : response; }; }; // src/adapter/web-standard/handler.ts var handleElysiaFile = (file, set2 = { headers: {} }) => { let path = file.path, contentType = mime[path.slice(path.lastIndexOf(".") + 1)]; return contentType && (set2.headers["content-type"] = contentType), file.stats && set2.status !== 206 && set2.status !== 304 && set2.status !== 412 && set2.status !== 416 ? file.stats.then((stat2) => { let size = stat2.size; return size !== void 0 && (set2.headers["content-range"] = `bytes 0-${size - 1}/${size}`, set2.headers["content-length"] = size), handleFile(file.value, set2); }) : handleFile(file.value, set2); }, mapResponse = (response, set2, request) => { if (isNotEmpty(set2.headers) || set2.status !== 200 || set2.cookie) switch (handleSet(set2), response?.constructor?.name) { case "String": return set2.headers["content-type"] = "text/plain", new Response(response, set2); case "Array": case "Object": return set2.headers["content-type"] = "application/json", new Response(JSON.stringify(response), set2); case "ElysiaFile": return handleElysiaFile(response, set2); case "File": return handleFile(response, set2); case "Blob": return handleFile(response, set2); case "ElysiaCustomStatusResponse": return set2.status = response.code, mapResponse( response.response, set2, request ); case "ReadableStream": return set2.headers["content-type"]?.startsWith( "text/event-stream" ) || (set2.headers["content-type"] = "text/event-stream; charset=utf-8"), request?.signal?.addEventListener( "abort", { handleEvent() { request?.signal && !request?.signal?.aborted && response.cancel(); } }, { once: !0 } ), new Response(response, set2); case void 0: return response ? new Response(JSON.stringify(response), set2) : new Response("", set2); case "Response": return handleResponse(response, set2, request); case "Error": return errorToResponse(response, set2); case "Promise": return response.then( (x) => mapResponse(x, set2, request) ); case "Function": return mapResponse(response(), set2, request); case "Number": case "Boolean": return new Response( response.toString(), set2 ); case "Cookie": return response instanceof Cookie ? new Response(response.value, set2) : new Response(response?.toString(), set2); case "FormData": return new Response(response, set2); default: if (response instanceof Response) return handleResponse(response, set2, request); if (response instanceof Promise) return response.then((x) => mapResponse(x, set2)); if (response instanceof Error) return errorToResponse(response, set2); if (response instanceof ElysiaCustomStatusResponse) return set2.status = response.code, mapResponse( response.response, set2, request ); if (typeof response?.next == "function") return handleStream(response, set2, request); if (typeof response?.then == "function") return response.then((x) => mapResponse(x, set2)); if (typeof response?.toResponse == "function") return mapResponse(response.toResponse(), set2); if ("charCodeAt" in response) { let code = response.charCodeAt(0); if (code === 123 || code === 91) return set2.headers["Content-Type"] || (set2.headers["Content-Type"] = "application/json"), new Response( JSON.stringify(response), set2 ); } return new Response(response, set2); } return response instanceof Response && !response.headers.has("content-length") && response.headers.get("transfer-encoding") === "chunked" ? handleStream( streamResponse(response), responseToSetHeaders(response, set2), request ) : ( // @ts-expect-error typeof response?.next == "function" || response instanceof ReadableStream ? handleStream(response, set2, request) : mapCompactResponse(response, request) ); }, mapEarlyResponse = (response, set2, request) => { if (response != null) if (isNotEmpty(set2.headers) || set2.status !== 200 || set2.cookie) switch (handleSet(set2), response?.constructor?.name) { case "String": return set2.headers["content-type"] = "text/plain", new Response(response, set2); case "Array": case "Object": return set2.headers["content-type"] = "application/json", new Response(JSON.stringify(response), set2); case "ElysiaFile": return handleElysiaFile(response, set2); case "File": return handleFile(response, set2); case "Blob": return handleFile(response, set2); case "ElysiaCustomStatusResponse": return set2.status = response.code, mapEarlyResponse( response.response, set2, request ); case "ReadableStream": return set2.headers["content-type"]?.startsWith( "text/event-stream" ) || (set2.headers["content-type"] = "text/event-stream; charset=utf-8"), request?.signal?.addEventListener( "abort", { handleEvent() { request?.signal && !request?.signal?.aborted && response.cancel(); } }, { once: !0 } ), new Response(response, set2); case void 0: return response ? new Response(JSON.stringify(response), set2) : void 0; case "Response": return handleResponse(response, set2, request); case "Promise": return response.then( (x) => mapEarlyResponse(x, set2) ); case "Error": return errorToResponse(response, set2); case "Function": return mapEarlyResponse(response(), set2); case "Number": case "Boolean": return new Response( response.toString(), set2 ); case "FormData": return new Response(response); case "Cookie": return response instanceof Cookie ? new Response(response.value, set2) : new Response(response?.toString(), set2); default: if (response instanceof Response) return handleResponse(response, set2, request); if (response instanceof Promise) return response.then((x) => mapEarlyResponse(x, set2)); if (response instanceof Error) return errorToResponse(response, set2); if (response instanceof ElysiaCustomStatusResponse) return set2.status = response.code, mapEarlyResponse( response.response, set2, request ); if (typeof response?.next == "function") return handleStream(response, set2, request); if (typeof response?.then == "function") return response.then((x) => mapEarlyResponse(x, set2)); if (typeof response?.toResponse == "function") return mapEarlyResponse(response.toResponse(), set2); if ("charCodeAt" in response) { let code = response.charCodeAt(0); if (code === 123 || code === 91) return set2.headers["Content-Type"] || (set2.headers["Content-Type"] = "application/json"), new Response( JSON.stringify(response), set2 ); } return new Response(response, set2); } else switch (response?.constructor?.name) { case "String": return set2.headers["content-type"] = "text/plain", new Response(response); case "Array": case "Object": return set2.headers["content-type"] = "application/json", new Response(JSON.stringify(response), set2); case "ElysiaFile": return handleElysiaFile(response, set2); case "File": return handleFile(response, set2); case "Blob": return handleFile(response, set2); case "ElysiaCustomStatusResponse": return set2.status = response.code, mapEarlyResponse( response.response, set2, request ); case "ReadableStream": return request?.signal?.addEventListener( "abort", { handleEvent() { request?.signal && !request?.signal?.aborted && response.cancel(); } }, { once: !0 } ), new Response(response, { headers: { "Content-Type": "text/event-stream; charset=utf-8" } }); case void 0: return response ? new Response(JSON.stringify(response), { headers: { "content-type": "application/json" } }) : new Response(""); case "Response": return !response.headers.has("content-length") && response.headers.get("transfer-encoding") === "chunked" ? handleStream( streamResponse(response), responseToSetHeaders(response), request ) : response; case "Promise": return response.then((x) => { let r = mapEarlyResponse(x, set2); if (r !== void 0) return r; }); case "Error": return errorToResponse(response, set2); case "Function": return mapCompactResponse(response(), request); case "Number": case "Boolean": return new Response(response.toString()); case "Cookie": return response instanceof Cookie ? new Response(response.value, set2) : new Response(response?.toString(), set2); case "FormData": return new Response(response); default: if (response instanceof Response) return response; if (response instanceof Promise) return response.then((x) => mapEarlyResponse(x, set2)); if (response instanceof Error) return errorToResponse(response, set2); if (response instanceof ElysiaCustomStatusResponse) return set2.status = response.code, mapEarlyResponse( response.response, set2, request ); if (typeof response?.next == "function") return handleStream(response, set2, request); if (typeof response?.then == "function") return response.then((x) => mapEarlyResponse(x, set2)); if (typeof response?.toResponse == "function") return mapEarlyResponse(response.toResponse(), set2); if ("charCodeAt" in response) { let code = response.charCodeAt(0); if (code === 123 || code === 91) return set2.headers["Content-Type"] || (set2.headers["Content-Type"] = "application/json"), new Response( JSON.stringify(response), set2 ); } return new Response(response); } }, mapCompactResponse = (response, request) => { switch (response?.constructor?.name) { case "String": return new Response(response, { headers: { "Content-Type": "text/plain" } }); case "Object": case "Array": return new Response(JSON.stringify(response), { headers: { "Content-Type": "application/json" } }); case "ElysiaFile": return handleElysiaFile(response); case "File": return handleFile(response); case "Blob": return handleFile(response); case "ElysiaCustomStatusResponse": return mapResponse( response.response, { status: response.code, headers: {} } ); case "ReadableStream": return request?.signal?.addEventListener( "abort", { handleEvent() { request?.signal && !request?.signal?.aborted && response.cancel(); } }, { once: !0 } ), new Response(response, { headers: { "Content-Type": "text/event-stream; charset=utf-8" } }); case void 0: return response ? new Response(JSON.stringify(response), { headers: { "content-type": "application/json" } }) : new Response(""); case "Response": return response.headers.get("transfer-encoding") === "chunked" ? handleStream( streamResponse(response), responseToSetHeaders(response), request ) : response; case "Error": return errorToResponse(response); case "Promise": return response.then( (x) => mapCompactResponse(x, request) ); // ? Maybe response or Blob case "Function": return mapCompactResponse(response(), request); case "Number": case "Boolean": return new Response(response.toString()); case "FormData": return new Response(response); default: if (response instanceof Response) return response; if (response instanceof Promise) return response.then( (x) => mapCompactResponse(x, request) ); if (response instanceof Error) return errorToResponse(response); if (response instanceof ElysiaCustomStatusResponse) return mapResponse( response.response, { status: response.code, headers: {} } ); if (typeof response?.next == "function") return handleStream(response, void 0, request); if (typeof response?.then == "function") return response.then((x) => mapResponse(x, set)); if (typeof response?.toResponse == "function") return mapCompactResponse(response.toResponse()); if ("charCodeAt" in response) { let code = response.charCodeAt(0); if (code === 123 || code === 91) return new Response(JSON.stringify(response), { headers: { "Content-Type": "application/json" } }); } return new Response(response); } }, errorToResponse = (error, set2) => new Response( JSON.stringify({ name: error?.name, message: error?.message, cause: error?.cause }), { status: set2?.status !== 200 ? set2?.status ?? 500 : 500, headers: set2?.headers } ), createStaticHandler = (handle, hooks, setHeaders = {}) => { if (typeof handle == "function") return; let response = mapResponse(handle, { headers: setHeaders }); if (!hooks.parse?.length && !hooks.transform?.length && !hooks.beforeHandle?.length && !hooks.afterHandle?.length) return response.clone.bind(response); }, handleResponse = createResponseHandler({ mapResponse, mapCompactResponse }), handleStream = createStreamHandler({ mapResponse, mapCompactResponse }); // src/adapter/web-standard/index.ts var WebStandardAdapter = { name: "web-standard", isWebStandard: !0, handler: { mapResponse, mapEarlyResponse, mapCompactResponse, createStaticHandler }, composeHandler: { mapResponseContext: "c.request", preferWebstandardHeaders: !0, // @ts-ignore Bun specific headers: `c.headers={} for(const [k,v] of c.request.headers.entries())c.headers[k]=v `, parser: { json(isOptional2) { return isOptional2 ? `try{c.body=await c.request.json()}catch{} ` : `c.body=await c.request.json() `; }, text() { return `c.body=await c.request.text() `; }, urlencoded() { return `c.body=parseQuery(await c.request.text()) `; }, arrayBuffer() { return `c.body=await c.request.arrayBuffer() `; }, formData(isOptional2) { let fnLiteral = ` c.body={} `; return isOptional2 ? fnLiteral += "let form;try{form=await c.request.formData()}catch{}" : fnLiteral += `const form=await c.request.formData() `, fnLiteral + `for(const key of form.keys()){if(c.body[key]) continue const value=form.getAll(key) if(value.length===1)c.body[key]=value[0] else c.body[key]=value}`; } } }, async stop(app, closeActiveConnections) { if (!app.server) throw new Error( "Elysia isn't running. Call `app.listen` to start the server." ); if (app.server && (app.server.stop(closeActiveConnections), app.server = null, app.event.stop?.length)) for (let i = 0; i < app.event.stop.length; i++) app.event.stop[i].fn(app); }, composeGeneralHandler: { parameters: "r", createContext(app) { let decoratorsLiteral = "", fnLiteral = "", defaultHeaders = app.setHeaders; for (let key of Object.keys(app.decorator)) decoratorsLiteral += `,'${key}':decorator['${key}']`; let standardHostname = app.config.handler?.standardHostname ?? !0, hasTrace = !!app.event.trace?.length; return fnLiteral += `const u=r.url,s=u.indexOf('/',${standardHostname ? 11 : 7}),qi=u.indexOf('?',s+1) let p if(qi===-1)p=u.substring(s) else p=u.substring(s, qi) `, hasTrace && (fnLiteral += `const id=randomId() `), fnLiteral += "const c={request:r,store,qi,path:p,url:u,redirect,error:status,status,set:{headers:", fnLiteral += Object.keys(defaultHeaders ?? {}).length ? "Object.assign({},app.setHeaders)" : "Object.create(null)", fnLiteral += ",status:200}", app.inference.server && (fnLiteral += ",get server(){return app.getServer()}"), hasTrace && (fnLiteral += ",[ELYSIA_REQUEST_ID]:id"), fnLiteral += decoratorsLiteral, fnLiteral += `} `, fnLiteral; }, error404(hasEventHook, hasErrorHook) { let findDynamicRoute = "if(route===null)return "; return hasErrorHook ? findDynamicRoute += `app.handleError(c,notFound,false,${this.parameters})` : findDynamicRoute += hasEventHook ? "new Response(error404Message,{status:c.set.status===200?404:c.set.status,headers:c.set.headers})" : "error404.clone()", { declare: hasErrorHook ? "" : `const error404Message=notFound.message.toString() const error404=new Response(error404Message,{status:404}) `, code: findDynamicRoute }; } }, composeError: { mapResponseContext: "", validationError: "return new Response(error.message,{headers:Object.assign({'content-type':'application/json'},set.headers),status:set.status})", unknownError: "return new Response(error.message,{headers:set.headers,status:error.status??set.status??500})" }, listen() { return () => { throw new Error( "WebStandard does not support listen, you might want to export default Elysia.fetch instead" ); }; } }; // src/sucrose.ts var separateFunction = (code) => { code.startsWith("async") && (code = code.slice(5)), code = code.trimStart(); let index = -1; if (code.charCodeAt(0) === 40 && (index = code.indexOf("=>", code.indexOf(")")), index !== -1)) { let bracketEndIndex = index; for (; bracketEndIndex > 0 && code.charCodeAt(--bracketEndIndex) !== 41; ) ; let body = code.slice(index + 2); return body.charCodeAt(0) === 32 && (body = body.trimStart()), [ code.slice(1, bracketEndIndex), body, { isArrowReturn: body.charCodeAt(0) !== 123 } ]; } if (/^(\w+)=>/g.test(code) && (index = code.indexOf("=>"), index !== -1)) { let body = code.slice(index + 2); return body.charCodeAt(0) === 32 && (body = body.trimStart()), [ code.slice(0, index), body, { isArrowReturn: body.charCodeAt(0) !== 123 } ]; } if (code.startsWith("function")) { index = code.indexOf("("); let end = code.indexOf(")"); return [ code.slice(index + 1, end), code.slice(end + 2), { isArrowReturn: !1 } ]; } let start = code.indexOf("("); if (start !== -1) { let sep = code.indexOf(` `, 2), parameter = code.slice(0, sep), end = parameter.lastIndexOf(")") + 1, body = code.slice(sep + 1); return [ parameter.slice(start, end), "{" + body, { isArrowReturn: !1 } ]; } let x = code.split(` `, 2); return [x[0], x[1], { isArrowReturn: !1 }]; }, bracketPairRange = (parameter) => { let start = parameter.indexOf("{"); if (start === -1) return [-1, 0]; let end = start + 1, deep = 1; for (; end < parameter.length; end++) { let char = parameter.charCodeAt(end); if (char === 123 ? deep++ : char === 125 && deep--, deep === 0) break; } return deep !== 0 ? [0, parameter.length] : [start, end + 1]; }, bracketPairRangeReverse = (parameter) => { let end = parameter.lastIndexOf("}"); if (end === -1) return [-1, 0]; let start = end - 1, deep = 1; for (; start >= 0; start--) { let char = parameter.charCodeAt(start); if (char === 125 ? deep++ : char === 123 && deep--, deep === 0) break; } return deep !== 0 ? [-1, 0] : [start, end + 1]; }, removeColonAlias = (parameter) => { for (; ; ) { let start = parameter.indexOf(":"); if (start === -1) break; let end = parameter.indexOf(",", start); end === -1 && (end = parameter.indexOf("}", start) - 1), end === -2 && (end = parameter.length), parameter = parameter.slice(0, start) + parameter.slice(end); } return parameter; }, retrieveRootParamters = (parameter) => { let hasParenthesis = !1; parameter.charCodeAt(0) === 40 && (parameter = parameter.slice(1, -1)), parameter.charCodeAt(0) === 123 && (hasParenthesis = !0, parameter = parameter.slice(1, -1)), parameter = parameter.replace(/( |\t|\n)/g, "").trim(); let parameters = []; for (; ; ) { let [start, end] = bracketPairRange(parameter); if (start === -1) break; parameters.push(parameter.slice(0, start - 1)), parameter.charCodeAt(end) === 44 && end++, parameter = parameter.slice(end); } parameter = removeColonAlias(parameter), parameter && (parameters = parameters.concat(parameter.split(","))); let parameterMap = /* @__PURE__ */ Object.create(null); for (let p of parameters) { if (p.indexOf(",") === -1) { parameterMap[p] = !0; continue; } for (let q of p.split(",")) parameterMap[q.trim()] = !0; } return { hasParenthesis, parameters: parameterMap }; }, findParameterReference = (parameter, inference) => { let { parameters, hasParenthesis } = retrieveRootParamters(parameter); return parameters.query && (inference.query = !0), parameters.headers && (inference.headers = !0), parameters.body && (inference.body = !0), parameters.cookie && (inference.cookie = !0), parameters.set && (inference.set = !0), parameters.server && (inference.server = !0), parameters.route && (inference.route = !0), parameters.url && (inference.url = !0), parameters.path && (inference.path = !0), hasParenthesis ? `{ ${Object.keys(parameters).join(", ")} }` : Object.keys(parameters).join(", "); }, findEndIndex = (type, content, index) => { let regex2 = new RegExp( `${type.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}[\\n\\t,; ]` ); index !== void 0 && (regex2.lastIndex = index); let match = regex2.exec(content); return match ? match.index : -1; }; var findAlias = (type, body, depth = 0) => { if (depth > 5) return []; let aliases = [], content = body; for (; ; ) { let index = findEndIndex(" = " + type, content); if (index === -1 && (index = findEndIndex("=" + type, content)), index === -1) { let lastIndex = content.indexOf(" = " + type); if (lastIndex === -1 && (lastIndex = content.indexOf("=" + type)), lastIndex + 3 + type.length !== content.length) break; index = lastIndex; } let part = content.slice(0, index), lastPart = part.lastIndexOf(" "), variable = part.slice(lastPart !== -1 ? lastPart + 1 : -1); if (variable === "}") { let [start, end] = bracketPairRangeReverse(part); aliases.push(removeColonAlias(content.slice(start, end))), content = content.slice(index + 3 + type.length); continue; } for (; variable.charCodeAt(0) === 44; ) variable = variable.slice(1); for (; variable.charCodeAt(0) === 9; ) variable = variable.slice(1); variable.includes("(") || aliases.push(variable), content = content.slice(index + 3 + type.length); } for (let alias of aliases) { if (alias.charCodeAt(0) === 123) continue; let deepAlias = findAlias(alias, body); deepAlias.length > 0 && aliases.push(...deepAlias); } return aliases; }, extractMainParameter = (parameter) => { if (!parameter) return; if (parameter.charCodeAt(0) !== 123) return parameter; if (parameter = parameter.slice(2, -2), !parameter.includes(",")) return parameter.indexOf("...") !== -1 ? parameter.slice(parameter.indexOf("...") + 3) : void 0; let spreadIndex = parameter.indexOf("..."); if (spreadIndex !== -1) return parameter.slice(spreadIndex + 3).trimEnd(); }, inferBodyReference = (code, aliases, inference) => { let access = (type, a