UNPKG

elysia

Version:

Ergonomic Framework for Human

431 lines (430 loc) 20.4 kB
"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_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 });