elysia
Version:
Ergonomic Framework for Human
1,288 lines (1,274 loc) • 80.5 kB
JavaScript
// src/universal/utils.ts
var isBun = typeof Bun < "u";
// src/universal/file.ts
var mime = {
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
mime[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 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/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 decode from "fast-decode-uri-component";
// 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/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/cookies.ts
import { parse, serialize } from "cookie";
import decode2 from "fast-decode-uri-component";
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;