UNPKG

elysia

Version:

Ergonomic Framework for Human

1,288 lines (1,274 loc) 80.5 kB
// 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;