elysia
Version:
Ergonomic Framework for Human
3,678 lines • 139 kB
JavaScript
// src/cookies.ts
import { parse, serialize } from "cookie";
import decode from "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
import { Value } from "@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() : 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) : [...Value.Errors(validator, value)].map(mapValueError), expected;
try {
expected = 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
[...Value.Errors(this.validator, this.value)].map(mapValueError)
);
}
static simplifyModel(validator) {
let model = "schema" in validator ? validator.schema : validator;
try {
return 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(
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, alias) => new RegExp(
`${alias}\\.(${type})|${alias}\\["${type}"\\]|${alias}\\['${type}'\\]`
).test(code);
for (let alias of aliases)
if (alias) {
if (alias.charCodeAt(0) === 123) {
let parameters = retrieveRootParamters(alias).parameters;
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.url && (inference.url = !0), parameters.route && (inference.route = !0), parameters.path && (inference.path = !0);
continue;
}
if (!inference.query && (access("query", alias) || code.includes("return " + alias) || code.includes("return " + alias + ".query")) && (inference.query = !0), !inference.headers && access("headers", alias) && (inference.headers = !0), !inference.body && access("body", alias) && (inference.body = !0), !inference.cookie && access("cookie", alias) && (inference.cookie = !0), !inference.set && access("set", alias) && (inference.set = !0), !inference.server && access("server", alias) && (inference.server = !0), !inference.route && access("route", alias) && (inference.route = !0), !inference.url && access("url", alias) && (inference.url = !0), !inference.path && access("path", alias) && (inference.path = !0), inference.query && inference.headers && inference.body && inference.cookie && inference.set && inference.server && inference.route && inference.url && inference.path)
break;
}
return aliases;
};
var isContextPassToFunction = (context, body, inference) => {
try {
let captureFunction = new RegExp(`\\w\\((.*?)?${context}`, "gs");
captureFunction.test(body);
let nextChar = body.charCodeAt(captureFunction.lastIndex);
return nextChar === 41 || nextChar === 44 ? (inference.query = !0, inference.headers = !0, inference.body = !0, inference.cookie = !0, inference.set = !0, inference.server = !0, inference.url = !0, inference.route = !0, inference.path = !0, !0) : !1;
} catch {
return console.log(
"[Sucrose] warning: unexpected isContextPassToFunction error, you may continue development as usual but please report the following to maintainers:"
), console.log("--- body ---"), console.log(body), console.log("--- context ---"), console.log(context), !0;
}
};
var caches = {};
var mergeInference = (a, b) => ({
body: a.body || b.body,
cookie: a.cookie || b.cookie,
headers: a.headers || b.headers,
query: a.query || b.query,
set: a.set || b.set,
server: a.server || b.server,
url: a.url || b.url,
route: a.route || b.route,
path: a.path || b.path
}), sucrose = (lifeCycle, inference = {
query: !1,
headers: !1,
body: !1,
cookie: !1,
set: !1,
server: !1,
url: !1,
route: !1,
path: !1
}) => {
let events = [];
lifeCycle.request?.length && events.push(...lifeCycle.request), lifeCycle.beforeHandle?.length && events.push(...lifeCycle.beforeHandle), lifeCycle.parse?.length && events.push(...lifeCycle.parse), lifeCycle.error?.length && events.push(...lifeCycle.error), lifeCycle.transform?.length && events.push(...lifeCycle.transform), lifeCycle.afterHandle?.length && events.push(...lifeCycle.afterHandle), lifeCycle.mapResponse?.length && events.push(...lifeCycle.mapResponse), lifeCycle.afterResponse?.length && events.push(...lifeCycle.afterResponse), lifeCycle.handler && typeof lifeCycle.handler == "function" && events.push(lifeCycle.handler);
for (let i = 0; i < events.length; i++) {
let e = events[i];
if (!e) continue;
let event = typeof e == "object" ? e.fn : e;
if (typeof event != "function") continue;
let content = event.toString(), key = checksum(content), cachedInference = caches[key];
if (cachedInference) {
inference = mergeInference(inference, cachedInference);
continue;
}
let fnInference = {
query: !1,
headers: !1,
body: !1,
cookie: !1,
set: !1,
server: !1,
url: !1,
route: !1,
path: !1
}, [parameter, body] = separateFunction(content), rootParameters = findParameterReference(parameter, fnInference), mainParameter = extractMainParameter(rootParameters);
if (mainParameter) {
let aliases = findAlias(mainParameter, body.slice(1, -1));
aliases.splice(0, -1, mainParameter);
let code = body;
code.charCodeAt(0) === 123 && code.charCodeAt(body.length - 1) === 125 && (code = code.slice(1, -1)), isContextPassToFunction(mainParameter, code, fnInference) || inferBodyReference(code, aliases, fnInference), !fnInference.query && code.includes("return " + mainParameter + ".query") && (fnInference.query = !0);
}
if (caches[key] || (caches[key] = fnInference), inference = mergeInference(inference, fnInference), inference.query && inference.headers && inference.body && inference.cookie && inference.set && inference.server && inference.url && inference.route && inference.path)
break;
}
return inference;
};
// src/compose.ts
import { Value as Value4 } from "@sinclair/typebox/value";
import {
Kind as Kind4,
OptionalKind as OptionalKind2,
TypeBoxError
} from "@sinclair/typebox";
import decode3 from "fast-decode-uri-component";
// src/parse-query.ts
import decode2 from "fast-decode-uri-component";
// src/trace.ts
var ELYSIA_TRACE = Symbol("ElysiaTrace");
// src/schema.ts
import {
Kind as Kind3,
OptionalKind,
TransformKind
} from "@sinclair/typebox";
import { Value as Value3 } from "@sinclair/typebox/value";
import { TypeCompiler as TypeCompiler3 } from "@sinclair/typebox/compiler";
import {
createMirror
} from "exact-mirror";
// src/type-system/index.ts
import { Type, Kind as Kind2 } from "@sinclair/typebox";
// src/type-system/format.ts
import { FormatRegistry } from "@sinclair/typebox";
var fullFormats = {
// date: http://tools.ietf.org/html/rfc3339#section-5.6
date,
// date-time: http://tools.ietf.org/html/rfc3339#section-5.6
time: getTime(!0),
"date-time": getDateTime(!0),
"iso-time": getTime(!1),
"iso-date-time": getDateTime(!1),
// duration: https://tools.ietf.org/html/rfc3339#appendix-A
duration: /^P(?!$)((\d+Y)?(\d+M)?(\d+D)?(T(?=\d)(\d+H)?(\d+M)?(\d+S)?)?|(\d+W)?)$/,
uri,
"uri-reference": /^(?:[a-z][a-z0-9+\-.]*:)?(?:\/?\/(?:(?:[a-z0-9\-._~!$&'()*+,;=:]|%[0-9a-f]{2})*@)?(?:\[(?:(?:(?:(?:[0-9a-f]{1,4}:){6}|::(?:[0-9a-f]{1,4}:){5}|(?:[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){4}|(?:(?:[0-9a-f]{1,4}:){0,1}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){3}|(?:(?:[0-9a-f]{1,4}:){0,2}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){2}|(?:(?:[0-9a-f]{1,4}:){0,3}[0-9a-f]{1,4})?::[0-9a-f]{1,4}:|(?:(?:[0-9a-f]{1,4}:){0,4}[0-9a-f]{1,4})?::)(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?))|(?:(?:[0-9a-f]{1,4}:){0,5}[0-9a-f]{1,4})?::[0-9a-f]{1,4}|(?:(?:[0-9a-f]{1,4}:){0,6}[0-9a-f]{1,4})?::)|[Vv][0-9a-f]+\.[a-z0-9\-._~!$&'()*+,;=:]+)\]|(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)|(?:[a-z0-9\-._~!$&'"()*+,;=]|%[0-9a-f]{2})*)(?::\d*)?(?:\/(?:[a-z0-9\-._~!$&'"()*+,;=:@]|%[0-9a-f]{2})*)*|\/(?:(?:[a-z0-9\-._~!$&'"()*+,;=:@]|%[0-9a-f]{2})+(?:\/(?:[a-z0-9\-._~!$&'"()*+,;=:@]|%[0-9a-f]{2})*)*)?|(?:[a-z0-9\-._~!$&'"()*+,;=:@]|%[0-9a-f]{2})+(?:\/(?:[a-z0-9\-._~!$&'"()*+,;=:@]|%[0-9a-f]{2})*)*)?(?:\?(?:[a-z0-9\-._~!$&'"()*+,;=:@/?]|%[0-9a-f]{2})*)?(?:#(?:[a-z0-9\-._~!$&'"()*+,;=:@/?]|%[0-9a-f]{2})*)?$/i,
// uri-template: https://tools.ietf.org/html/rfc6570
"uri-template": /^(?:(?:[^\x00-\x20"'<>%\\^`{|}]|%[0-9a-f]{2})|\{[+#./;?&=,!@|]?(?:[a-z0-9_]|%[0-9a-f]{2})+(?::[1-9][0-9]{0,3}|\*)?(?:,(?:[a-z0-9_]|%[0-9a-f]{2})+(?::[1-9][0-9]{0,3}|\*)?)*\})*$/i,
// For the source: https://gist.github.com/dperini/729294
// For test cases: https://mathiasbynens.be/demo/url-regex
url: /^(?:https?|ftp):\/\/(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z0-9\u{00a1}-\u{ffff}]+-)*[a-z0-9\u{00a1}-\u{ffff}]+)(?:\.(?:[a-z0-9\u{00a1}-\u{ffff}]+-)*[a-z0-9\u{00a1}-\u{ffff}]+)*(?:\.(?:[a-z\u{00a1}-\u{ffff}]{2,})))(?::\d{2,5})?(?:\/[^\s]*)?$/iu,
email: /^[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/i,
hostname: /^(?=.{1,253}\.?$)[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9](?:[-0-9a-z]{0,61}[0-9a-z])?)*\.?$/i,
// optimized https://www.safaribooksonline.com/library/view/regular-expressions-cookbook/9780596802837/ch07s16.html
ipv4: /^(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)$/,
ipv6: /^((([0-9a-f]{1,4}:){7}([0-9a-f]{1,4}|:))|(([0-9a-f]{1,4}:){6}(:[0-9a-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9a-f]{1,4}:){5}(((:[0-9a-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9a-f]{1,4}:){4}(((:[0-9a-f]{1,4}){1,3})|((:[0-9a-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9a-f]{1,4}:){3}(((:[0-9a-f]{1,4}){1,4})|((:[0-9a-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9a-f]{1,4}:){2}(((:[0-9a-f]{1,4}){1,5})|((:[0-9a-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9a-f]{1,4}:){1}(((:[0-9a-f]{1,4}){1,6})|((:[0-9a-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9a-f]{1,4}){1,7})|((:[0-9a-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))$/i,
regex,
// uuid: http://tools.ietf.org/html/rfc4122
uuid: /^(?:urn:uuid:)?[0-9a-f]{8}-(?:[0-9a-f]{4}-){3}[0-9a-f]{12}$/i,
// JSON-pointer: https://tools.ietf.org/html/rfc6901
// uri fragment: https://tools.ietf.org/html/rfc3986#appendix-A
"json-pointer": /^(?:\/(?:[^~/]|~0|~1)*)*$/,
"json-pointer-uri-fragment": /^#(?:\/(?:[a-z0-9_\-.!$&'()*+,;:=@]|%[0-9a-f]{2}|~0|~1)*)*$/i,
// relative JSON-pointer: http://tools.ietf.org/html/draft-luff-relative-json-pointer-00
"relative-json-pointer": /^(?:0|[1-9][0-9]*)(?:#|(?:\/(?:[^~/]|~0|~1)*)*)$/,
// the following formats are used by the openapi specification: https://spec.openapis.org/oas/v3.0.0#data-types
// byte: https://github.com/miguelmota/is-base64
byte,
// signed 32 bit integer
int32: { type: "number", validate: validateInt32 },
// signed 64 bit integer
int64: { type: "number", validate: validateInt64 },
// C-type float
float: { type: "number", validate: validateNumber },
// C-type double
double: { type: "number", validate: validateNumber },
// hint to the UI to hide input strings
password: !0,
// unchecked string payload
binary: !0
};
function isLeapYear(year) {
return year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0);
}
var DATE = /^(\d\d\d\d)-(\d\d)-(\d\d)$/, DAYS = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
function date(str) {
let matches = DATE.exec(str);
if (!matches) return !1;
let year = +matches[1], month = +matches[2], day = +matches[3];
return month >= 1 && month <= 12 && day >= 1 && day <= (month === 2 && isLeapYear(year) ? 29 : DAYS[month]);
}
var TIME = /^(\d\d):(\d\d):(\d\d(?:\.\d+)?)(z|([+-])(\d\d)(?::?(\d\d))?)?$/i;
function getTime(strictTimeZone) {
return function(str) {
let matches = TIME.exec(str);
if (!matches) return !1;
let hr = +matches[1], min = +matches[2], sec = +matches[3], tz = matches[4], tzSign = matches[5] === "-" ? -1 : 1, tzH = +(matches[6] || 0), tzM = +(matches[7] || 0);
if (tzH > 23 || tzM > 59 || strictTimeZone && !tz) return !1;
if (hr <= 23 && min <= 59 && sec < 60) return !0;
let utcMin = min - tzM * tzSign, utcHr = hr - tzH * tzSign - (utcMin < 0 ? 1 : 0);
return (utcHr === 23 || utcHr === -1) && (utcMin === 59 || utcMin === -1) && sec < 61;
};
}
var parseDateTimeEmptySpace = (str) => str.charCodeAt(str.length - 6) === 32 ? str.slice(0, -6) + "+" + str.slice(-5) : str, DATE_TIME_SEPARATOR = /t|\s/i;
function getDateTime(strictTimeZone) {
let time = getTime(strictTimeZone);
return function(str) {
let dateTime = str.split(DATE_TIME_SEPARATOR);
return dateTime.length === 2 && date(dateTime[0]) && time(dateTime[1]);
};
}
var NOT_URI_FRAGMENT = /\/|:/, URI = /^(?:[a-z][a-z0-9+\-.]*:)(?:\/?\/(?:(?:[a-z0-9\-._~!$&'()*+,;=:]|%[0-9a-f]{2})*@)?(?:\[(?:(?:(?:(?:[0-9a-f]{1,4}:){6}|::(?:[0-9a-f]{1,4}:){5}|(?:[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){4}|(?:(?:[0-9a-f]{1,4}:){0,1}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){3}|(?:(?:[0-9a-f]{1,4}:){0,2}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){2}|(?:(?:[0-9a-f]{1,4}:){0,3}[0-9a-f]{1,4})?::[0-9a-f]{1,4}:|(?:(?:[0-9a-f]{1,4}:){0,4}[0-9a-f]{1,4})?::)(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?))|(?:(?:[0-9a-f]{1,4}:){0,5}[0-9a-f]{1,4})?::[0-9a-f]{1,4}|(?:(?:[0-9a-f]{1,4}:){0,6}[0-9a-f]{1,4})?::)|[Vv][0-9a-f]+\.[a-z0-9\-._~!$&'()*+,;=:]+)\]|(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)|(?:[a-z0-9\-._~!$&'()*+,;=]|%[0-9a-f]{2})*)(?::\d*)?(?:\/(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*|\/(?:(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})+(?:\/(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*)?|(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})+(?:\/(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*)(?:\?(?:[a-z0-9\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?(?:#(?:[a-z0-9\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?$/i;
function uri(str) {
return NOT_URI_FRAGMENT.test(str) && URI.test(str);
}
var BYTE = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/gm;
function byte(str) {
return BYTE.lastIndex = 0, BYTE.test(str);
}
var MIN_INT32 = -(2 ** 31), MAX_INT32 = 2 ** 31 - 1;
function validateInt32(value) {
return Number.isInteger(value) && value <= MAX_INT32 && value >= MIN_INT32;
}
function validateInt64(value) {
return Number.isInteger(value);
}
function validateNumber() {
return !0;
}
var Z_ANCHOR = /[^\\]\\Z/;
function regex(str) {
if (Z_ANCHOR.test(str)) return !1;
try {
return new RegExp(str), !0;
} catch {
return !1;
}
}
var isISO8601 = /(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+([+-][0-2]\d:[0-5]\d|Z))|(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d([+-][0-2]\d:[0-5]\d|Z))|(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d([+-][0-2]\d:[0-5]\d|Z))/, isFormalDate = /(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)\s(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s\d{2}\s\d{4}\s\d{2}:\d{2}:\d{2}\sGMT(?:\+|-)\d{4}\s\([^)]+\)/, isShortenDate = /^(?:(?:(?:(?:0?[1-9]|[12][0-9]|3[01])[/\s-](?:0?[1-9]|1[0-2])[/\s-](?:19|20)\d{2})|(?:(?:19|20)\d{2}[/\s-](?:0?[1-9]|1[0-2])[/\s-](?:0?[1-9]|[12][0-9]|3[01]))))(?:\s(?:1[012]|0?[1-9]):[0-5][0-9](?::[0-5][0-9])?(?:\s[AP]M)?)?$/, _validateDate = fullFormats.date, _validateDateTime = fullFormats["date-time"];
FormatRegistry.Has("date") || FormatRegistry.Set("date", (value) => {
let temp = parseDateTimeEmptySpace(value).replace(/"/g, "");
if (isISO8601.test(temp) || isFormalDate.test(temp) || isShortenDate.test(temp) || _validateDate(temp)) {
let date2 = new Date(temp);
if (!Number.isNaN(date2.getTime())) return !0;
}
return !1;
});
FormatRegistry.Has("date-time") || FormatRegistry.Set("date-time", (value) => {
let temp = value.replace(/"/g, "");
if (isISO8601.test(temp) || isFormalDate.test(temp) || isShortenDate.test(temp) || _validateDateTime(temp)) {
let date2 = new Date(temp);
if (!Number.isNaN(date2.getTime())) return !0;
}
return !1;
});
Object.entries(fullFormats).forEach((formatEntry) => {
let [formatName, formatValue] = formatEntry;
FormatRegistry.Has(formatName) || (formatValue instanceof RegExp ? FormatRegistry.Set(formatName, (value) => formatValue.test(value)) : typeof formatValue == "function" && FormatRegistry.Set(formatName, formatValue));
});
FormatRegistry.Has("numeric") || FormatRegistry.Set("numeric", (value) => !!value && !isNaN(+value));
FormatRegistry.Has("integer") || FormatRegistry.Set(
"integer",
(value) => !!value && Number.isInteger(+value)
);
FormatRegistry.Has("boolean") || FormatRegistry.Set(
"boolean",
(value) => value === "true" || value === "false"
);
FormatRegistry.Has("ObjectString") || FormatRegistry.Set("ObjectString", (value) => {
let start = value.charCodeAt(0);
if ((start === 9 || start === 10 || start === 32) && (start = value.trimStart().charCodeAt(0)), start !== 123 && start !== 91) return !1;
try {
return JSON.parse(value), !0;
} catch {
return !1;
}
});
FormatRegistry.Has("ArrayString") || FormatRegistry.Set("ArrayString", (value) => {
let start = value.charCodeAt(0);
if ((start === 9 || start === 10 || start === 32) && (start = value.trimStart().charCodeAt(0)), start !== 123 && start !== 91) return !1;
try {
return JSON.parse(value), !0;
} catch {
return !1;
}
});
// src/type-system/utils.ts
import {
Kind,
TypeRegistry,
Unsafe
} from "@sinclair/typebox";
import { Value as Value2 } from "@sinclair/typebox/value";
import { TypeCompiler } from "@sinclair/typebox/compiler";
var tryParse = (v, schema) => {
try {
return JSON.parse(v);
} catch {
throw new ValidationError("property", schema, v);
}
};
function createType(kind, func) {
return TypeRegistry.Has(kind) || TypeRegistry.Set(kind, func), (options = {}) => Unsafe({ ...options, [Kind]: kind });
}
var compile = (schema) => {
try {
let compiler = TypeCompiler.Compile(schema);
return compiler.Create = () => Value2.Create(schema), compiler.Error = (v) => new ValidationError("property", schema, v, compiler.Errors(v)), compiler;
} catch {
return {
Check: (v) => Value2.Check(schema, v),
CheckThrow: (v) => {
if (!Value2.Check(schema, v))
throw new ValidationError(
"property",
schema,
v,
Value2.Errors(schema, v)
);
},
Decode: (v) => Value2.Decode(schema, v),
Create: () => Value2.Create(schema),
Error: (v) => new ValidationError(
"property",
schema,
v,
Value2.Errors(schema, v)
)
};
}
}, parseFileUnit = (size) => {
if (typeof size == "string")
switch (size.slice(-1)) {
case "k":
return +size.slice(0, size.length - 1) * 1024;
case "m":
return +size.slice(0, size.length - 1) * 1048576;
default:
return +size;
}
return size;
}, checkFileExtension = (type, extension) => type.startsWith(extension) ? !0 : extension.charCodeAt(extension.length - 1) === 42 && extension.charCodeAt(extension.length - 2) === 47 && type.startsWith(extension.slice(0, -1)), _fileTypeFromBlobWarn = !1, warnIfFileTypeIsNotInstalled = () => {
_fileTypeFromBlobWarn || (console.warn(
"[Elysia] Attempt to validate file type without 'file-type'. This may lead to security risks. We recommend installing 'file-type' to properly validate file extension."
), _fileTypeFromBlobWarn = !0);
}, loadFileType = async () => import("file-type").then((x) => (_fileTypeFromBlob = x.fileTypeFromBlob, _fileTypeFromBlob)).catch(warnIfFileTypeIsNotInstalled), _fileTypeFromBlob;
var validateFile = (options, value) => {
if (value instanceof ElysiaFile) return !0;
if (!(value instanceof Blob) || options.minSize && value.size < parseFileUnit(options.minSize) || options.maxSize && value.size > parseFileUnit(options.maxSize))
return !1;
if (options.extension) {
if (typeof options.extension == "string")
return checkFileExtension(value.type, options.extension);
for (let i = 0; i < options.extension.length; i++)
if (checkFileExtension(value.type, options.extension[i]))
return !0;
return !1;
}
return !0;
};
// src/type-system/index.ts
import {
TypeSystemPolicy,
TypeSystem,
TypeSystemDuplicateFormat,
TypeSystemDuplicateTypeKind
} from "@sinclair/typebox/system";
import { TypeRegistry as TypeRegistry2, FormatRegistry as FormatRegistry2 } from "@sinclair/typebox";
import { TypeCompiler as TypeCompiler2, TypeCheck as TypeCheck2 } from "@sinclair/typebox/compiler";
var t = Object.assign({}, Type);
createType(
"UnionEnum",
(schema, value) => (typeof value == "number" || typeof value == "string" || value === null) && schema.enum.includes(value)
);
var internalFiles = createType(
"Files",
(options, value) => {
if (!Array.isArray(value)) return validateFile(options, value);
if (options.minItems && value.length < options.minItems || options.maxItems && value.length > options.maxItems) return !1;
for (let i = 0; i < value.length; i++)
if (!validateFile(options, value[i])) return !1;
return !0;
}
), internalFormData = createType(
"ElysiaForm",
({ compiler, ...schema }, value) => {
if (!(value instanceof FormData)) return !1;
if (compiler) {
if (!(ELYSIA_FORM_DATA in value))
throw new ValidationError("property", schema, value);
if (!compiler.Check(value[ELYSIA_FORM_DATA]))
throw compiler.Error(value[ELYSIA_FORM_DATA]);
}
return !0;
}
), ElysiaType = {
// @ts-ignore
String: (property) => Type.String(property),
Numeric: (property) => {
let schema = Type.Number(property), compiler = compile(schema);
return t.Transform(
t.Union(
[
t.String({
format: "numeric",
default: 0
}),
t.Number(property)
],
property
)
).Decode((value) => {
let number = +value;
if (isNaN(number)) return value;
if (property && !compiler.Check(number))
throw compiler.Error(value);
return number;
}).Encode((value) => value);
},
Integer: (property) => {
let schema = Type.Integer(property), compiler = compile(schema);
return t.Transform(
t.Union(
[
t.String({
format: "integer",
default: 0
}),
Type.Integer(property)
],
property
)
).Decode((value) => {
let number = +value;
if (!compiler.Check(number)) throw compiler.Error(number);
return number;
}).Encode((value) => value);
},
Date: (property) => {
let schema = Type.Date(property), compiler = compile(schema), _default = property?.default ? new Date(property.default) : void 0;
return t.Transform(
t.Union(
[
Type.Date(property),
t.String({
format: "date-time",
default: _default?.toISOString()
}),
t.String({
format: "date",
default: _default?.toISOString()
}),
t.Number({ default: _default?.getTime() })
],
property
)
).Decode((value) => {
if (typeof value == "number") {
let date3 = new Date(value);
if (!compiler.Check(date3)) throw compiler.Error(date3);
return date3;
}
if (value instanceof Date) return value;
let date2 = new Date(parseDateTimeEmptySpace(value));
if (!date2 || isNaN(date2.getTime()))
throw new ValidationError("property", schema, date2);
if (!compiler.Check(date2)) throw compiler.Error(date2);
return date2;
}).Encode((value) => value.toISOString());
},
BooleanString: (property) => {
let schema = Type.Boolean(property), compiler = compile(schema);
return t.Transform(
t.Union(
[
t.Boolean(property),
t.String({
format: "boolean",
default: !1
})
],
property
)
).Decode((value) => {
if (typeof value == "string") return value === "true";
if (value !== void 0 && !compiler.Check(value))
throw compiler.Error(value);
return value;
}).Encode((value) => value);
},
ObjectString: (properties, options) => {
let schema = t.Object(properties, options), compiler = compile(schema), defaultValue = JSON.stringify(compiler.Create());
return t.Transform(
t.Union([
t.String({
format: "ObjectString",
default: defaultValue
}),
schema
])
).Decode((value) => {
if (typeof value == "string") {
if (value.charCodeAt(0) !== 123)
throw new ValidationError("property", schema, value);
if (!compiler.Check(value = tryParse(value, schema)))
throw compiler.Error(value);
return compiler.Decode(value);
}
return value;
}).Encode((value) => {
let original;
if (typeof value == "string" && (value = tryParse(original = value, schema)), !compiler.Check(value)) throw compiler.Error(value);
return original ?? JSON.stringify(value);
});
},
ArrayString: (children = t.String(), options) => {
let schema = t.Array(children, options), compiler = compile(schema), decode4 = (value, isProperty = !1) => {
if (value.charCodeAt(0) === 91) {
if (!compiler.Check(value = tryParse(value, schema)))
throw compiler.Error(value);
return compiler.Decode(value);
}
if (value.indexOf(",") !== -1) {
if (!compiler.Check(value)) throw compiler.Error(value);
return compiler.Decode(value);
}
if (isProperty) return value;
throw new ValidationError("property", schema, value);
};
return t.Transform(
t.Union([
t.String({
format: "ArrayString",
default: options?.default
}),
schema
])
).Decode((value) => {
if (Array.isArray(value)) {
let values = [];
for (let i = 0; i < value.length; i++) {
let v = value[i];
if (typeof v == "string") {
let t2 = decode4(v, !0);
Array.isArray(t2) ? values = values.concat(t2) : values.push(t2);
continue;
}
values.push(v);
}
return values;
}
return typeof value == "string" ? decode4(value) : value;
}).Encode((value) => {
let original;
if (typeof value == "string" && (value = tryParse(original = value, schema)), !compiler.Check(value))
throw new ValidationError("property", schema, value);
return original ?? JSON.stringify(value);
});
},
File: createType(
"File",
validateFile
),
Files: (options = {}) => t.Transform(internalFiles(options)).Decode((value) => Array.isArray(value) ? value : [value]).Encode((value) => value),
Nullable: (schema, options) => t.Union([schema, t.Null()], options),
/**
* Allow Optional, Nullable and Undefined
*/
MaybeEmpty: (schema, options) => t.Union([schema, t.Null(), t.Undefined()], options),
Cookie: (properties, {
domain,
expires,
httpOnly,
maxAge,
path,
priority,
sameSite,
secure,
secrets,
sign,
...options
} = {}) => {
let v = t.Object(properties, options);
return v.config = {
domain,
expires,
httpOnly,
maxAge,
path,
priority,
sameSite,
secure,
secrets,
sign
}, v;
},
UnionEnum: (values, options = {}) => {
let type = values.every((value) => typeof value == "string") ? { type: "string" } : values.every((value) => typeof value == "number") ? { type: "number" } : values.every((value) => value === null) ? { type: "null" } : {};
if (values.some((x) => typeof x == "object" && x !== null))
throw new Error("This type does not support objects or arrays");
return {
// default is need for generating error message
default: values[0],
...options,
[Kind2]: "UnionEnum",
...type,
enum: values
};
},
NoValidate: (v, enabled = !0) => (v.noValidate = enabled, v),
Form: (v, options = {}) => {
let schema = t.Object(v, {
default: form({}),
...options
}), compiler = compile(schema);
return t.Union([
schema,
// @ts-expect-error
internalFormData({
compiler
})
]);
}
};
t.BooleanString = ElysiaType.BooleanString;
t.ObjectString = ElysiaType.ObjectString;
t.ArrayString = ElysiaType.ArrayString;
t.Numeric = ElysiaType.Numeric;
t.Integer = ElysiaType.Integer;
t.File = (arg) => (arg?.type && loadFileType(), ElysiaType.File({
default: "File",
...arg,
extension: arg?.type,
type: "string",
format: "binary"
}));
t.Files = (arg) => (arg?.type && loadFileType(), ElysiaType.Files({
...arg,
elysiaMeta: "Files",
default: "Files",
extension: arg?.type,
type: "array",
items: {
...arg,
default: "Files",
type: "string",
format: "binary"
}
}));
t.Nullable = (schema) => ElysiaType.Nullable(schema);
t.MaybeEmpty = ElysiaType.MaybeEmpty;
t.Cookie = ElysiaType.Cookie;
t.Date = ElysiaType.Date;
t.UnionEnum = ElysiaType.UnionEnum;
t.NoValidate = ElysiaType.NoValidate;
t.Form = ElysiaType.Form;
// src/schema.ts
var isOptional = (schema) => schema ? schema?.[Kind3] === "Import" && schema.References ? schema.References().some(isOptional) : (schema.schema && (schema = schema.schema), !!schema && OptionalKind in schema) : !1, hasAdditionalProperties = (_schema) => {
if (!_schema) return !1;
let schema = _schema?.schema ?? _schema;
if (schema[Kind3] === "Import" && _schema.References)
return _schema.References().some(hasAdditionalProperties);
if (schema.anyOf) return schema.anyOf.some(hasAdditionalProperties);
if (schema.someOf) return schema.someOf.some(hasAdditionalProperties);
if (schema.allOf) return schema.allOf.some(hasAdditionalProperties);
if (schema.not) return schema.not.some(hasAdditionalProperties);
if (schema.type === "object") {
let properties = schema.properties;
if ("additionalProperties" in schema) return schema.additionalProperties;
if ("patternProperties" in schema) return !1;
for (let key of Object.keys(properties)) {
let property = properties[key];
if (property.type === "object") {
if (hasAdditionalProperties(property)) return !0;
} else if (property.anyOf) {
for (let i = 0; i < property.anyOf.length; i++)
if (hasAdditionalProperties(property.anyOf[i])) return !0;
}
return property.additionalProperties;
}
return !1;
}
return schema.type === "array" && schema.items && !Array.isArray(schema.items) ? hasAdditionalProperties(schema.items) : !1;
};
var hasProperty = (expectedProperty, _schema) => {
if (!_schema) return;
let schema = _schema.schema ?? _schema;
if (schema[Kind3] === "Import" && _schema.References)
return _schema.References().some((schema2) => hasProperty(expectedProperty, schema2));
if (schema.type === "object") {
let properties = schema.properties;
if (!properties) return !1;
for (let key of Object.keys(properties)) {
let property = properties[key];
if (expectedProperty in property) return !0;
if (property.type === "object") {
if (hasProperty(expectedProperty, property)) return !0;
} else if (property.anyOf) {
for (let i = 0; i < property.anyOf.length; i++)
if (hasProperty(expectedProperty, property.anyOf[i]))
return !0;
}
}
return !1;
}
return expectedProperty in schema;
}, hasRef = (schema) => {
if (!schema) return !1;
if (schema.oneOf) {
for (let i = 0; i < schema.oneOf.length; i++)
if (hasRef(schema.oneOf[i])) return !0;
}
if (schema.anyOf) {
for (let i = 0; i < schema.anyOf.length; i++)
if (hasRef(schema.anyOf[i])) return !0;
}
if (schema.oneOf) {
for (let i = 0; i < schema.oneOf.length; i++)
if (hasRef(schema.oneOf[i])) return !0;
}
if (schema.allOf) {
for (let i = 0; i < schema.allOf.length; i++)
if (hasRef(schema.allOf[i])) return !0;
}
if (schema.not && hasRef(schema.not)) return !0;
if (schema.type === "object" && schema.properties) {
let properties = schema.properties;
for (let key of Object.keys(properties)) {
let property = properties[key];
if (hasRef(property) || property.type === "array" && property.items && hasRef(property.items))
return !0;
}
}
return schema.type === "array" && schema.items && hasRef(schema.items) ? !0 : schema[Kind3] === "Ref" && "$ref" in schema;
}, hasTransform = (schema) => {
if (!schema) return !1;
if (schema.$ref && schema.$defs && schema.$ref in schema.$defs && hasTransform(schema.$defs[schema.$ref]))
return !0;
if (schema.oneOf) {
for (let i = 0; i < schema.oneOf.length; i++)
if (hasTransform(schema.oneOf[i])) return !0;
}
if (schema.anyOf) {
for (let i = 0; i < schema.anyOf.length; i++)
if (hasTransform(schema.anyOf[i])) return !0;
}
if (schema.allOf) {
for (let i = 0; i < schema.allOf.length; i++)
if (hasTransform(schema.allOf[i])) return !0;
}
if (schema.not && hasTransform(schema.not)) return !0;
if (schema.type === "object" && schema.properties) {
let properties = schema.properties;
for (let key of Object.keys(properties)) {
let property = properties[key];
if (hasTransform(property) || property.type === "array" && property.items && hasTransform(property.items))
return !0;
}
}
return schema.type === "array" && schema.items && hasTransform(schema.items) ? !0 : TransformKind in schema;
}, replaceSchemaType = (schema, options, _config = {}) => {
let config = _config;
if (config.root = !0, !Array.isArray(options))
return options.original = schema, _replaceSchemaType(schema, options, config);
for (let option of options)
option.original = schema, schema = _replaceSchemaType(schema, option, config);
return schema;
}, _replaceSchemaType = (schema, options, config) => {
if (!schema) return schema;
let root = config.root;
if (options.onlyFirstObject && schema.type === "object")
return options.to(schema) ?? schema;
if (options.untilObjectFound && !root && schema.type === "object")
return schema;
let fromSymbol = options.from[Kind3];
if (schema.oneOf) {
for (let i = 0; i < schema.oneOf.length; i++)
schema.oneOf[i] = _replaceSchemaType(
schema.oneOf[i],
options,
config
);
return schema;
}
if (schema.anyOf) {
for (let i = 0; i < schema.anyOf.length; i++)
schema.anyOf[i] = _replaceSchemaType(
schema.anyOf[i],
options,
config
);
return schema;
}
if (schema.allOf) {
for (let i = 0; i < schema.allOf.length; i++)
schema.allOf[i] = _replaceSchemaType(
schema.allOf[i],
options,
config
);
return schema;
}
if (schema.not) return _replaceSchemaType(schema.not, options, config);
let isRoot = root && !!options.excludeRoot;
if (schema[Kind3] === fromSymbol) {
let { anyOf, oneOf, allOf, not, properties: properties2, items, ...rest } = schema, to = options.to(rest);
if (!to) return schema;
let transform, composeProperties = (schema2) => {
let v = _composeProperties(schema2);
return v.$id && delete v.$id, v;
}, _composeProperties = (v) => {
if (properties2 && v.type === "object") {
let newProperties = {};
for (let [key, value2] of Object.entries(properties2))
newProperties[key] = _replaceSchemaType(
value2,
options,
{
...config,
root: !1
}
);
return {
...rest,
...v,
properties: newProperties
};
}
if (items && v.type === "array")
return {
...rest,
...v,
items: _replaceSchemaType(items, options, {
...config,
root: !1
})
};
let value = {
...rest,
...v
};
return delete value.required, properties2 && v.type === "string" && v.format === "ObjectString" && v.default === "{}" && (transform = t.ObjectString(properties2, rest), value.default = JSON.stringify(
Value3.Create(t.Object(properties2))
), value.properties = properties2), items && v.type === "string" && v.format === "ArrayString" && v.default === "[]" && (transform = t.ArrayString(items, rest), value.default = JSON.stringify(Value3.Create(t.Array(items))), value.items = items), value;
};
if (isRoot) {
if (properties2) {
let newProperties = {};
for (let [key, value] of Object.entries(properties2))
newProperties[key] = _replaceSchemaType(
value,
options,
{
...config,
root: !1
}
);
return {
...rest,
properties: newProperties
};
} else if (items?.map)
return {
...rest,
items: items.map(
(v) => _replaceSchemaType(v, options, {
...config,
root: !1
})
)
};
return rest;
}
if (to.anyOf)
for (let i = 0; i < to.anyOf.length; i++)
to.anyOf[i] = composeProperties(to.anyOf[i]);
else if (to.oneOf)
for (let i = 0; i < to.oneOf.length; i++)
to.oneOf[i] = composeProperties(to.oneOf[i]);
else if (to.allOf)
for (let i = 0; i < to.allOf.length; i++)
to.allOf[i] = composeProperties(to.allOf[i]);
else to.not && (to.not = composeProperties(to.not));
if (transform && (to[TransformKind] = transform[TransformKind]), to.anyOf || to.oneOf || to.allOf || to.not) return to;
if (properties2) {
let newProperties = {};
for (let [key, value] of Object.entries(properties2))
newProperties[key] = _replaceSchemaType(
value,
options,
{
...config,
root: !1
}
);
return {
...rest,
...to,
properties: newProperties
};
} else if (items?.map)
return {
...rest,
...to,
items: items.map(
(v) => _replaceSchemaType(v, options, {
...config,
root: !1
})
)
};
return {
...rest,
...to
};
}
let properties = schema?.properties;
if (properties && root && options.rootOnly !== !0)
for (let [key, value] of Object.entries(properties))
switch (value[Kind3]) {
case fromSymbol:
let { anyOf, oneOf, allOf, not, type, ...rest } = value, to = options.to(rest);
if (!to) return schema;
if (to.anyOf)
for (let i = 0; i < to.anyOf.length; i++)
to.anyOf[i] = { ...rest, ...to.anyOf[i] };
else if (to.oneOf)
for (let i = 0; i < to.oneOf.length; i++)
to.oneOf[i] = { ...rest, ...to.oneOf[i] };
else if (to.allOf)
for (let i = 0; i < to.allOf.length; i++)
to.allOf[i] = { ...rest, ...to.allOf[i] };
else to.not && (to.not = { ...rest, ...to.not });
properties[key] = {
...rest,
..._replaceSchemaType(rest, options, {
...config,
root: !1
})
};
break;
case "Object":
case "Union":
properties[key] = _replaceSchemaType(value, options, {
...config,
root: !1
});
break;
default:
if (Array.isArray(value.items))
for (let i = 0; i < value.items.length; i++)
value.items[i] = _replaceSchemaType(
value.items[i],
options,
{
...config,
root: !1
}
);
else value.anyOf || value.oneOf || value.allOf || value.not ? properties[key] = _replaceSchemaType(value, options, {
...config,
root: !1
}) : value.type === "array" && (value.items = _replaceSchemaType(value.items, options, {
...config,
root: !1
}));
break;
}
return schema.type === "array" && schema.items && (Array.isArray(schema.items) ? schema.items = schema.items.map(
(item) => _replaceSchemaType(item, options, {
...config,
root: !1
})
) : schema.items = _replaceSchemaType(schema.items, options, {
...config,
root: !1
})), schema;
}, createCleaner = (schema) => (value) => {
if (typeof value == "object")
try {
return Value3.Clean(schema, value);
} catch {
}
return value;
}, getSchemaValidator = (s, {
models = {},
dynamic = !1,
modules,
normalize = !1,
additionalProperties = !1,
coerce = !1,
additionalCoerce = [],
validators,
sanitize
} = {}) => {
if (validators = validators?.filter((x) => x), !s) {
if (!validators?.length) return;
s = validators[0], validators = validators.slice(1);
}
let doesHaveRef, replaceSchema = (schema2) => coerce ? replaceSchemaType(schema2, [
{
from: t.Number(),
to: (options) => t.Numeric(options),
untilObjectFound: !0
},
{
from: t.Boolean(),
to: (options) => t.BooleanString(options),
untilObjectFound: !0
},
...Array.isArray(additionalCoerce) ? additionalCoerce : [additionalCoerce]
]) : replaceSchemaType(schema2, additionalCoerce), mapSchema = (s2) => {
let schema2;
if (!s2) return;
if (typeof s2 != "string") schema2 = s2;
else {
let isArray = s2.endsWith("[]"), key = isArray ? s2.substring(0, s2.length - 2) : s2;
schema2 = modules?.Import(
key
) ?? models[key], isArray && (schema2 = t.Array(schema2));
}
if (!schema2) return;
let _doesHaveRef;
if (schema2[Kind3] !== "Import" && (_doesHaveRef = hasRef(schema2))) {
let id = randomId();
doesHaveRef === void 0 && (doesHaveRef = _doesHaveRef), schema2 = t.Module({
// @ts-expect-error private property
...modules?.$defs,
[id]: schema2
}).Import(id);
}
if (schema2[Kind3] === "Import") {
let newDefs = {};
for (let [key2, value] of Object.entries(schema2.$defs))
newDefs[key2] = replaceSchema(value);
let key = schema2.$ref;
schema2 = t.Module(newDefs).Import(key);
} else (coerce || additionalCoerce) && (schema2 = replaceSchema(schema2));
return schema2;
}, schema = mapSchema(s);
if (validators?.length) {
let hasAdditional = !1, { schema: mergedObjectSchema, notObjects } = mergeObjectSchemas([
schema,
...validators.map(mapSchema)
]);
notObjects && (schema = t.Intersect([
...mergedObjectSchema ? [mergedObjectSchema] : [],
...notObjects.map((x) => {
let schema2 = mapSchema(x);
return schema2.type === "object" && "additionalProperties" in schema2 && (!hasAdditional && schema2.additionalProperties === !1 && (hasAdditional = !0), delete schema2.additionalProperties), schema2;
})
]), schema.type === "object" && hasAdditional && (schema.additionalProperties = !1));
} else
schema.type === "object" && !("additionalProperties" in schema) ? schema.additionalProperties = additionalProperties : schema = replaceSchemaType(schema, {
onlyFirstObject: !0,
from: t.Object({}),
// @ts-ignore
to({ properties, ...options }) {
if (properties && !("additionalProperties" in schema))
return t.Object(properties, {
...options,
additionalProperties: !1
});
}
});
if (dynamic) {
let validator = {
schema,
references: "",
checkFunc: () => {
},
code: "",
// @ts-expect-error
Check: (value) => Value3.Check(schema, value),
Errors: (value) => Value3.Errors(schema, value),
Code: () => "",
Clean: createCleaner(schema),
Decode: (value) => Value3.Decode(schema, value),
Encode: (value) => Value3.Encode(schema, value),
get hasAdditionalProperties() {
return "~hasAdditionalProperties" in this ? this["~hasAdditionalProperties"] : this["~hasAdditionalProperties"] = hasAdditionalProperties(schema);
},
get hasDefault() {
return "~hasDefault" in this ? this["~hasDefault"] : this["~hasDefault"] = hasProperty("default", schema);
},
get isOptional() {
return "~isOptional" in this ? this["~isOptional"] : this["~isOptional"] = isOptional(schema);
},
get hasTransform() {
return "~hasTransform" in this ? this["~hasTransform"] : this["~hasTransform"] = hasTransform(schema);
},
"~hasRef": doesHaveRef,
get hasRef() {
return "~hasRef" in this ? this["~hasRef"] : this["~hasRef"] = hasTransform(schema);
}
};
if (schema.config && (validator.config = schema.config, validator?.schema?.config && delete validator.schema.config), normalize && schema.additionalProperties === !1)
if (normalize === !0 || normalize === "exactMirror")
try {
validator.Clean = createMirror(schema, {
TypeCompiler: TypeCompiler3,
sanitize: sanitize?.(),
modules
});
} catch {
console.warn(
"Failed to create exactMirror. Please report the following code to https://github.com/elysiajs/elysia/issues"
), console.warn(schema), validator.Clean = createCleaner(schema);
}
else validator.Clean = createCleaner(schema);
return validator.parse = (v) => {
try {
return validator.Decode(v);
} catch {
throw [...validator.Errors(v)].map(mapValueError);
}
}, validator.safeParse = (v) => {
try {
return { success: !0, data: validator.Decode(v), error: null };
} catch {
let errors = [...compiled.Errors(v)].map(mapValueError);
return {
success: !1,
data: null,
error: errors[0]?.summary,
errors
};
}
}, validator;
}
let compiled = TypeCompiler3.Compile(
schema,
Object.values(models)
);
if (schema.config && (compiled.config = schema.config, compiled?.schema?.config && delete compiled.schema.config), normalize === !0 || normalize === "exactMirror")
try {
compiled.Clean = createMirror(schema, {
TypeCompiler: TypeCompiler3,
sanitize: sanitize?.(),
modules
});
} catch {
console.warn(
"Failed to create exactMirror. Please report the following code to https://github.com/elysiajs/elysia/issues"
), console.warn(schema), compiled.Clean = createCleaner(schema);
}
else compiled.Clean = createCleaner(schema);
return compiled.parse = (v) => {
try {
return compiled.Decode(v);
} catch {
throw [...compiled.Errors(v)].map(mapValueError);
}
}, compiled.safeParse = (v) => {
try {
return { success: !0, data: compiled.Decode(v), error: null };
} catch {
let errors = [...compiled.Errors(v)].map(mapValueError);
return {
success: !1,
data: null,
error: errors[0]?.summary,
errors
};
}
}, Object.assign(compiled, {
get hasAdditionalProperties() {
return "~hasAdditionalProperties" in this ? this["~hasAdditionalProperties"] : this["~hasAdditionalProperties"] = hasAdditionalProperties(compiled);
},
get hasDefault() {
return "~hasDefault" in this ? this["~hasDefault"] : this["~hasDefault"] = hasProperty("default", compiled);
},
get isOptional() {
return "~isOptional" in this ? this["~isOptional"] : this["~isOptional"] = isOptional(compiled);
},
get hasTransform() {
return "~hasTransform" in this ? this["~hasTransform"] : this["~hasTransform"] = hasTransform(schema);
},
get hasRef() {
return "~hasRef" in this ? this["~hasRef"] : this["~hasRef"] = hasRef(schema);
},
"~hasRef": doesHaveRef
}), compiled;
};
var mergeObjectSchemas = (schemas) => {
if (schemas.length === 0)
return {
schema: void 0,
notObjects: []
};
if (schemas.length === 1)
return schemas[0].type === "object" ? {
schema: schemas[0],
notObjects: []
} : {
schema: void 0,
notObjects: schemas
};
let newSchema, notObjects = [], additionalPropertiesIsTrue = !1, additionalPropertiesIsFalse = !1;
for (let schema of schemas) {
if (schema.type !== "object") {
notObjects.push(schema);
continue;
}
if ("additionalProperties" in schema && (schema.additionalProperties === !0 ? additionalPropertiesIsTrue = !0 : schema.additionalProperties === !1 && (additionalPropertiesIsFalse = !0)), !newSchema) {
newSchema = schema;
continue;
}
newSchema = {
...newSchema,
...schema,
properties: {
...newSchema.properties,
...schema.properties
},
required: [...newSchema?.required ?? [], ...schema.required]
};
}
return newSchema && (newSchema.required && (newSchema.required = [...new Set(newSchema.required)]), additionalPropertiesIsFalse ? newSchema.additionalProperties = !1 : additionalPropertiesIsTrue && (newSchema.additionalProperties = !0)), {
schema: newSchema,
notObjects
};
};
// src/compose.ts
var createReport = ({
context = "c",
trace = [],
addFn
}) => {
if (!trace.length)
return () => ({
resolveChild() {
return () => {
};
},
resolve() {
}
});
for (let i = 0; i < trace.length; i++)
addFn(
`let report${i},reportChild${i},reportErr${i},reportErrChild${i};let trace${i}=${context}[ELYSIA_TRACE]?.[${i}]??trace[${i}](${context});
`
);
return (event, {
name,
total = 0
} = {}) => {
name || (name = "anonymous");
let reporter = event === "error" ? "reportErr" : "report";
for (let i = 0; i < trace.length; i++)
addFn(
`${reporter}${i} = trace${i}.${event}({id,event:'${event}',name:'${name}',begin:performance.now(),total:${total}})
`
);
return {
resolve() {
for (let i = 0; i < trace.length; i++)
addFn(`${reporter}${i}.resolve()
`);
},
resolveChild(name2) {
for (let i = 0; i < trace.length; i++)
addFn(
`${reporter}Child${i}=${reporter}${i}.resolveChild?.shift()?.({id,event:'${event}',name:'${name2}',begin:performance.now()})
`
);
return (binding) => {
for (let i = 0; i < trace.length; i++)
addFn(
binding ? `if(${binding} instanceof Error){${reporter}Child${i}?.(${binding}) }else{${reporter}Child${i}?.()}` : `${reporter}Child${i}?.()
`
);
};
}
};
};
};
var matchResponseClone = /=>\s?response\.clone\(/, matchFnReturn = /(?:return|=>)\s?\S+\(|a(?:sync|wait)/, isAsync = (v) => {
let isObject = typeof v == "object";
if (isObject && v.isAsync !== void 0) return v.isAsync;
let fn = isObject ? v.fn : v;
if (fn.constructor.name === "AsyncFunction") return !0;
let literal = fn.toString();
if (matchResponseClone.test(literal))
return isObject && (v.isAsync = !1), !1;
let result = matchFnReturn.test(literal);
return isObject && (v.isAsync = result), result;
}, hasReturn = (v) => {
let isObject = typeof v == "object";
if (isObject && v.hasReturn !== void 0) return v.hasReturn;
let fnLiteral = isObject ? v.fn.toString() : typeof v == "string" ? v.toString() : v, parenthesisEnd = fnLiteral.indexOf(")");
if (fnLiteral.charCodeAt(parenthesisEnd + 2) === 61 && fnLiteral.charCodeAt(parenthesisEnd + 5) !== 123)
return isObject && (v.hasReturn = !0), !0;
let result = fnLiteral.includes("return");
return isObject && (v.hasReturn = result), result;
};
var createOnRequestHandler = (app, addFn) => {
let fnLiteral = "", reporter = createReport({
trace: app.event.trace,
addFn: addFn ?? ((word) => {
fnLiteral += word;
})
})("request", {
total: app.event.request?.length
});
if (app.event.request?.length) {
fnLiteral += "try{";
for (let i = 0; i < app.event.request.length; i++) {
let hook = app.event.request[i], withReturn = hasReturn(hook), maybeAsync = isAsync(hook), endUnit = reporter.resolveChild(app.event.request[i].fn.name);
withReturn ? (fnLiteral += `re=mapEarlyResponse(${maybeAsync ? "await " : ""}onRequest[${i}](c),c.set)
`, endUnit("re"), fnLiteral += `if(re!==undefined)return re
`) : (fnLiteral += `${maybeAsync ? "await " : ""}onRequest[${i}](c)
`, endUnit());
}
fnLiteral += "}catch(error){return app.handleError(c,error,false)}";
}
return reporter.resolve(), fnLiteral;
}, createHoc = (app, fnName = "map") => {
let hoc = app.extender.higherOrderFunctions;
if (!hoc.length) return "return " + fnName;
let adapter = app["~adapter"].composeGeneralHandler, handler = fnName;
for (let i = 0; i < hoc.length; i++)
handler = `hoc[${i}](${handler},${adapter.parameters})`;
return `return function hocMap(${adapter.parameters}){return ${handler}(${adapter.parameters})}`;
};
// src/adapter/bun/handler.ts
var mapResponse2 = (response, set2, request) => {
if (isNotEmpty(set2.headers) || set2.status !== 200 || set2.cookie)
switch (handleSet(set2), response?.constructor?.name) {
case "String":
return new Response(response, set2);
case "Array":
case "Object":
return set2.headers["content-type"] = "application/json", new Response(JSON.stringify(response), set2);
case "ElysiaFile":
return handleFile(response.value);
case "File":
return handleFile(response, set2);
case "Blob":
return handleFile(response, set2);
case "ElysiaCustomStatusResponse":
return set2.status = response.code, mapResponse2(
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 handleResponse2(response, set2, request);
case "Error":
return errorToResponse2(response, set2);
case "Promise":
return response.then(
(x) => mapResponse2(x, set2, request)
);
case "Function":
return mapResponse2(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 handleResponse2(response, set2, request);
if (response instanceof Promise)
return response.then((x) => mapResponse2(x, set2));
if (response instanceof Error)
return errorToResponse2(response, set2);
if (response instanceof ElysiaCustomStatusResponse)
return set2.status = response.code, mapResponse2(
response.response,
set2,
request
);
if (typeof response?.next == "function")
return handleStream2(response, set2, request);
if (typeof response?.then == "function")
return response.then((x) => mapResponse2(x, set2));
if (typeof response?.toResponse == "function")
return mapResponse2(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" ? handleStream2(
streamResponse(response),
responseToSetHeaders(response, set2),
request
) : (
// @ts-expect-error
typeof response?.next == "function" || response instanceof ReadableStream ? handleStream2(response, set2, request) : mapCompactResponse2(response, request)
);
}, mapEarlyResponse2 = (response, set2, request) => {
if (response != null)
if (isNotEmpty(set2.headers) || set2.status !== 200 || set2.cookie)
switch (handleSet(set2), response?.constructor?.name) {
case "String":
return new Response(response, set2);
case "Array":
case "Object":
return set2.headers["content-type"] = "application/json", new Response(JSON.stringify(response), set2);
case "ElysiaFile":
return handleFile(response.value);
case "File":
return handleFile(response, set2);
case "Blob":
return handleFile(response, set2);
case "ElysiaCustomStatusResponse":
return set2.status = response.code, mapEarlyResponse2(
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 handleResponse2(response, set2, request);
case "Promise":
return response.then(
(x) => mapEarlyResponse2(x, set2)
);
case "Error":
return errorToResponse2(response, set2);
case "Function":
return mapEarlyResponse2(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 handleResponse2(response, set2, request);
if (response instanceof Promise)
return response.then((x) => mapEarlyResponse2(x, set2));
if (response instanceof Error)
return errorToResponse2(response, set2);
if (response instanceof ElysiaCustomStatusResponse)
return set2.status = response.code, mapEarlyResponse2(
response.response,
set2,
request
);
if (typeof response?.next == "function")
return handleStream2(response, set2, request);
if (typeof response?.then == "function")
return response.then((x) => mapEarlyResponse2(x, set2));
if (typeof response?.toResponse == "function")
return mapEarlyResponse2(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 new Response(response);
case "Array":
case "Object":
return set2.headers["content-type"] = "application/json", new Response(JSON.stringify(response), set2);
case "ElysiaFile":
return handleFile(response.value);
case "File":
return handleFile(response, set2);
case "Blob":
return handleFile(response, set2);
case "ElysiaCustomStatusResponse":
return set2.status = response.code, mapEarlyResponse2(
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" ? handleStream2(
streamResponse(response),
responseToSetHeaders(response),
request
) : response;
case "Promise":
return response.then((x) => {
let r = mapEarlyResponse2(x, set2);
if (r !== void 0) return r;
});
case "Error":
return errorToResponse2(response, set2);
case "Function":
return mapCompactResponse2(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) => mapEarlyResponse2(x, set2));
if (response instanceof Error)
return errorToResponse2(response, set2);
if (response instanceof ElysiaCustomStatusResponse)
return set2.status = response.code, mapEarlyResponse2(
response.response,
set2,
request
);
if (typeof response?.next == "function")
return handleStream2(response, set2, request);
if (typeof response?.then == "function")
return response.then((x) => mapEarlyResponse2(x, set2));
if (typeof response?.toResponse == "function")
return mapEarlyResponse2(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);
}
}, mapCompactResponse2 = (response, request) => {
switch (response?.constructor?.name) {
case "String":
return new Response(response);
case "Object":
case "Array":
return new Response(JSON.stringify(response), {
headers: {
"Content-Type": "application/json"
}
});
case "ElysiaFile":
return handleFile(response.value);
case "File":
return handleFile(response);
case "Blob":
return handleFile(response);
case "ElysiaCustomStatusResponse":
return mapResponse2(
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" ? handleStream2(
streamResponse(response),
responseToSetHeaders(response),
request
) : response;
case "Error":
return errorToResponse2(response);
case "Promise":
return response.then(
(x) => mapCompactResponse2(x, request)
);
// ? Maybe response or Blob
case "Function":
return mapCompactResponse2(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) => mapCompactResponse2(x, request)
);
if (response instanceof Error)
return errorToResponse2(response);
if (response instanceof ElysiaCustomStatusResponse)
return mapResponse2(
response.response,
{
status: response.code,
headers: {}
}
);
if (typeof response?.next == "function")
return handleStream2(response, void 0, request);
if (typeof response?.then == "function")
return response.then((x) => mapResponse2(x, set));
if (typeof response?.toResponse == "function")
return mapCompactResponse2(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);
}
}, errorToResponse2 = (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
}
), createStaticHandler2 = (handle, hooks, setHeaders = {}) => {
if (typeof handle == "function") return;
let response = mapResponse2(handle, {
headers: setHeaders
});
if (!hooks.parse?.length && !hooks.transform?.length && !hooks.beforeHandle?.length && !hooks.afterHandle?.length)
return response.clone.bind(response);
}, handleResponse2 = createResponseHandler({
mapResponse: mapResponse2,
mapCompactResponse: mapCompactResponse2
}), handleStream2 = createStreamHandler({
mapResponse: mapResponse2,
mapCompactResponse: mapCompactResponse2
});
// src/adapter/bun/compose.ts
var allocateIf = (value, condition) => condition ? value : "", createContext = (app, route, inference, isInline = !1) => {
let fnLiteral = "", defaultHeaders = app.setHeaders, hasTrace = !!app.event.trace?.length;
hasTrace && (fnLiteral += `const id=randomId()
`);
let isDynamic = /[:*]/.test(route.path), getQi = `const u=request.url,s=u.indexOf('/',${app.config.handler?.standardHostname ?? !0 ? 11 : 7}),qi=u.indexOf('?', s + 1)
`, needsQuery = inference.query || !!route.hooks.query || !!route.standaloneValidators?.find((x) => x.query) || app.event.request?.length;
needsQuery && (fnLiteral += getQi);
let getPath = inference.path ? isDynamic ? "get path(){" + (needsQuery ? "" : getQi) + `if(qi===-1)return u.substring(s)
return u.substring(s,qi)
},` : `path:'${route.path}',` : "";
fnLiteral += allocateIf("const c=", !isInline) + "{request,store," + allocateIf("qi,", needsQuery) + allocateIf("params:request.params,", isDynamic) + getPath + allocateIf(
"url:request.url,",
hasTrace || inference.url || needsQuery
) + "redirect,error:status,status,set:{headers:" + (isNotEmpty(defaultHeaders) ? "Object.assign({},app.setHeaders)" : "Object.create(null)") + ",status:200}", inference.server && (fnLiteral += ",get server(){return app.getServer()}"), hasTrace && (fnLiteral += ",[ELYSIA_REQUEST_ID]:id");
{
let decoratorsLiteral = "";
for (let key of Object.keys(app.singleton.decorator))
decoratorsLiteral += `,'${key}':decorator['${key}']`;
fnLiteral += decoratorsLiteral;
}
return fnLiteral += `}
`, fnLiteral;
}, createBunRouteHandler = (app, route) => {
let hasTrace = !!app.event.trace?.length, hasHoc = !!app.extender.higherOrderFunctions.length, inference = sucrose(
route.hooks,
// @ts-expect-error
app.inference
);
inference = sucrose(
{
handler: route.handler
},
inference
);
let fnLiteral = "const handler=data.handler,app=data.app,store=data.store,decorator=data.decorator,redirect=data.redirect,route=data.route,mapEarlyResponse=data.mapEarlyResponse," + allocateIf("randomId=data.randomId,", hasTrace) + allocateIf("ELYSIA_REQUEST_ID=data.ELYSIA_REQUEST_ID,", hasTrace) + allocateIf("ELYSIA_TRACE=data.ELYSIA_TRACE,", hasTrace) + allocateIf("trace=data.trace,", hasTrace) + allocateIf("hoc=data.hoc,", hasHoc) + `status=data.status
`;
app.event.request?.length && (fnLiteral += `const onRequest=app.event.request.map(x=>x.fn)
`), fnLiteral += `${app.event.request?.find(isAsync) ? "async" : ""} function map(request){`;
let needsQuery = inference.query || !!route.hooks.query || !!route.standaloneValidators?.find((x) => x.query);
return hasTrace || needsQuery || app.event.request?.length ? (fnLiteral += createContext(app, route, inference), fnLiteral += createOnRequestHandler(app), fnLiteral += "return handler(c)}") : fnLiteral += `return handler(${createContext(app, route, inference, !0)})}`, fnLiteral += createHoc(app), Function(
"data",
fnLiteral
)({
app,
handler: route.compile?.() ?? route.composed,
redirect,
status,
// @ts-expect-error private property
hoc: app.extender.higherOrderFunctions.map((x) => x.fn),
store: app.store,
decorator: app.decorator,
route: route.path,
randomId: hasTrace ? randomId : void 0,
ELYSIA_TRACE: hasTrace ? ELYSIA_TRACE : void 0,
ELYSIA_REQUEST_ID: hasTrace ? ELYSIA_REQUEST_ID : void 0,
trace: hasTrace ? app.event.trace?.map((x) => x?.fn ?? x) : void 0,
mapEarlyResponse: mapEarlyResponse2
});
};
// src/adapter/bun/handler-native.ts
var createNativeStaticHandler = (handle, hooks, setHeaders = {}) => {
if (typeof handle == "function" || handle instanceof Blob) return;
if (typeof handle == "object" && handle?.toString() === "[object HTMLBundle]")
return () => handle;
let response = mapResponse2(handle, {
headers: setHeaders
});
if (!hooks.parse?.length && !hooks.transform?.length && !hooks.beforeHandle?.length && !hooks.afterHandle?.length)
return response instanceof Promise ? response.then((response2) => {
if (response2)
return response2.headers.has("content-type") || response2.headers.append("content-type", "text/plain"), response2.clone();
}) : (response.headers.has("content-type") || response.headers.append("content-type", "text/plain"), () => response.clone());
};
// src/ws/index.ts
var websocket = {
open(ws) {
ws.data.open?.(ws);
},
message(ws, message) {
ws.data.message?.(ws, message);
},
drain(ws) {
ws.data.drain?.(ws);
},
close(ws, code, reason) {
ws.data.close?.(ws, code, reason);
}
}, ElysiaWS = class {
constructor(raw, data, body = void 0) {
this.raw = raw;
this.data = data;
this.body = body;
this.validator = raw.data?.validator, this.sendText = raw.sendText.bind(raw), this.sendBinary = raw.sendBinary.bind(raw), this.close = raw.close.bind(raw), this.terminate = raw.terminate.bind(raw), this.publishText = raw.publishText.bind(raw), this.publishBinary = raw.publishBinary.bind(raw), this.subscribe = raw.subscribe.bind(raw), this.unsubscribe = raw.unsubscribe.bind(raw), this.isSubscribed = raw.isSubscribed.bind(raw), this.cork = raw.cork.bind(raw), this.remoteAddress = raw.remoteAddress, this.binaryType = raw.binaryType, this.data = raw.data, this.send = this.send.bind(this), this.ping = this.ping.bind(this), this.pong = this.pong.bind(this), this.publish = this.publish.bind(this);
}
get id() {
return this.data.id;
}
/**
* Sends a message to the client.
*
* @param data The data to send.
* @param compress Should the data be compressed? If the client does not support compression, this is ignored.
* @example
* ws.send("Hello!");
* ws.send("Compress this.", true);
* ws.send(new Uint8Array([1, 2, 3, 4]));
*/
send(data, compress) {
return Buffer.isBuffer(data) ? this.raw.send(data, compress) : this.validator?.Check(data) === !1 ? this.raw.send(
new ValidationError("message", this.validator, data).message
) : (typeof data == "object" && (data = JSON.stringify(data)), this.raw.send(data, compress));
}
/**
* Sends a ping.
*
* @param data The data to send
*/
ping(data) {
return Buffer.isBuffer(data) ? this.raw.ping(data) : this.validator?.Check(data) === !1 ? this.raw.send(
new ValidationError("message", this.validator, data).message
) : (typeof data == "object" && (data = JSON.stringify(data)), this.raw.ping(data));
}
/**
* Sends a pong.
*
* @param data The data to send
*/
pong(data) {
return Buffer.isBuffer(data) ? this.raw.pong(data) : this.validator?.Check(data) === !1 ? this.raw.send(
new ValidationError("message", this.validator, data).message
) : (typeof data == "object" && (data = JSON.stringify(data)), this.raw.pong(data));
}
/**
* Sends a message to subscribers of the topic.
*
* @param topic The topic name.
* @param data The data to send.
* @param compress Should the data be compressed? If the client does not support compression, this is ignored.
* @example
* ws.publish("chat", "Hello!");
* ws.publish("chat", "Compress this.", true);
* ws.publish("chat", new Uint8Array([1, 2, 3, 4]));
*/
publish(topic, data, compress) {
return Buffer.isBuffer(data) ? this.raw.publish(
topic,
data,
compress
) : this.validator?.Check(data) === !1 ? this.raw.send(
new ValidationError("message", this.validator, data).message
) : (typeof data == "object" && (data = JSON.stringify(data)), this.raw.publish(topic, data, compress));
}
get readyState() {
return this.raw.readyState;
}
}, createWSMessageParser = (parse2) => {
let parsers = typeof parse2 == "function" ? [parse2] : parse2;
return async function(ws, message) {
if (typeof message == "string") {
let start = message?.charCodeAt(0);
if (start === 34 || start === 47 || start === 91 || start === 123)
try {
message = JSON.parse(message);
} catch {
}
else isNumericString(message) ? message = +message : message === "true" ? message = !0 : message === "false" ? message = !1 : message === "null" && (message = null);
}
if (parsers)
for (let i = 0; i < parsers.length; i++) {
let temp = parsers[i](ws, message);
if (temp instanceof Promise && (temp = await temp), temp !== void 0) return temp;
}
return message;
};
}, createHandleWSResponse = (validateResponse) => {
let handleWSResponse = (ws, data) => {
if (data instanceof Promise)
return data.then((data2) => handleWSResponse(ws, data2));
if (Buffer.isBuffer(data)) return ws.send(data.toString());
if (data === void 0) return;
let send = (datum) => {
if (validateResponse?.Check(datum) === !1)
return ws.send(
new ValidationError("message", validateResponse, datum).message
);
if (typeof datum == "object") return ws.send(JSON.stringify(datum));
ws.send(datum);
};
if (typeof data?.next != "function")
return void send(data);
let init = data.next();
if (init instanceof Promise)
return (async () => {
let first = await init;
if (validateResponse?.Check(first) === !1)
return ws.send(
new ValidationError("message", validateResponse, first).message
);
if (send(first.value), !first.done)
for await (let datum of data) send(datum);
})();
if (send(init.value), !init.done) for (let datum of data) send(datum);
};
return handleWSResponse;
};
// src/adapter/bun/index.ts
var optionalParam = /:.+?\?(?=\/|$)/, getPossibleParams = (path) => {
let match = optionalParam.exec(path);
if (!match) return [path];
let routes = [], head = path.slice(0, match.index), param = match[0].slice(0, -1), tail = path.slice(match.index + match[0].length);
routes.push(head.slice(0, -1)), routes.push(head + param);
for (let fragment of getPossibleParams(tail))
fragment && (fragment.startsWith("/:") || routes.push(head.slice(0, -1) + fragment), routes.push(head + param + fragment));
return routes;
}, supportedMethods = {
GET: !0,
HEAD: !0,
OPTIONS: !0,
DELETE: !0,
PATCH: !0,
POST: !0,
PUT: !0
}, mapRoutes = (app) => {
if (!app.config.aot || !app.config.systemRouter) return;
let routes = {}, add = (route, handler) => {
routes[route.path] ? routes[route.path][route.method] || (routes[route.path][route.method] = handler) : routes[route.path] = {
[route.method]: handler
};
}, tree = app.routeTree;
for (let route of app.router.history) {
if (typeof route.handler != "function") continue;
let method = route.method;
if (method === "GET" && `WS_${route.path}` in tree || method === "WS" || route.path.charCodeAt(route.path.length - 1) === 42 || !(method in supportedMethods))
continue;
if (method === "ALL") {
`WS_${route.path}` in tree || (routes[route.path] = route.hooks?.config?.mount ? route.hooks.trace || app.event.trace || // @ts-expect-error private property
app.extender.higherOrderFunctions ? createBunRouteHandler(app, route) : route.hooks.mount || route.handler : route.handler);
continue;
}
let compiled, handler = app.config.precompile ? createBunRouteHandler(app, route) : (request) => compiled ? compiled(request) : (compiled = createBunRouteHandler(app, route))(
request
);
for (let path of getPossibleParams(route.path))
add(
{
method,
path
},
handler
);
}
return routes;
}, mergeRoutes = (r1, r2) => {
if (!r2) return r1;
for (let key of Object.keys(r2))
if (r1[key] !== r2[key]) {
if (!r1[key]) {
r1[key] = r2[key];
continue;
}
if (r1[key] && r2[key]) {
if (typeof r1[key] == "function" || r1[key] instanceof Response) {
r1[key] = r2[key];
continue;
}
r1[key] = {
...r1[key],
...r2[key]
};
}
}
return r1;
}, BunAdapter = {
...WebStandardAdapter,
name: "bun",
handler: {
mapResponse: mapResponse2,
mapEarlyResponse: mapEarlyResponse2,
mapCompactResponse: mapCompactResponse2,
createStaticHandler: createStaticHandler2,
createNativeStaticHandler
},
composeHandler: {
...WebStandardAdapter.composeHandler,
headers: hasHeaderShorthand ? `c.headers=c.request.headers.toJSON()
` : `c.headers={}
for(const [k,v] of c.request.headers.entries())c.headers[k]=v
`
},
listen(app) {
return (options, callback) => {
if (typeof Bun > "u")
throw new Error(
".listen() is designed to run on Bun only. If you are running Elysia in other environment please use a dedicated plugin or export the handler via Elysia.fetch"
);
if (app.compile(), typeof options == "string") {
if (!isNumericString(options))
throw new Error("Port must be a numeric value");
options = parseInt(options);
}
let createStaticRoute = (iterator, { withAsync = !1 } = {}) => {
let staticRoutes = {}, ops = [];
for (let [path, route] of Object.entries(iterator))
if (supportPerMethodInlineHandler) {
if (!route) continue;
for (let [method, value] of Object.entries(route))
if (!(!value || !(method in supportedMethods))) {
if (value instanceof Promise) {
withAsync && (staticRoutes[path] || (staticRoutes[path] = {}), ops.push(
value.then((awaited) => {
awaited instanceof Response && (staticRoutes[path][method] = awaited), typeof awaited == "object" && awaited?.toString() === "[object HTMLBundle]" && (staticRoutes[path][method] = awaited);
})
));
continue;
}
!(value instanceof Response) && !(typeof value == "object" && value?.toString() === "[object HTMLBundle]") || (staticRoutes[path] || (staticRoutes[path] = {}), staticRoutes[path][method] = value);
}
} else {
if (!route) continue;
if (route instanceof Promise) {
withAsync && (staticRoutes[path] || (staticRoutes[path] = {}), ops.push(
route.then((awaited) => {
awaited instanceof Response && (staticRoutes[path] = awaited);
})
));
continue;
}
if (!(route instanceof Response)) continue;
staticRoutes[path] = route;
}
return withAsync ? Promise.all(ops).then(() => staticRoutes) : staticRoutes;
}, serve = typeof options == "object" ? {
development: !isProduction,
reusePort: !0,
...app.config.serve || {},
...options || {},
// @ts-ignore
routes: mergeRoutes(
mergeRoutes(
createStaticRoute(app.router.response),
mapRoutes(app)
),
// @ts-expect-error private property
app.config.serve?.routes
),
websocket: {
...app.config.websocket || {},
...websocket || {}
},
fetch: app.fetch
} : {
development: !isProduction,
reusePort: !0,
...app.config.serve || {},
// @ts-ignore
routes: mergeRoutes(
mergeRoutes(
createStaticRoute(app.router.response),
mapRoutes(app)
),
// @ts-expect-error private property
app.config.serve?.routes
),
websocket: {
...app.config.websocket || {},
...websocket || {}
},
port: options,
fetch: app.fetch
};
if (app.server = Bun.serve(serve), app.event.start)
for (let i = 0; i < app.event.start.length; i++)
app.event.start[i].fn(app);
callback && callback(app.server), process.on("beforeExit", () => {
if (app.server && (app.server.stop?.(), app.server = null, app.event.stop))
for (let i = 0; i < app.event.stop.length; i++)
app.event.stop[i].fn(app);
}), app.promisedModules.then(async () => {
app.server?.reload({
...serve,
fetch: app.fetch,
// @ts-ignore
routes: mergeRoutes(
mergeRoutes(
await createStaticRoute(app.router.response, {
withAsync: !0
}),
mapRoutes(app)
),
// @ts-expect-error private property
app.config.serve?.routes
)
}), Bun?.gc(!1);
});
};
},
async stop(app, closeActiveConnections) {
if (app.server) {
if (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);
} else
console.log(
"Elysia isn't running. Call `app.listen` to start the server.",
new Error().stack
);
},
ws(app, path, options) {
let { parse: parse2, body, response, ...rest } = options, validateMessage = getSchemaValidator(body, {
// @ts-expect-error private property
modules: app.definitions.typebox,
// @ts-expect-error private property
models: app.definitions.type,
normalize: app.config.normalize
}), validateResponse = getSchemaValidator(response, {
// @ts-expect-error private property
modules: app.definitions.typebox,
// @ts-expect-error private property
models: app.definitions.type,
normalize: app.config.normalize
});
app.route(
"WS",
path,
async (context) => {
let server = context.server ?? app.server, { set: set2, path: path2, qi, headers, query, params } = context;
if (context.validator = validateResponse, options.upgrade)
if (typeof options.upgrade == "function") {
let temp = options.upgrade(context);
temp instanceof Promise && await temp;
} else options.upgrade && Object.assign(
set2.headers,
options.upgrade
);
if (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"]
));
let handleResponse3 = createHandleWSResponse(validateResponse), parseMessage = createWSMessageParser(parse2), _id;
if (typeof options.beforeHandle == "function") {
let result = options.beforeHandle(context);
result instanceof Promise && await result;
}
let errorHandlers = [
...options.error ? Array.isArray(options.error) ? options.error : [options.error] : [],
...(app.event.error ?? []).map(
(x) => typeof x == "function" ? x : x.fn
)
].filter((x) => x), handleErrors = errorHandlers.length ? async (ws, error) => {
for (let handleError of errorHandlers) {
let response2 = handleError(
Object.assign(context, { error })
);
if (response2 instanceof Promise && (response2 = await response2), await handleResponse3(ws, response2), response2) break;
}
} : () => {
};
if (!server?.upgrade(context.request, {
headers: isNotEmpty(set2.headers) ? set2.headers : void 0,
data: {
...context,
get id() {
return _id || (_id = randomId());
},
validator: validateResponse,
ping(data) {
options.ping?.(data);
},
pong(data) {
options.pong?.(data);
},
open: async (ws) => {
try {
await handleResponse3(
ws,
options.open?.(
new ElysiaWS(ws, context)
)
);
} catch (error) {
handleErrors(ws, error);
}
},
message: async (ws, _message) => {
let message = await parseMessage(ws, _message);
if (validateMessage?.Check(message) === !1)
return void ws.send(
new ValidationError(
"message",
validateMessage,
message
).message
);
try {
await handleResponse3(
ws,
options.message?.(
new ElysiaWS(
ws,
context,
message
),
message
)
);
} catch (error) {
handleErrors(ws, error);
}
},
drain: async (ws) => {
try {
await handleResponse3(
ws,
options.drain?.(
new ElysiaWS(ws, context)
)
);
} catch (error) {
handleErrors(ws, error);
}
},
close: async (ws, code, reason) => {
try {
await handleResponse3(
ws,
options.close?.(
new ElysiaWS(ws, context),
code,
reason
)
);
} catch (error) {
handleErrors(ws, error);
}
}
}
}))
return set2.status = 400, "Expected a websocket connection";
},
{
...rest,
websocket: options
}
);
}
};
export {
BunAdapter
};
/**
* @license
*
* MIT License
*
* Copyright (c) 2020 Evgeny Poberezkin
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/