elysia
Version:
Ergonomic Framework for Human
1,418 lines (1,407 loc) • 142 kB
JavaScript
"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