elysia
Version:
Ergonomic Framework for Human
431 lines (430 loc) • 20.4 kB
JavaScript
;
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_utils = require('./utils.js');
const injectDefaultValues = (typeChecker, obj) => {
let schema = typeChecker.schema;
if (schema && (schema.$defs?.[schema.$ref] && (schema = schema.$defs[schema.$ref]), !!schema?.properties))
for (const [key, keySchema] of Object.entries(schema.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;
hooks = handler.store.hooks;
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);
value.length === 1 ? body[key] = value[0] : body[key] = value;
}
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);
value.length === 1 ? body[key] = value[0] : body[key] = value;
}
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);
value.length === 1 ? body[key] = value[0] : body[key] = value;
}
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 = schema.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);
validator.body?.Decode && (context.body = validator.body.Decode(body));
}
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) {
const temp = responseValidator.Clean(response2);
if (responseValidator?.Check(temp) === !1)
throw new import_error.ValidationError(
"response",
responseValidator,
response2
);
response2 = temp;
} else
throw new import_error.ValidationError(
"response",
responseValidator,
response2
);
responseValidator?.Encode && (context.response = response2 = responseValidator.Encode(response2)), responseValidator?.Clean && (context.response = response2 = responseValidator.Clean(response2));
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) {
const temp = responseValidator.Clean(response);
if (responseValidator?.Check(temp) === !1)
throw new import_error.ValidationError(
"response",
responseValidator,
response
);
response = temp;
} else
throw new import_error.ValidationError(
"response",
responseValidator,
response
);
responseValidator?.Encode && (response = responseValidator.Encode(response)), responseValidator?.Clean && (response = responseValidator.Clean(response));
}
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 = validator?.cookie?.schema?.properties;
if (secret)
for (const name of cookieMeta.sign)
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
});