522 lines
24 KiB
JavaScript
522 lines
24 KiB
JavaScript
"use strict";
|
|
var __defProp = Object.defineProperty;
|
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
var __export = (target, all) => {
|
|
for (var name in all)
|
|
__defProp(target, name, { get: all[name], enumerable: !0 });
|
|
}, __copyProps = (to, from, except, desc) => {
|
|
if (from && typeof from == "object" || typeof from == "function")
|
|
for (let key of __getOwnPropNames(from))
|
|
!__hasOwnProp.call(to, key) && key !== except && __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
return to;
|
|
};
|
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: !0 }), mod);
|
|
var dynamic_handle_exports = {};
|
|
__export(dynamic_handle_exports, {
|
|
createDynamicErrorHandler: () => createDynamicErrorHandler,
|
|
createDynamicHandler: () => createDynamicHandler
|
|
});
|
|
module.exports = __toCommonJS(dynamic_handle_exports);
|
|
var import_value = require("@sinclair/typebox/value"), import_cookies = require('./cookies.js'), import_error = require('./error.js'), import_parse_query = require('./parse-query.js'), import_schema = require('./schema.js'), import_utils = require('./utils.js');
|
|
const ARRAY_INDEX_REGEX = /^(.+)\[(\d+)\]$/, DANGEROUS_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]), isDangerousKey = (key) => {
|
|
if (DANGEROUS_KEYS.has(key)) return !0;
|
|
const match = key.match(ARRAY_INDEX_REGEX);
|
|
return match ? DANGEROUS_KEYS.has(match[1]) : !1;
|
|
}, parseArrayKey = (key) => {
|
|
const match = key.match(ARRAY_INDEX_REGEX);
|
|
return match ? {
|
|
name: match[1],
|
|
index: parseInt(match[2], 10)
|
|
} : null;
|
|
}, parseObjectString = (entry) => {
|
|
if (!(typeof entry != "string" || entry.charCodeAt(0) !== 123))
|
|
try {
|
|
const parsed = JSON.parse(entry);
|
|
if (parsed && typeof parsed == "object" && !Array.isArray(parsed))
|
|
return parsed;
|
|
} catch {
|
|
return;
|
|
}
|
|
}, setNestedValue = (obj, path, value) => {
|
|
const keys = path.split("."), lastKey = keys.pop();
|
|
if (isDangerousKey(lastKey) || keys.some(isDangerousKey)) return;
|
|
let current = obj;
|
|
for (const key of keys) {
|
|
const arrayInfo2 = parseArrayKey(key);
|
|
if (arrayInfo2) {
|
|
Array.isArray(current[arrayInfo2.name]) || (current[arrayInfo2.name] = []);
|
|
const existing = current[arrayInfo2.name][arrayInfo2.index], isFile = typeof File < "u" && existing instanceof File;
|
|
(!existing || typeof existing != "object" || Array.isArray(existing) || isFile) && (current[arrayInfo2.name][arrayInfo2.index] = parseObjectString(existing) ?? {}), current = current[arrayInfo2.name][arrayInfo2.index];
|
|
} else
|
|
(!current[key] || typeof current[key] != "object") && (current[key] = {}), current = current[key];
|
|
}
|
|
const arrayInfo = parseArrayKey(lastKey);
|
|
arrayInfo ? (Array.isArray(current[arrayInfo.name]) || (current[arrayInfo.name] = []), current[arrayInfo.name][arrayInfo.index] = value) : current[lastKey] = value;
|
|
}, normalizeFormValue = (value) => {
|
|
if (value.length === 1) {
|
|
const stringValue2 = value[0];
|
|
if (typeof stringValue2 == "string" && (stringValue2.charCodeAt(0) === 123 || stringValue2.charCodeAt(0) === 91))
|
|
try {
|
|
const parsed2 = JSON.parse(stringValue2);
|
|
if (parsed2 && typeof parsed2 == "object")
|
|
return parsed2;
|
|
} catch {
|
|
}
|
|
return value[0];
|
|
}
|
|
const stringValue = value.find(
|
|
(entry) => typeof entry == "string"
|
|
);
|
|
if (!stringValue || typeof File > "u") return value;
|
|
const files = value.filter((entry) => entry instanceof File);
|
|
if (!files.length || stringValue.charCodeAt(0) !== 123) return value;
|
|
let parsed;
|
|
try {
|
|
parsed = JSON.parse(stringValue);
|
|
} catch {
|
|
return value;
|
|
}
|
|
return typeof parsed != "object" || parsed === null ? value : (!("file" in parsed) && files.length === 1 ? parsed.file = files[0] : !("files" in parsed) && files.length > 1 && (parsed.files = files), parsed);
|
|
}, injectDefaultValues = (typeChecker, obj) => {
|
|
let schema = typeChecker.schema;
|
|
if (!schema) return;
|
|
schema.$defs?.[schema.$ref] && (schema = schema.$defs[schema.$ref]);
|
|
const properties = (0, import_schema.getSchemaProperties)(schema);
|
|
if (properties)
|
|
for (const [key, keySchema] of Object.entries(properties))
|
|
obj[key] ??= keySchema.default;
|
|
}, createDynamicHandler = (app) => {
|
|
const { mapResponse, mapEarlyResponse } = app["~adapter"].handler, defaultHeader = app.setHeaders;
|
|
return async (request) => {
|
|
const url = request.url, s = url.indexOf("/", 11), qi = url.indexOf("?", s + 1), path = qi === -1 ? url.substring(s) : url.substring(s, qi), set = {
|
|
cookie: {},
|
|
status: 200,
|
|
headers: defaultHeader ? { ...defaultHeader } : {}
|
|
}, context = Object.assign(
|
|
{},
|
|
// @ts-expect-error
|
|
app.singleton.decorator,
|
|
{
|
|
set,
|
|
// @ts-expect-error
|
|
store: app.singleton.store,
|
|
request,
|
|
path,
|
|
qi,
|
|
error: import_error.status,
|
|
status: import_error.status,
|
|
redirect: import_utils.redirect
|
|
}
|
|
);
|
|
let hooks;
|
|
try {
|
|
if (app.event.request)
|
|
for (let i = 0; i < app.event.request.length; i++) {
|
|
const onRequest = app.event.request[i].fn;
|
|
let response2 = onRequest(context);
|
|
if (response2 instanceof Promise && (response2 = await response2), response2 = mapEarlyResponse(response2, set), response2) return context.response = response2;
|
|
}
|
|
const methodKey = request.method === "GET" && request.headers.get("upgrade")?.toLowerCase() === "websocket" ? "WS" : request.method, handler = app.router.dynamic.find(request.method, path) ?? app.router.dynamic.find(methodKey, path) ?? app.router.dynamic.find("ALL", path);
|
|
if (!handler)
|
|
throw context.query = qi === -1 ? {} : (0, import_parse_query.parseQuery)(url.substring(qi + 1)), new import_error.NotFoundError();
|
|
const { handle, validator, content, route } = handler.store;
|
|
if (hooks = handler.store.hooks, hooks.config?.mount)
|
|
return await hooks.config.mount(request);
|
|
let body;
|
|
if (request.method !== "GET" && request.method !== "HEAD")
|
|
if (content)
|
|
switch (content) {
|
|
case "application/json":
|
|
body = await request.json();
|
|
break;
|
|
case "text/plain":
|
|
body = await request.text();
|
|
break;
|
|
case "application/x-www-form-urlencoded":
|
|
body = (0, import_parse_query.parseQuery)(await request.text());
|
|
break;
|
|
case "application/octet-stream":
|
|
body = await request.arrayBuffer();
|
|
break;
|
|
case "multipart/form-data": {
|
|
body = {};
|
|
const form = await request.formData();
|
|
for (const key of form.keys()) {
|
|
if (body[key]) continue;
|
|
const value = form.getAll(key), finalValue = normalizeFormValue(value);
|
|
key.includes(".") || key.includes("[") ? setNestedValue(body, key, finalValue) : body[key] = finalValue;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
else {
|
|
let contentType;
|
|
if (request.body && (contentType = request.headers.get("content-type")), contentType) {
|
|
const index = contentType.indexOf(";");
|
|
if (index !== -1 && (contentType = contentType.slice(0, index)), context.contentType = contentType, hooks.parse)
|
|
for (let i = 0; i < hooks.parse.length; i++) {
|
|
const hook = hooks.parse[i].fn;
|
|
if (typeof hook == "string")
|
|
switch (hook) {
|
|
case "json":
|
|
case "application/json":
|
|
body = await request.json();
|
|
break;
|
|
case "text":
|
|
case "text/plain":
|
|
body = await request.text();
|
|
break;
|
|
case "urlencoded":
|
|
case "application/x-www-form-urlencoded":
|
|
body = (0, import_parse_query.parseQuery)(
|
|
await request.text()
|
|
);
|
|
break;
|
|
case "arrayBuffer":
|
|
case "application/octet-stream":
|
|
body = await request.arrayBuffer();
|
|
break;
|
|
case "formdata":
|
|
case "multipart/form-data": {
|
|
body = {};
|
|
const form = await request.formData();
|
|
for (const key of form.keys()) {
|
|
if (body[key]) continue;
|
|
const value = form.getAll(key), finalValue = normalizeFormValue(value);
|
|
key.includes(".") || key.includes("[") ? setNestedValue(body, key, finalValue) : body[key] = finalValue;
|
|
}
|
|
break;
|
|
}
|
|
default: {
|
|
const parser = app["~parser"][hook];
|
|
if (parser) {
|
|
let temp = parser(
|
|
context,
|
|
contentType
|
|
);
|
|
if (temp instanceof Promise && (temp = await temp), temp) {
|
|
body = temp;
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
else {
|
|
let temp = hook(context, contentType);
|
|
if (temp instanceof Promise && (temp = await temp), temp) {
|
|
body = temp;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (delete context.contentType, body === void 0)
|
|
switch (contentType) {
|
|
case "application/json":
|
|
body = await request.json();
|
|
break;
|
|
case "text/plain":
|
|
body = await request.text();
|
|
break;
|
|
case "application/x-www-form-urlencoded":
|
|
body = (0, import_parse_query.parseQuery)(await request.text());
|
|
break;
|
|
case "application/octet-stream":
|
|
body = await request.arrayBuffer();
|
|
break;
|
|
case "multipart/form-data": {
|
|
body = {};
|
|
const form = await request.formData();
|
|
for (const key of form.keys()) {
|
|
if (body[key]) continue;
|
|
const value = form.getAll(key), finalValue = normalizeFormValue(value);
|
|
key.includes(".") || key.includes("[") ? setNestedValue(body, key, finalValue) : body[key] = finalValue;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
context.route = route, context.body = body, context.params = handler?.params || void 0, context.query = qi === -1 ? {} : (0, import_parse_query.parseQuery)(url.substring(qi + 1)), context.headers = {};
|
|
for (const [key, value] of request.headers.entries())
|
|
context.headers[key] = value;
|
|
const cookieMeta = {
|
|
domain: app.config.cookie?.domain ?? // @ts-expect-error
|
|
validator?.cookie?.config.domain,
|
|
expires: app.config.cookie?.expires ?? // @ts-expect-error
|
|
validator?.cookie?.config.expires,
|
|
httpOnly: app.config.cookie?.httpOnly ?? // @ts-expect-error
|
|
validator?.cookie?.config.httpOnly,
|
|
maxAge: app.config.cookie?.maxAge ?? // @ts-expect-error
|
|
validator?.cookie?.config.maxAge,
|
|
// @ts-expect-error
|
|
path: app.config.cookie?.path ?? validator?.cookie?.config.path,
|
|
priority: app.config.cookie?.priority ?? // @ts-expect-error
|
|
validator?.cookie?.config.priority,
|
|
partitioned: app.config.cookie?.partitioned ?? // @ts-expect-error
|
|
validator?.cookie?.config.partitioned,
|
|
sameSite: app.config.cookie?.sameSite ?? // @ts-expect-error
|
|
validator?.cookie?.config.sameSite,
|
|
secure: app.config.cookie?.secure ?? // @ts-expect-error
|
|
validator?.cookie?.config.secure,
|
|
secrets: app.config.cookie?.secrets ?? // @ts-expect-error
|
|
validator?.cookie?.config.secrets,
|
|
// @ts-expect-error
|
|
sign: app.config.cookie?.sign ?? validator?.cookie?.config.sign
|
|
}, cookieHeaderValue = request.headers.get("cookie");
|
|
context.cookie = await (0, import_cookies.parseCookie)(
|
|
context.set,
|
|
cookieHeaderValue,
|
|
cookieMeta
|
|
);
|
|
const headerValidator = validator?.createHeaders?.();
|
|
headerValidator && injectDefaultValues(headerValidator, context.headers);
|
|
const paramsValidator = validator?.createParams?.();
|
|
paramsValidator && injectDefaultValues(paramsValidator, context.params);
|
|
const queryValidator = validator?.createQuery?.();
|
|
if (queryValidator && injectDefaultValues(queryValidator, context.query), hooks.transform)
|
|
for (let i = 0; i < hooks.transform.length; i++) {
|
|
const hook = hooks.transform[i];
|
|
let response2 = hook.fn(context);
|
|
if (response2 instanceof Promise && (response2 = await response2), response2 instanceof import_error.ElysiaCustomStatusResponse) {
|
|
const result = mapEarlyResponse(response2, context.set);
|
|
if (result)
|
|
return context.response = result;
|
|
}
|
|
hook.subType === "derive" && Object.assign(context, response2);
|
|
}
|
|
if (validator) {
|
|
if (headerValidator) {
|
|
const _header = structuredClone(context.headers);
|
|
for (const [key, value] of request.headers)
|
|
_header[key] = value;
|
|
if (validator.headers.Check(_header) === !1)
|
|
throw new import_error.ValidationError(
|
|
"header",
|
|
validator.headers,
|
|
_header
|
|
);
|
|
} else validator.headers?.Decode && (context.headers = validator.headers.Decode(context.headers));
|
|
if (paramsValidator?.Check(context.params) === !1)
|
|
throw new import_error.ValidationError(
|
|
"params",
|
|
validator.params,
|
|
context.params
|
|
);
|
|
if (validator.params?.Decode && (context.params = validator.params.Decode(context.params)), validator.query?.schema) {
|
|
let schema = validator.query.schema;
|
|
schema.$defs?.[schema.$ref] && (schema = schema.$defs[schema.$ref]);
|
|
const properties = (0, import_schema.getSchemaProperties)(schema);
|
|
if (properties)
|
|
for (const property of Object.keys(properties)) {
|
|
const value = properties[property];
|
|
(value.type === "array" || value.items?.type === "string") && typeof context.query[property] == "string" && context.query[property] && (context.query[property] = context.query[property].split(","));
|
|
}
|
|
}
|
|
if (queryValidator?.Check(context.query) === !1)
|
|
throw new import_error.ValidationError(
|
|
"query",
|
|
validator.query,
|
|
context.query
|
|
);
|
|
if (validator.query?.Decode && (context.query = validator.query.Decode(context.query)), validator.createCookie?.()) {
|
|
let cookieValue = {};
|
|
for (const [key, value] of Object.entries(context.cookie))
|
|
cookieValue[key] = value.value;
|
|
if (validator.cookie.Check(cookieValue) === !1)
|
|
throw new import_error.ValidationError(
|
|
"cookie",
|
|
validator.cookie,
|
|
cookieValue
|
|
);
|
|
validator.cookie?.Decode && (cookieValue = validator.cookie.Decode(
|
|
cookieValue
|
|
));
|
|
}
|
|
if (validator.createBody?.()?.Check(body) === !1)
|
|
throw new import_error.ValidationError("body", validator.body, body);
|
|
if (validator.body?.Decode) {
|
|
let decoded = validator.body.Decode(body);
|
|
decoded instanceof Promise && (decoded = await decoded), context.body = decoded?.value ?? decoded;
|
|
}
|
|
}
|
|
if (hooks.beforeHandle)
|
|
for (let i = 0; i < hooks.beforeHandle.length; i++) {
|
|
const hook = hooks.beforeHandle[i];
|
|
let response2 = hook.fn(context);
|
|
if (response2 instanceof Promise && (response2 = await response2), response2 instanceof import_error.ElysiaCustomStatusResponse) {
|
|
const result = mapEarlyResponse(response2, context.set);
|
|
if (result)
|
|
return context.response = result;
|
|
}
|
|
if (hook.subType === "resolve") {
|
|
Object.assign(context, response2);
|
|
continue;
|
|
}
|
|
if (response2 !== void 0) {
|
|
if (context.response = response2, hooks.afterHandle)
|
|
for (let i2 = 0; i2 < hooks.afterHandle.length; i2++) {
|
|
let newResponse = hooks.afterHandle[i2].fn(
|
|
context
|
|
);
|
|
newResponse instanceof Promise && (newResponse = await newResponse), newResponse && (response2 = newResponse);
|
|
}
|
|
const result = mapEarlyResponse(response2, context.set);
|
|
if (result) return context.response = result;
|
|
}
|
|
}
|
|
let response = typeof handle == "function" ? handle(context) : handle;
|
|
if (response instanceof Promise && (response = await response), hooks.afterHandle?.length) {
|
|
context.response = response;
|
|
for (let i = 0; i < hooks.afterHandle.length; i++) {
|
|
let response2 = hooks.afterHandle[i].fn(
|
|
context
|
|
);
|
|
response2 instanceof Promise && (response2 = await response2);
|
|
const isCustomStatuResponse = response2 instanceof import_error.ElysiaCustomStatusResponse, status2 = isCustomStatuResponse ? response2.code : set.status ? typeof set.status == "string" ? import_utils.StatusMap[set.status] : set.status : 200;
|
|
isCustomStatuResponse && (set.status = status2, response2 = response2.response);
|
|
const responseValidator = validator?.createResponse?.()?.[status2];
|
|
if (responseValidator?.Check(response2) === !1)
|
|
if (responseValidator?.Clean)
|
|
try {
|
|
const temp = responseValidator.Clean(response2);
|
|
if (responseValidator?.Check(temp) === !1)
|
|
throw new import_error.ValidationError(
|
|
"response",
|
|
responseValidator,
|
|
response2
|
|
);
|
|
response2 = temp;
|
|
} catch (error) {
|
|
throw error instanceof import_error.ValidationError ? error : new import_error.ValidationError(
|
|
"response",
|
|
responseValidator,
|
|
response2
|
|
);
|
|
}
|
|
else
|
|
throw new import_error.ValidationError(
|
|
"response",
|
|
responseValidator,
|
|
response2
|
|
);
|
|
if (responseValidator?.Encode && (context.response = response2 = responseValidator.Encode(response2)), responseValidator?.Clean)
|
|
try {
|
|
context.response = response2 = responseValidator.Clean(response2);
|
|
} catch {
|
|
}
|
|
const result = mapEarlyResponse(response2, context.set);
|
|
if (result !== void 0) return context.response = result;
|
|
}
|
|
} else {
|
|
const isCustomStatuResponse = response instanceof import_error.ElysiaCustomStatusResponse, status2 = isCustomStatuResponse ? response.code : set.status ? typeof set.status == "string" ? import_utils.StatusMap[set.status] : set.status : 200;
|
|
isCustomStatuResponse && (set.status = status2, response = response.response);
|
|
const responseValidator = validator?.createResponse?.()?.[status2];
|
|
if (responseValidator?.Check(response) === !1)
|
|
if (responseValidator?.Clean)
|
|
try {
|
|
const temp = responseValidator.Clean(response);
|
|
if (responseValidator?.Check(temp) === !1)
|
|
throw new import_error.ValidationError(
|
|
"response",
|
|
responseValidator,
|
|
response
|
|
);
|
|
response = temp;
|
|
} catch (error) {
|
|
throw error instanceof import_error.ValidationError ? error : new import_error.ValidationError(
|
|
"response",
|
|
responseValidator,
|
|
response
|
|
);
|
|
}
|
|
else
|
|
throw new import_error.ValidationError(
|
|
"response",
|
|
responseValidator,
|
|
response
|
|
);
|
|
if (responseValidator?.Encode && (response = responseValidator.Encode(response)), responseValidator?.Clean)
|
|
try {
|
|
response = responseValidator.Clean(response);
|
|
} catch {
|
|
}
|
|
}
|
|
if (context.set.cookie && cookieMeta?.sign) {
|
|
const secret = cookieMeta.secrets ? typeof cookieMeta.secrets == "string" ? cookieMeta.secrets : cookieMeta.secrets[0] : void 0;
|
|
if (cookieMeta.sign === !0) {
|
|
if (secret)
|
|
for (const [key, cookie] of Object.entries(
|
|
context.set.cookie
|
|
))
|
|
context.set.cookie[key].value = await (0, import_utils.signCookie)(
|
|
cookie.value,
|
|
secret
|
|
);
|
|
} else {
|
|
const properties = (0, import_schema.getSchemaProperties)(validator?.cookie?.schema);
|
|
if (secret)
|
|
for (const name of cookieMeta.sign)
|
|
!properties || !(name in properties) || context.set.cookie[name]?.value && (context.set.cookie[name].value = await (0, import_utils.signCookie)(
|
|
context.set.cookie[name].value,
|
|
secret
|
|
));
|
|
}
|
|
}
|
|
return mapResponse(context.response = response, context.set);
|
|
} catch (error) {
|
|
const reportedError = error instanceof import_value.TransformDecodeError && error.error ? error.error : error;
|
|
return app.handleError(context, reportedError);
|
|
} finally {
|
|
const afterResponses = hooks ? hooks.afterResponse : app.event.afterResponse;
|
|
afterResponses && (import_utils.hasSetImmediate ? setImmediate(async () => {
|
|
for (const afterResponse of afterResponses)
|
|
await afterResponse.fn(context);
|
|
}) : Promise.resolve().then(async () => {
|
|
for (const afterResponse of afterResponses)
|
|
await afterResponse.fn(context);
|
|
}));
|
|
}
|
|
};
|
|
}, createDynamicErrorHandler = (app) => {
|
|
const { mapResponse } = app["~adapter"].handler;
|
|
return async (context, error) => {
|
|
const errorContext = Object.assign(context, { error, code: error.code });
|
|
if (errorContext.set = context.set, // @ts-expect-error
|
|
typeof error?.toResponse == "function" && !(error instanceof import_error.ValidationError) && !(error instanceof import_value.TransformDecodeError))
|
|
try {
|
|
let raw = error.toResponse();
|
|
typeof raw?.then == "function" && (raw = await raw), raw instanceof Response && (context.set.status = raw.status), context.response = raw;
|
|
} catch {
|
|
}
|
|
if (!context.response && app.event.error)
|
|
for (let i = 0; i < app.event.error.length; i++) {
|
|
let response = app.event.error[i].fn(errorContext);
|
|
if (response instanceof Promise && (response = await response), response != null)
|
|
return context.response = mapResponse(
|
|
response,
|
|
context.set
|
|
);
|
|
}
|
|
if (context.response) {
|
|
if (app.event.mapResponse)
|
|
for (let i = 0; i < app.event.mapResponse.length; i++) {
|
|
let response = app.event.mapResponse[i].fn(errorContext);
|
|
response instanceof Promise && (response = await response), response != null && (context.response = response);
|
|
}
|
|
return mapResponse(context.response, context.set);
|
|
}
|
|
return context.set.status = error.status ?? 500, mapResponse(
|
|
typeof error.cause == "string" ? error.cause : error.message,
|
|
context.set
|
|
);
|
|
};
|
|
};
|
|
// Annotate the CommonJS export names for ESM import in node:
|
|
0 && (module.exports = {
|
|
createDynamicErrorHandler,
|
|
createDynamicHandler
|
|
});
|