"use strict"; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __name = (target, value) => __defProp(target, "name", { value, configurable: true }); var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__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: true }), mod); // src/index.ts var src_exports = {}; __export(src_exports, { BaseRouter: () => BaseRouter, FileLike: () => FileLike, IncludesRouter: () => IncludesRouter, MethodsRouter: () => MethodsRouter, Middleware: () => Middleware, Request: () => Request, Response: () => Response, ServerAdapter: () => ServerAdapter, ServerDomain: () => serverDomain, ServerRequestAdapter: () => ServerRequestAdapter, ServerResponseAdapter: () => ServerResponseAdapter, ServerRouterAdapter: () => ServerRouterAdapter, Serverless: () => Serverless, ServerlessAdapter: () => ServerlessAdapter, ServerlessRouterAdapter: () => ServerlessRouterAdapter, default: () => serverDomain, formDataLikeFactory: () => formDataLikeFactory, middleware: () => middleware, nestedMiddleware: () => nestedMiddleware, path: () => path, pathNested: () => pathNested, requestMiddleware: () => requestMiddleware, serverAdapter: () => serverAdapter, serverDomainModifier: () => serverDomainModifier, serverRequestAdapter: () => serverRequestAdapter, serverResponseAdapter: () => serverResponseAdapter, serverRouterAdapter: () => serverRouterAdapter, serverlessAdapter: () => serverlessAdapter, serverlessRouterAdapter: () => serverlessRouterAdapter, status: () => status_exports }); module.exports = __toCommonJS(src_exports); // src/request/utils.ts function parseParamsValue(value, type) { if (type.regex && !type.regex.test(value)) return void 0; if (type.type.includes("string") && typeof value === "string") return value; else if (type.type.includes("string") && typeof value !== "string") { if (value !== void 0 && value !== null) return String(value); else return void 0; } else if (type.type.includes("number") && typeof value === "number") return value; else if (type.type.includes("number") && typeof value !== "number") { const numberValidatorRegex = /^[\d]+((\.{1})?[\d]+)?$/g; if (value !== void 0 && value !== null && numberValidatorRegex.test(value.toString())) return Number(value); else return void 0; } else if (type.type.includes("boolean") && typeof value === "boolean") return value; else if (type.type.includes("boolean") && typeof value !== "boolean") return Boolean(value); return void 0; } __name(parseParamsValue, "parseParamsValue"); function parseQueryParams(value, type) { if (type.isArray && Array.isArray(value)) return value.map((valueToParse) => parseParamsValue(valueToParse, type)); else if (type.isArray && !Array.isArray(value)) return [ parseParamsValue(value, type) ]; else return parseParamsValue(value, type); } __name(parseQueryParams, "parseQueryParams"); function formDataLikeFactory() { return class FormDataLike { static { __name(this, "FormDataLike"); } $$type = "$PFormDataLike"; proxyCallback; data; /** * Instead of the default FormData constructor, this one will create a FormData-like object. You can pass a * proxyCallback to it, this way you can lazy load the values of the form data. * * @param proxyCallback - A callback that will be called when a value is needed. This way you can lazy load the * values of the form data. */ constructor(proxyCallback) { this.proxyCallback = proxyCallback; this.data = proxyCallback ? new Proxy({}, { get: /* @__PURE__ */ __name((target, name) => { if (name in target) return target[name]; else { const values = proxyCallback.getValue(name); if (!values) return void 0; for (const value of values || []) { if (value) { if (target[name]) target[name].push(value); else target[name] = [ value ]; } } return target[name]; } }, "get"), set: /* @__PURE__ */ __name((target, name, value) => { target[name] = value; return true; }, "set"), deleteProperty: /* @__PURE__ */ __name((target, name) => { delete target[name]; return true; }, "deleteProperty"), has: /* @__PURE__ */ __name((target, name) => { return name in target; }, "has") }) : {}; } append(name, value, fileName) { const existingDataOfName = this.data[name]; if (existingDataOfName) existingDataOfName.push({ value, fileName }); else this.data[name] = [ { value, fileName } ]; } get(name) { const existingDataOfName = this.data[name]; if (existingDataOfName) return existingDataOfName[0]?.value || null; else return null; } getAll(name) { const existingDataOfName = this.data[name]; if (existingDataOfName) return existingDataOfName.map((item) => item.value); else return []; } has(name) { return name in this.data; } set(name, value, fileName) { this.data[name] = [ { value, fileName } ]; } delete(name) { delete this.data[name]; } /** * Converts the form data like object to a json object, this way it can be validated by schemas or anything else. * * Important: Be aware that this function will only return the first value of each key, if you want to get all * values of a key use getAll instead. */ toJSON() { const allKeys = this.proxyCallback?.getKeys() || Object.keys(this.data); const result = {}; for (const key of allKeys) { const values = this.getAll(key); if (values.length > 1) result[key] = values; else if (values.length === 1) result[key] = values[0]; } return result; } }; } __name(formDataLikeFactory, "formDataLikeFactory"); // src/adapters/requests/class.ts var ServerRequestAdapter = class { static { __name(this, "ServerRequestAdapter"); } /** * This should return the full concatenated url of the request, with domain and path. * * @example * ```ts * import { Request } from 'express'; * * url: (_, serverRequestAndResponseData: { req: Request }) => { * const { req } = serverRequestAndResponseData; * return `${req.protocol}://${req.get('host')}${req.originalUrl}`; * }, * ``` * * @param _server - The {@link ServerAdapter} or {@link ServerlessAdapter} instance. * @param _serverRequestAndResponseData - The server request and response data that you have defined on {@link ServerRouterAdapter.parseHandler} or * {@link ServerRouterAdapter.parseHandlers} on the router. */ url(_server, _serverRequestAndResponseData) { return ""; } /** * Translates the headers from the server request to the headers of the request to the API. This is lazy loaded, so it will only parse the headers when the user actually needs it. * In other words, it is a proxy, so you just need to extract each value of the header one by one. What is expected is the user to pass the key of the header like that: * https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers * * We don't make assumptions so we do not transform it to lowerCase by default. Depending of your framework you are totally free to do this for better parsing. * * @example * ```ts * import { Request } from 'express'; * * headers: (_, serverRequestAndResponseData: { req: Request }, key) => { * const lowerCasedKey = key.toLowerCase(); * const { req } = serverRequestAndResponseData; * * return req.headers[lowerCasedKey]; * }, * ``` * * @param _server - The {@link ServerAdapter} or {@link ServerlessAdapter} instance. * @param _serverRequestAndResponseData - The server request and response data that you have defined on {@link ServerRouterAdapter.parseHandler} or * {@link ServerRouterAdapter.parseHandlers} on the router. * @param _key - The key of the header that the user wants to extract. * * @returns - The value of the header if it exists, otherwise undefined. */ headers(_server, _serverRequestAndResponseData, _key) { return void 0; } /** * This should return the method of the request. Casing doesn't matter, it should just follow this guide: https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods * * @example * ```ts * import { Request } from 'express'; * * method: (_server, serverRequestAndResponseData) => { * const { req } = serverRequestAndResponseData as { req: Request }; * return req.method; * }, * ``` * * @param _server - The {@link ServerAdapter} or {@link ServerlessAdapter} instance. * @param _serverRequestAndResponseData - The server request and response data that you have defined on {@link ServerRouterAdapter.parseHandler} or * {@link ServerRouterAdapter.parseHandlers} on the router. * * @returns - The method of the request. */ method(_server, _serverRequestAndResponseData) { return ""; } /** * Translates the params from the server request to the params of the request to the API. This is lazy loaded, so it will only parse the params when the user actually needs it. * In other words, it is a proxy, so you just need to extract each value of the param one by one. What is expected is the user to pass the key of the param like that: * https://expressjs.com/en/4x/api.html#req.params * * You don't need to worry about parsing, we parse it on our side, but if you do parse, no problem, we will just ignore parsing on our end. But please note that this might * introduce unexpected behavior to users. So make sure to document it. * * @example * ```ts * import { Request } from 'express'; * * params: (_, serverRequestAndResponseData: { req: Request }, key) => { * const { req } = serverRequestAndResponseData; * return req.params[key]; * }, * ``` * * @param _server - The {@link ServerAdapter} or {@link ServerlessAdapter} instance. * @param _serverRequestAndResponseData - The server request and response data that you have defined on {@link ServerRouterAdapter.parseHandler} or * {@link ServerRouterAdapter.parseHandlers} on the router. * @param _key - The key of the param that the user wants to extract. * * @returns - The value of the param if it exists, otherwise undefined. */ params(_server, _serverRequestAndResponseData, _key) { return void 0; } /** * Translates the query from the server request to the query of the request to the API. This is lazy loaded, so it will only parse the query when the user actually needs it. * In other words, it is a proxy, so you just need to extract each value of the query one by one. What is expected is the user to pass the key of the query like that: * https://expressjs.com/en/4x/api.html#req.query * * You don't need to worry about parsing, we parse it on our side, but if you do parse, no problem, we will just ignore parsing on our end. But please note that this might * introduce unexpected behavior to users. So make sure to document it. * * @example * ```ts * import { Request } from 'express'; * * query: (_, serverRequestAndResponseData: { req: Request }, key) => { * const { req } = serverRequestAndResponseData; * return req.query[key]; * }, * ``` * * @param _server - The {@link ServerAdapter} or {@link ServerlessAdapter} instance. * @param _serverRequestAndResponseData - The server request and response data that you have defined on {@link ServerRouterAdapter.parseHandler} or * {@link ServerRouterAdapter.parseHandlers} on the router. * @param _key - The key of the query that the user wants to extract. * * @returns - The value of the query if it exists, otherwise undefined. */ query(_server, _serverRequestAndResponseData, _key) { return void 0; } /** * When the request is a `application/json` request, this should return the parsed json. This is called when the user calls the {@link Request.json} method. * * If you want to let users pass custom options to the {@link Request.json} method, you can override the {@link customToJsonOptions} static method. * The user will then need to call this method (for intellisense) in order to pass custom options. * * @example * ```ts * import express, { Request } from 'express'; * * toJson: (_, serverRequestAndResponseData: { req: Request }, options: Parameters) => { * const { req } = serverRequestAndResponseData; * * return new Promise((resolve) => { * express.json(options)(req, undefined, () => { * resolve(req.body); * }); * }); * }, * ``` * * @param _server - The {@link ServerAdapter} or {@link ServerlessAdapter} instance. * @param _serverRequestAndResponseData - The server request and response data that you have defined on {@link ServerRouterAdapter.parseHandler} or * {@link ServerRouterAdapter.parseHandlers} on the router. * @param _options - Any type of custom options that you want to be able to pass when converting to json. If you want to support custom options, please override the * {@link customToJsonOptions} static method. * * @returns - A promise that resolves to the parsed json. */ toJson(_server, _serverRequestAndResponseData, _options) { return new Promise((resolve) => resolve(void 0)); } /** * This should return something when the request Content-Type is a `multipart/form-data` or `application/x-www-form-urlencoded` request. This is lazy loaded, so * it will only parse the data when you actually need it. * Transforms the data to a FormData-like instance. FormData is not available on Node.js and other runtimes, so in order to support it we have created a FormData-like class that * follows the same api as the original FormData. * * see: https://developer.mozilla.org/en-US/docs/Web/API/FormData * * Because it's a custom class, we add some useful stuff like the ability to lazy load the data, so it will only parse the data when you actually need it. * * @example * ```ts * import express, { Request } from 'express'; * * toFormData: (server, serverRequestAndResponseData, formDataConstructor, isUrlEncoded, options) => { * const serverInstanceAndSettings = servers.get(server.serverName); * const { req, res } = serverRequestAndResponseData as { req: Request; res: Response }; * * return new Promise((resolve) => { * let formDataOrUrlEncodedParser = isUrlEncoded * ? serverInstanceAndSettings?.urlEncodedParser * : serverInstanceAndSettings?.formDataParser; * * if (isUrlEncoded && serverInstanceAndSettings && !serverInstanceAndSettings?.urlEncodedParser) { * const urlEncodedParserSettings = serverInstanceAndSettings.settings.customServerSettings?.urlEncodedOptions; * * serverInstanceAndSettings.urlEncodedParser = express.urlencoded({ * ...urlEncodedParserSettings, * extended: true, * }); * formDataOrUrlEncodedParser = serverInstanceAndSettings.urlEncodedParser; * } else if (serverInstanceAndSettings && !serverInstanceAndSettings?.formDataParser) { * const formDataParserSettings = serverInstanceAndSettings.settings.customServerSettings?.multerOptions; * * serverInstanceAndSettings.formDataParser = multer(formDataParserSettings); * formDataOrUrlEncodedParser = serverInstanceAndSettings.formDataParser; * } * * let middleware: * | ReturnType * | ReturnType[keyof ReturnType]> * | undefined = undefined; * if (isUrlEncoded && !formDataOrUrlEncodedParser) formDataOrUrlEncodedParser = express.urlencoded({ extended: true }); * else if (!isUrlEncoded && !formDataOrUrlEncodedParser) formDataOrUrlEncodedParser = multer(); * * const optionsOfParser = (options?.options || []) as any[]; * if (!isUrlEncoded) { * const formDataParser = formDataOrUrlEncodedParser as ReturnType; * if (options && !isUrlEncoded) middleware = (formDataParser[options.type as keyof ReturnType] as any)(...optionsOfParser); * if (!middleware) middleware = formDataParser.any(); * } else middleware = formDataOrUrlEncodedParser as ReturnType; * * middleware(req, res, () => { * const formData = new formDataConstructor({ * getKeys: () => { * const bodyKeys = Object.keys(req.body || {}) || []; * if (req?.files) { * if (Array.isArray(req.files)) { * for (const file of req.files) bodyKeys.push(file.fieldname); * } else bodyKeys.push(...Object.keys(req.files)); * } * if (req?.file) bodyKeys.push(req.file.fieldname); * return bodyKeys; * }, * getValue: (name) => { * const bodyKeys = Object.keys(req.body || {}); * for (const key of bodyKeys) { * if (key === name) * return [ * { * value: req.body[key], * filename: undefined, * }, * ]; * } * * if (req?.files) { * if (Array.isArray(req.files)) { * const files = []; * for (const file of req.files) { * if (file.fieldname === name) * files.push({ * value: new File([file.buffer], file.originalname, { type: file.mimetype }), * filename: file.originalname, * }); * } * return files; * } else { * const files = req.files[name]; * const filesArray = []; * * for (const file of files) { * if (file.fieldname === name) * filesArray.push({ * value: new File([file.buffer], file.originalname, { type: file.mimetype }), * filename: file.originalname, * }); * } * return filesArray; * } * } * * if (req?.file) * if (req.file.fieldname === name) * return [ * { * value: new File([req.file.buffer], req.file.originalname, { type: req.file.mimetype }), * filename: req.file.originalname, * }, * ]; * return []; * }, * }); * resolve(formData); * }); * }); * } * ``` * * @param _server - The {@link ServerAdapter} or {@link ServerlessAdapter} adapter. * @param _serverRequestAndResponseData - The server request and response data that you have defined on {@link ServerRouterAdapter.parseHandler} or * {@link ServerRouterAdapter.parseHandlers} on the router. * @param _formDataConstructor - The constructor of the FormData-like class. It's a class so you should use it like this: `new formDataConstructor()`. You can pass a custom * proxyCallback, this will lazy load the values when you actually need it. {@link FormDataLike} * @param _isUrlEncoded - Whether or not the request is a `application/x-www-form-urlencoded` request. If not, it's a `multipart/form-data` request. * @param _options - Any type of custom options that you want to be able to pass when converting to FormData. If you want to support custom options, please override the * {@link customToFormDataOptions} static method. * * @returns -A promise that resolves to a FormData-like instance. */ toFormData(_server, _serverRequestAndResponseData, _formDataConstructor, _isUrlEncoded, _options) { new _formDataConstructor(); return new Promise((resolve) => resolve(new (formDataLikeFactory())())); } /** * This should return the parsed ArrayBuffer of the request. This is called when the user calls the {@link Request.arrayBuffer} method. * * If you want to let users pass custom options to the {@link Request.arrayBuffer} method, you can override the {@link customToArrayBufferOptions} static method. * The user will then need to call this method (for intellisense) in order to pass custom options. * * @example * ```ts * import express, { Request } from 'express'; * * toArrayBuffer: (_, serverRequestAndResponseData: { req: Request }, options: Parameters) => { * const { req } = serverRequestAndResponseData; * return new Promise((resolve) => { * express.raw(options)(req, undefined, () => { * resolve(new ArrayBuffer([req.body])); * }); * }); * }, * ``` * * @param _server - The {@link ServerAdapter} or {@link ServerlessAdapter} instance. * @param _serverRequestAndResponseData - The server request and response data that you have defined on {@link ServerRouterAdapter.parseHandler} or * {@link ServerRouterAdapter.parseHandlers} on the router. * @param _options - Any type of custom options that you want to be able to pass when converting to ArrayBuffer. If you want to support custom options, please override the * {@link customToArrayBufferOptions} static method. * * @returns - A promise that resolves to the parsed ArrayBuffer. */ toArrayBuffer(_server, _serverRequestAndResponseData, _options) { return new Promise((resolve) => resolve(void 0)); } /** * This should return the parsed Blob of the request. This is called when the user calls the {@link Request.blob} method. * If you want to let users pass custom options to the {@link Request.blob} method, you can override the {@link customToBlobOptions} static method. * The user will then need to call this method (for intellisense) in order to pass custom options. A File instance can also be returned since it's generally more descriptive. * * @example * ```ts * import express, { Request } from 'express'; * * toBlob: (_, serverRequestAndResponseData: { req: Request }, options: Parameters) => { * const { req } = serverRequestAndResponseData; * return new Promise((resolve) => { * express.raw(options)(req, undefined, () => { * resolve(new Blob([req.body])); * }); * }); * }, * ``` * * @param _server - The {@link ServerAdapter} or {@link ServerlessAdapter} instance. * @param _serverRequestAndResponseData - The server request and response data that you have defined on {@link ServerRouterAdapter.parseHandler} or * {@link ServerRouterAdapter.parseHandlers} on the router. * @param _options - Any type of custom options that you want to be able to pass when converting to Blob. If you want to support custom options, please override the * {@link customToBlobOptions} static method. * * @returns - A promise that resolves to the parsed Blob. */ toBlob(_server, _serverRequestAndResponseData, _options) { return new Promise((resolve) => resolve(void 0)); } /** * This should return the parsed raw data of the request. This is called when the user calls the {@link Request.raw} method. This should just return whatever you have on the body * of the request. You don't need to parse or anything like that. * * If you want to let users pass custom options to the {@link Request.raw} method, you can override the {@link customToRawOptions} static method. * The user will then need to call this method (for intellisense) in order to pass custom options. * * @example * ```ts * import express, { Request } from 'express'; * * toRaw: (_, serverRequestAndResponseData: { req: Request }, options: Parameters) => { * const { req } = serverRequestAndResponseData; * return new Promise((resolve) => { * express.raw(options)(req, undefined, () => { * resolve(req.body); * }); * }); * }, * ``` * * @param _server - The {@link ServerAdapter} or {@link ServerlessAdapter} instance. * @param _serverRequestAndResponseData - The server request and response data that you have defined on {@link ServerRouterAdapter.parseHandler} or * {@link ServerRouterAdapter.parseHandlers} on the router. * @param _options - Any type of custom options that you want to be able to pass when converting to raw. If you want to support custom options, please override the * {@link customToRawOptions} static method. * * @returns - A promise that resolves to the parsed raw data. */ toRaw(_server, _serverRequestAndResponseData, _options) { return new Promise((resolve) => resolve(void 0)); } /** * Translates the request to a string. Should be used for text/plain requests. * * If you want to let users pass custom options to the {@link Request.text} method, you can override the {@link customToTextOptions} static method. * The user will then need to call this method (for intellisense) in order to pass custom options. * * @example * ```ts * import express, { Request } from 'express'; * * toText: (_, serverRequestAndResponseData: { req: Request }, options: Parameters) => { * const { req } = serverRequestAndResponseData; * return new Promise((resolve) => { * express.text(options)(req, undefined, () => { * resolve(req.body); * }); * }); * }, * ``` * * @param _server - The {@link ServerAdapter} or {@link ServerlessAdapter} instance. * @param _serverRequestAndResponseData - The server request and response data that you have defined on {@link ServerRouterAdapter.parseHandler} or * {@link ServerRouterAdapter.parseHandlers} on the router. * @param _options - Any type of custom options that you want to be able to pass when converting to raw. If you want to support custom options, please override the * {@link customToTextOptions} static method. * * @returns A promise that resolves to a string. */ toText(_server, _serverRequestAndResponseData, _options) { return new Promise((resolve) => resolve(void 0)); } /** * If you want to pass custom options to the `toFormData` method, you can override this method, the user will need to call this method so he can have intellisense on the options. * * You can totally ignore this method and just pass the options directly to the `toFormData` method. * * @param args - The arguments that you want to pass to the `toFormData` method. */ static customToFormDataOptions(args) { return args; } static customToJsonOptions(args) { return args; } static customToTextOptions(args) { return args; } static customToBlobOptions(args) { return args; } static customToArrayBufferOptions(args) { return args; } static customToRawOptions(args) { return args; } }; // src/adapters/requests/function.ts function serverRequestAdapter(args) { let CustomServerRequestAdapter = class CustomServerRequestAdapter extends ServerRequestAdapter { static { __name(this, "CustomServerRequestAdapter"); } url = args.url; method = args.method; headers = args.headers; params = args.params; query = args.query; toJson = args.toJson; static customToJsonOptions = args.customToJsonOptions || ServerRequestAdapter.customToJsonOptions; toFormData = args.toFormData; static customToFormDataOptions = args.customToFormDataOptions || ServerRequestAdapter.customToFormDataOptions; toArrayBuffer = args.toArrayBuffer; static customToArrayBufferOptions = args.customToArrayBufferOptions || ServerRequestAdapter.customToArrayBufferOptions; toBlob = args.toBlob; static customToBlobOptions = args.customToBlobOptions || ServerRequestAdapter.customToBlobOptions; toText = args.toText; static customToTextOptions = args.customToTextOptions || ServerRequestAdapter.customToTextOptions; toRaw = args.toRaw; static customToRawOptions = args.customToRawOptions || ServerRequestAdapter.customToRawOptions; }; return CustomServerRequestAdapter; } __name(serverRequestAdapter, "serverRequestAdapter"); // src/adapters/response.ts function serverResponseAdapter(args) { let CustomServerResponseAdapter = class CustomServerResponseAdapter extends ServerResponseAdapter { static { __name(this, "CustomServerResponseAdapter"); } stream = args.stream; sendFile = args.sendFile; redirect = args.redirect; send = args.send; }; return CustomServerResponseAdapter; } __name(serverResponseAdapter, "serverResponseAdapter"); var ServerResponseAdapter = class { static { __name(this, "ServerResponseAdapter"); } /** * This function is used for handling redirects. * * @param _server The {@link ServerAdapter} or {@link ServerlessAdapter} adapter. * @param _serverRequestAndResponseData The server request and response data. * @param _status The status code of the response. * @param _headers The headers of the response. * @param _redirectTo The redirect url. * * @returns - A promise that resolves with the data needed for redirection. This data is the data that will be returned from the callback on * {@link ServerRouterAdapter.parseHandler} or {@link ServerRouterAdapter.parseHandlers}. */ // eslint-disable-next-line ts/require-await async redirect(_server, _serverRequestAndResponseData, _status, _headers, _redirectTo) { return void 0; } /** * This function is used for handling sending data to the client. * * @param _server The {@link ServerAdapter} or {@link ServerlessAdapter} adapter. * @param _serverRequestAndResponseData The server request and response data. * @param _status The status code of the response. * @param _headers The headers of the response. * @param _body The body of the response. * * @returns A promise that resolves with the data needed for sending the response. */ // eslint-disable-next-line ts/require-await async send(_server, _serverRequestAndResponseData, _status, _headers, _body) { return void 0; } // eslint-disable-next-line ts/require-await async stream(_server, _serverRequestAndResponseData, _status, _headers, _body, _isAsync) { return void 0; } // eslint-disable-next-line ts/require-await async sendFile(_server, _serverRequestAndResponseData, _status, _headers, _filePath) { return void 0; } }; // src/adapters/routers/index.ts function serverRouterAdapter(args) { let CustomServerRouterAdapter = class CustomServerRouterAdapter extends ServerRouterAdapter { static { __name(this, "CustomServerRouterAdapter"); } parseRoute = args.parseRoute; parseHandler = args.parseHandler; parseHandlers = args.parseHandlers; load404 = args.load404; }; return CustomServerRouterAdapter; } __name(serverRouterAdapter, "serverRouterAdapter"); var ServerRouterAdapter = class { static { __name(this, "ServerRouterAdapter"); } /** * This method is used for loading a 405 handler, this will only be called if no handler is found for the requested method. * * IMPORTANT: If you define a route handler OUTSIDE of palmares and we do not find the route, this will still be called, because this is defined by your framework of choice. * * @example * ```ts * load404(server, handler) { * const initializedServer = servers.get(server.serverName)?.server; * if (initializedServer) { * initializedServer.use((req, res) => { * const serverRequestAndResponseData = { * req, * res, * }; * handler(serverRequestAndResponseData); * }); * } * }, * ``` * * @param _server - The {@link ServerAdapter} or {@link ServerlessAdapter} instance. * @param _handler - The handler is a simple callback function that receives a single parameter as argument. Whatever you pass on this parameter can later be retrieved inside of * {@link ServerResponseAdapter} and {@link ServerRequestAdapter} methods. */ // eslint-disable-next-line ts/require-await async load404(_server, _handler) { return void 0; } /** * Used for parsing each part of the route, instead of parsing the whole route all at once, the framework itself will call this method for each part of the route. * * n this example we are parsing the route and following Express's route syntax, like /users/:id, /users/:id/posts, /users/:id/posts/:postId, etc. So each url param will contain * a colon before the name of the param. * * @example * ```ts * parseRoute(server, partOfPath, urlParamType) { * if (urlParamType) return ':${partOfPath}`; * else return partOfPath; * }, * ``` * * @param _server - The {@link ServerAdapter} or {@link ServerlessAdapter} instance. * @param _partOfPath - The part of the path to be parsed. * @param _urlParamType - If the part of the path is a url param, this will be true, otherwise it will be false. * * @returns The parsed part of the path. */ parseRoute(_server, _partOfPath, _urlParamType) { return void 0; } /** * Usually {@link parseHandlers()} is preferred, but if your framework supports all methods from the {@link MethodTypes} enum, you can use this method instead. * This method is used to parse one handler at a time. * * IMPORTANT: Don't forget to handle the `all` method, so it can be used to accept all methods. * * @example * ```ts * parseHandler(server, path, method, handler, queryParams) { * const initializedServer = servers.get(server.serverName)?.server; * if (initializedServer) { * initializedServer[method](path, (req: Request, res: Response) => { * const serverRequestAndResponseData = { * req, * res, * }; * handler(serverRequestAndResponseData); * }); * } * }, * ``` * * @param _server - The {@link ServerAdapter} or {@link ServerlessAdapter} instance. * @param _path - The retrieved by calling {@link parseRoute()} method. * @param _method - The method to be used. * @param _handler - The handler is a simple callback function that receives a single parameter as argument. Whatever you pass on this parameter can later be retrieved inside of * {@link ServerResponseAdapter} and {@link ServerRequestAdapter} methods. What you return on {@link ServerResponseAdapter.redirect} or {@link ServerResponseAdapter.send} will be * the return value of this method. * @param _queryParams - The query params so you can parse it and validate as you wish. */ parseHandler(_server, _path, _method, _handler, _options, _queryParams) { return void 0; } parseHandlers(_server, _path, _methodsAndHandlers, _queryParams, _404Handler) { return void 0; } }; // src/adapters/index.ts function serverAdapter(args) { let CustomServerAdapter = class CustomServerAdapter extends ServerAdapter { static { __name(this, "CustomServerAdapter"); } request = args.request; response = args.response; routers = args.routers; load = args.load; start = args.start; close = args.close; static customServerSettings = args.customServerSettings; }; return CustomServerAdapter; } __name(serverAdapter, "serverAdapter"); var ServerAdapter = class { static { __name(this, "ServerAdapter"); } $$type = "$PServerAdapter"; serverName; settings; allSettings; domains; routers = new ServerRouterAdapter(); request = new ServerRequestAdapter(); response = new ServerResponseAdapter(); constructor(serverName, allSettings, settings, domains) { this.serverName = serverName; this.settings = settings; this.allSettings = allSettings; this.domains = domains; } /** * This is the function that will be called by Palmares to load the server. Usually you add the * server constructor here. Notice that this function DOES NOT start the server, it will be used * for adding middleware, custom logic, etc. * * You can use a global Map to store the server instance, this way you can access it later on the * start function. Since this is functional and not class based. * * @example * ``` * load: async (serverName, _domains: Domain[], settings: ServerSettingsTypeExpress) => { * let server: Express | undefined = servers.get(serverName)?.server; * if (!server) { * server = express(); * servers.set(serverName, { server, settings }); * } * if (settings?.customServerSettings?.middlewares) { * settings.customServerSettings.middlewares.forEach((middleware) => { * server?.use(middleware); * }); * } * }, * ``` * * @param serverName - The name of the server, by default a palmares application can contain multiple servers. * @param domains - All of the domains of the application, usually you will not need this, but can be useful. * @param settings - The settings for the server. */ // eslint-disable-next-line ts/require-await async load(_serverName, _domains, _settings) { return void 0; } /** * This is the function that will be called by Palmares to start the server. Usually you start the server here. * Most servers have a `.listen`, that's what you will call here. * * Use the logServerStart function to log to the user that the server has started. * * @example * ``` * start: async (serverName, port, logServerStart) => { * const serverInstanceToStart = servers.get(serverName); * if (serverInstanceToStart) { * serverInstanceToStart.server.listen(port, () => logServerStart()); * } * }, * ``` * * @param serverName - The name of the server, by default a palmares application can contain multiple servers. * @param port - The port to start the server on. * @param logServerStart - A function that you can call to log to the user that the server has started. */ // eslint-disable-next-line ts/require-await async start(_serverName, _port, _logServerStart) { return void 0; } /** * Custom function to call when we receive a SIGINT or SIGTERM signal. With that you can close the server gracefully. * * @example * ``` * close: async () => { * console.log('closing the server'); * }, * ``` */ // eslint-disable-next-line ts/require-await async close() { return void 0; } static customServerSettings(args) { return args; } }; // src/adapters/routers/serverless.ts function serverlessRouterAdapter(args) { let CustomServerRouterAdapter = class CustomServerRouterAdapter extends ServerlessRouterAdapter { static { __name(this, "CustomServerRouterAdapter"); } parseRoute = args.parseRoute; parseHandlers = args.parseHandlers; load404 = args.load404; }; return CustomServerRouterAdapter; } __name(serverlessRouterAdapter, "serverlessRouterAdapter"); var ServerlessRouterAdapter = class { static { __name(this, "ServerlessRouterAdapter"); } /** * This method is used for loading a 405 handler, this will only be called if no handler is found for the requested method. * * IMPORTANT: If you define a route handler OUTSIDE of palmares and we do not find the route, this will still be called, because this is defined by your framework of choice. * * @example * ```ts * load404(server, handler) { * const initializedServer = servers.get(server.serverName)?.server; * if (initializedServer) { * initializedServer.use((req, res) => { * const serverRequestAndResponseData = { * req, * res, * }; * handler(serverRequestAndResponseData); * }); * } * }, * ``` * * @param _server - The {@link ServerAdapter} or {@link ServerlessAdapter} instance. * @param _handler - The handler is a simple callback function that receives a single parameter as argument. Whatever you pass on this parameter can later be retrieved inside of * {@link ServerResponseAdapter} and {@link ServerRequestAdapter} methods. */ // eslint-disable-next-line ts/require-await async load404(_server, _handler) { return void 0; } /** * This method is used for loading a 500 handler, this handler will be called when an error occurs during the request/response lifecycle. * * IMPORTANT: If you define a route handler OUTSIDE of palmares and an error occurs in the handler, this method will not be called. * * @example * ```ts * load500(server, handler) { * const initializedServer = servers.get(server.serverName)?.server; * if (initializedServer) { * initializedServer.use((req, res) => { * const serverRequestAndResponseData = { * req, * res, * }; * handler(serverRequestAndResponseData); * }); * } * }, * ``` * * @param _server - The {@link ServerAdapter} or {@link ServerlessAdapter} instance. * @param _handler - The handler is a simple callback function that receives a single parameter as argument. Whatever you pass on this parameter can later be retrieved inside of * {@link ServerResponseAdapter} and {@link ServerRequestAdapter} methods. */ // eslint-disable-next-line ts/require-await async load500(_server, _handler) { return void 0; } /** * Used for parsing each part of the route, instead of parsing the whole route all at once, the framework itself will call this method for each part of the route. * * n this example we are parsing the route and following Express's route syntax, like /users/:id, /users/:id/posts, /users/:id/posts/:postId, etc. So each url param will contain * a colon before the name of the param. * * @example * ```ts * parseRoute(server, partOfPath, urlParamType) { * if (urlParamType) return ':${partOfPath}`; * else return partOfPath; * }, * ``` * * @param _server - The {@link ServerAdapter} or {@link ServerlessAdapter} instance. * @param _partOfPath - The part of the path to be parsed. * @param _urlParamType - If the part of the path is a url param, this will be true, otherwise it will be false. * * @returns The parsed part of the path. */ parseRoute(_server, _partOfPath, _urlParamType) { return void 0; } /** * Use this method if you want to parse all handlers at once. Parse all handlers at once is ofter useful if your framework doesn't support the same methods as us. With this * method you can loop through each handler and parse it or you can listen to all methods and parse them during the request/response lifecycle. * * Important: if this method is defined, {@link parseHandler()} will be ignored. * * @param _server - The {@link ServerlessAdapter} instance. * @param _path - The retrieved by calling {@link parseRoute()} method. * @param _methodsAndHandlers - A Map instance where the method is the key and the handler is the value. The handler is a simple * callback function that receives a single parameter as argument. Whatever you pass on this parameter can later be retrieved inside of {@link ServerResponseAdapter} * and {@link ServerRequestAdapter} methods. What you return on {@link ServerResponseAdapter.redirect} or {@link ServerResponseAdapter.send} will be * the return value of the handler callback. * @param _queryParams - The query params so you can parse it and validate as you wish. * @param _404Handler - The 404 handler. */ // eslint-disable-next-line ts/require-await async parseHandlers(_server, _rootFileSystemPath, _path, _methodsAndHandlers, _queryParams, _404Handler) { return void 0; } }; // src/adapters/serverless.ts function serverlessAdapter(args) { let CustomServerAdapter = class CustomServerAdapter extends ServerlessAdapter { static { __name(this, "CustomServerAdapter"); } request = args.request; response = args.response; routers = args.routers; load = args.load; static customServerSettings = args.customServerSettings; }; return CustomServerAdapter; } __name(serverlessAdapter, "serverlessAdapter"); var ServerlessAdapter = class { static { __name(this, "ServerlessAdapter"); } $$type = "$PServerlessAdapter"; serverName; settings; allSettings; domains; routers = new ServerlessRouterAdapter(); request = new ServerRequestAdapter(); response = new ServerResponseAdapter(); constructor(serverName, allSettings, settings, domains) { this.serverName = serverName; this.settings = settings; this.allSettings = allSettings; this.domains = domains; } // eslint-disable-next-line ts/require-await async load(_serverName, _domains, _settings) { return void 0; } // eslint-disable-next-line ts/require-await async generate(..._args) { return void 0; } static customServerSettings(args) { return args; } }; // src/router/routers.ts var BaseRouter = class { static { __name(this, "BaseRouter"); } path; __domain; __partsOfPath; __queryParamsAndPath = { path: "", params: /* @__PURE__ */ new Map() }; __urlParamsAndPath = { path: "", params: /* @__PURE__ */ new Map() }; __completePaths = /* @__PURE__ */ new Map(); __parentRouter; __wasCreatedFromNested = false; __children; __middlewares = []; __handlers = void 0; constructor(path2, children) { this.path = path2; this.__children = children; const { queryPath, urlPath, queryParams, urlParams, partsOfPath } = this.extractUrlAndQueryParametersFromPath(path2 || ""); this.__partsOfPath = partsOfPath; this.__queryParamsAndPath = { path: queryPath, params: new Map(Object.entries(queryParams)) }; this.__urlParamsAndPath = { path: urlPath, params: new Map(Object.entries(urlParams)) }; } static new(path2) { const newRouter = new MethodsRouter(path2); return newRouter; } static newNested() { return (path2) => { const newRouter = new MethodsRouter(path2); newRouter.__wasCreatedFromNested = true; return newRouter; }; } /** * Used for including other routers inside of this router. This way we can construct a tree of routers. And you * can use it to use the same middlewares and handlers for multiple routes. */ nested(children) { const newRouter = new IncludesRouter(this.path); const isNested = typeof children === "function"; const childrenArray = isNested ? children(newRouter.child()) : children; const doesChildrenAlreadyExists = Array.isArray(this.__children); const formattedChildren = childrenArray.map((child) => { child.__wasCreatedFromNested = isNested; child.__parentRouter = this; this.appendChildToParentRouter(this, child); return child; }); if (doesChildrenAlreadyExists) this.__children = this.__children?.concat(formattedChildren) || void 0; else this.__children = formattedChildren; return this; } appendChildToParentRouter(router, child) { while (router) { const fullUrlPath = `${router.__urlParamsAndPath.path}${child.__urlParamsAndPath.path}`; const fullQueryPath = `${router.__queryParamsAndPath.path}&${child.__queryParamsAndPath.path}`; const existsHandlersOnChild = typeof child.__handlers === "object" && Object.keys(child.__handlers).length > 0; const existsChildHandlersOnChild = child.__completePaths.size > 0; if (existsHandlersOnChild) { router.__completePaths.set(fullUrlPath, { middlewares: router.__middlewares.concat(child.__middlewares), partsOfPath: router.__partsOfPath.concat(child.__partsOfPath), urlParams: new Map([ ...router.__urlParamsAndPath.params, ...child.__urlParamsAndPath.params ]), urlPath: fullUrlPath, queryParams: new Map([ ...router.__queryParamsAndPath.params, ...child.__queryParamsAndPath.params ]), queryPath: fullQueryPath, router: child, handlers: child.__handlers }); } if (existsChildHandlersOnChild) { for (const [childPath, childPathData] of child.__completePaths.entries()) { const completePath = `${router.path}${childPath}`; router.__completePaths.set(completePath, { middlewares: router.__middlewares.concat(childPathData.middlewares), partsOfPath: router.__partsOfPath.concat(childPathData.partsOfPath), urlParams: new Map([ ...router.__urlParamsAndPath.params, ...childPathData.urlParams ]), urlPath: `${fullUrlPath}${childPathData.queryPath}`, queryParams: new Map([ ...router.__queryParamsAndPath.params, ...childPathData.queryParams ]), queryPath: `${fullQueryPath}&${childPathData.queryPath}`, router: child, handlers: childPathData.handlers }); } } router = router.__parentRouter; } } middlewares(definedMiddlewares) { const middlewaresAsMutable = this.__middlewares; this.__middlewares = middlewaresAsMutable.concat(definedMiddlewares); for (const handler of this.__completePaths.values()) handler.middlewares = definedMiddlewares.concat(handler.middlewares); return this; } extractQueryParamsFromPath(splittedPath, params, initialIndex) { let index = initialIndex; index++; const hasNotReachedEndOrNextQueryParam = /* @__PURE__ */ __name(() => splittedPath[index] !== "&" && index < splittedPath.length, "hasNotReachedEndOrNextQueryParam"); const ignoreSpaces = /* @__PURE__ */ __name(() => { if (splittedPath[index] === " ") index++; }, "ignoreSpaces"); while (index < splittedPath.length) { let queryParamName = ""; let queryParamType = ""; let queryParamRegex = ""; const queryParamTypes = []; let isArray = false; let isOptional = false; while (hasNotReachedEndOrNextQueryParam()) { ignoreSpaces(); if (splittedPath[index] === "&") index++; else if (splittedPath[index] === "=") { index++; if (splittedPath[index] === "{") { index++; while (splittedPath[index] !== "}") { ignoreSpaces(); queryParamRegex += splittedPath[index]; index++; } index++; } if (splittedPath[index] === ":") index++; while (hasNotReachedEndOrNextQueryParam()) { ignoreSpaces(); if (splittedPath[index] === "?") isOptional = true; else if (splittedPath[index] === "[" && splittedPath[index + 1] === "]") { isArray = true; index = index + 2; } else if (splittedPath[index] === "(") { index++; ignoreSpaces(); while (splittedPath[index] !== ")" && index < splittedPath.length) { ignoreSpaces(); if (splittedPath[index] === "|") { queryParamTypes.push(queryParamType); queryParamType = ""; } else { queryParamType += splittedPath[index]; } index++; } if (splittedPath[index] === ")") queryParamTypes.push(queryParamType); } else { queryParamType += splittedPath[index]; } index++; } } else { queryParamName += splittedPath[index]; index++; } } if (queryParamTypes.length === 0) queryParamTypes.push(queryParamType); params[queryParamName] = { type: queryParamTypes, isOptional, isArray, regex: queryParamRegex && queryParamRegex !== "" ? new RegExp(queryParamRegex) : void 0 }; index++; } return index; } extractUrlParamsFromPath(splittedPath, params, initialIndex) { let urlParamName = ""; let urlParamType = ""; let urlParamRegex = ""; let index = initialIndex; index++; const ignoreSpaces = /* @__PURE__ */ __name(() => { if (splittedPath[index] === " ") index++; }, "ignoreSpaces"); while (splittedPath[index] !== ">") { ignoreSpaces(); if (splittedPath[index] === ":") { index++; while (splittedPath[index] !== ">") { ignoreSpaces(); if (splittedPath[index] === ":") index++; if (splittedPath[index] === "{") { index++; while (splittedPath[index] !== "}") { ignoreSpaces(); urlParamRegex += splittedPath[index]; index++; } index++; } else { while (splittedPath[index] !== ">") { ignoreSpaces(); urlParamType += splittedPath[index]; index++; } } } } else while (splittedPath[index] !== ":") { ignoreSpaces(); urlParamName += splittedPath[index]; index++; } } params[urlParamName] = { type: [ urlParamType ], regex: urlParamRegex !== "" ? new RegExp(urlParamRegex) : new RegExp(urlParamType === "number" ? `^(?<${urlParamName}>\\d+)$` : urlParamType === "boolean" ? `^(?<${urlParamName}>true|false)$` : `^(?<${urlParamName}>\\w+)$`) }; index++; return index; } /** * This works similarly to a lexer in a programming language, but it's a bit simpler. We split the * characters and then we loop through them to find what we want. * * This means the complexity will grow the bigger the path is. */ extractUrlAndQueryParametersFromPath(path2) { const urlParams = {}; const queryParams = {}; const splittedPath = path2.split(""); const pathLength = splittedPath.length; const partsOfPath = []; let partOfPath = ""; let queryPath = ""; let index = 0; while (pathLength > index) { const isBeginningOfUrlParam = splittedPath[index] === "<"; const isEnteringQueryParams = splittedPath[index] === "?"; if (isBeginningOfUrlParam) { index = this.extractUrlParamsFromPath(splittedPath, urlParams, index); const keysOfUrlParams = Object.keys(urlParams); const lastInsertedKey = keysOfUrlParams[keysOfUrlParams.length - 1]; partsOfPath.push({ part: lastInsertedKey, isUrlParam: true }); } else if (isEnteringQueryParams) { const startIndex = index; index = this.extractQueryParamsFromPath(splittedPath, queryParams, index); queryPath = path2.slice(startIndex, index); } else if (splittedPath[index] !== "/") { partOfPath += splittedPath[index]; index++; } else { if (partOfPath !== "") { partsOfPath.push({ part: partOfPath, isUrlParam: false }); partOfPath = ""; } index++; } } if (partOfPath !== "") partsOfPath.push({ part: partOfPath, isUrlParam: false }); const urlPath = path2.replace(queryPath, ""); return { urlParams, queryParams, urlPath, queryPath: queryPath.replace(/^\?/g, ""), partsOfPath }; } }; var IncludesRouter = class extends BaseRouter { static { __name(this, "IncludesRouter"); } /** * Syntax sugar for creating a nested router inside of the `include` method when passing a function * instead of an array. * * @param path - The path of the route. * @returns - The child router. */ child() { return MethodsRouter.newNested(); } }; var MethodsRouter = class extends BaseRouter { static { __name(this, "MethodsRouter"); } /*middlewares( definedMiddlewares: Narrow ): MethodsRouter< TParentRouter, TChildren, readonly [...(TMiddlewares['length'] extends 0 ? [] : TMiddlewares), ...TRouterMiddlewares], TRootPath, TAlreadyDefinedHandlers, TRootRoutesTree > { const middlewaresAsMutable = this.__middlewares as unknown as Middleware[]; (this.__middlewares as unknown as Middleware[]) = middlewaresAsMutable.concat(definedMiddlewares as Middleware[]); for (const handler of this.__completePaths.values()) handler.middlewares = (definedMiddlewares as Middleware[]).concat(handler.middlewares); return this as any; }*/ get(handler, options) { if (Array.isArray(options?.middlewares)) { const middlewaresAsMutable = this.__middlewares; this.__middlewares = middlewaresAsMutable.concat(options.middlewares); for (const handler2 of this.__completePaths.values()) handler2.middlewares = options.middlewares.concat(handler2.middlewares); } const existingHandlers = this.__handlers ? this.__handlers : {}; delete existingHandlers.all; this.__handlers = { ...existingHandlers, get: { handler, options } }; return this; } post(handler, options) { if (Array.isArray(options?.middlewares)) { const middlewaresAsMutable = this.__middlewares; this.__middlewares = middlewaresAsMutable.concat(options.middlewares); for (const handler2 of this.__completePaths.values()) handler2.middlewares = options.middlewares.concat(handler2.middlewares); } const existingHandlers = this.__handlers ? this.__handlers : {}; delete existingHandlers.all; this.__handlers = { ...existingHandlers, post: { handler, options } }; return this; } delete(handler, options) { if (Array.isArray(options?.middlewares)) { const middlewaresAsMutable = this.__middlewares; this.__middlewares = middlewaresAsMutable.concat(options.middlewares); for (const handler2 of this.__completePaths.values()) handler2.middlewares = options.middlewares.concat(handler2.middlewares); } const existingHandlers = this.__handlers ? this.__handlers : {}; delete existingHandlers.all; this.__handlers = { ...existingHandlers, delete: { handler, options } }; return this; } options(handler, options) { if (Array.isArray(options?.middlewares)) { const middlewaresAsMutable = this.__middlewares; this.__middlewares = middlewaresAsMutable.concat(options.middlewares); for (const handler2 of this.__completePaths.values()) handler2.middlewares = options.middlewares.concat(handler2.middlewares); } const existingHandlers = this.__handlers ? this.__handlers : {}; delete existingHandlers.all; this.__handlers = { ...existingHandlers, options: { handler, options } }; return this; } head(handler, options) { if (Array.isArray(options?.middlewares)) { const middlewaresAsMutable = this.__middlewares; this.__middlewares = middlewaresAsMutable.concat(options.middlewares); for (const handler2 of this.__completePaths.values()) handler2.middlewares = options.middlewares.concat(handler2.middlewares); } const existingHandlers = this.__handlers ? this.__handlers : {}; delete existingHandlers.all; this.__handlers = { ...existingHandlers, head: { handler, options } }; return this; } put(handler, options) { if (Array.isArray(options?.middlewares)) { const middlewaresAsMutable = this.__middlewares; this.__middlewares = middlewaresAsMutable.concat(options.middlewares); for (const handler2 of this.__completePaths.values()) handler2.middlewares = options.middlewares.concat(handler2.middlewares); } const existingHandlers = this.__handlers ? this.__handlers : {}; delete existingHandlers.all; this.__handlers = { ...existingHandlers, put: { handler, options } }; return this; } patch(handler, options) { if (Array.isArray(options?.middlewares)) { const middlewaresAsMutable = this.__middlewares; this.__middlewares = middlewaresAsMutable.concat(options.middlewares); for (const handler2 of this.__completePaths.values()) handler2.middlewares = options.middlewares.concat(handler2.middlewares); } const existingHandlers = this.__handlers ? this.__handlers : {}; delete existingHandlers.all; this.__handlers = { ...existingHandlers, patch: { handler, options } }; return this; } all(handler, options) { const handlersAsAny = this.__handlers; if (handlersAsAny) { for (const key of Object.keys(handlersAsAny)) if (key !== "all") delete handlersAsAny[key]; } const existingHandlers = this.__handlers ? this.__handlers : {}; this.__handlers = { ...existingHandlers, all: { handler, options } }; return this; } }; // src/router/functions.ts function path(path1 = "") { return MethodsRouter.new(path1); } __name(path, "path"); function pathNested(parentRouter) { return (path2 = "") => { const newRouter = MethodsRouter.newNested()(path2); if (parentRouter) parentRouter.nested([ newRouter ]); return newRouter; }; } __name(pathNested, "pathNested"); // src/middleware/index.ts var Middleware = class { static { __name(this, "Middleware"); } /** * This function is executed during the request lifecycle. It can return a {@link Request} or a {@link Response}. * * If it returns a {@link Request}, the request will be passed to the next middleware or handler. If it's * a {@link Response}, the response will be sent to the passed middlewares until it's sent to the client. * * ### IMPORTANT * * Using `middleware` function it's nice if you explicitly define how the {@link Request} will enter the * function. This way we can correctly type the Request on the client. We will know how the data needs to * be sent to the server. * * ### IMPORTANT2 * * If you don't explicitly type the Request, at least explicitly type the returned {@link Request}. * This way we can correctly type the request on the handler. * * @example * ```ts * import { Middleware, Response, HTTP_401_UNAUTHORIZED } from '@palmares/server'; * * export class AuthenticateMiddleware extends Middleware { * request: async (request: Request { * const bearerAuth = request.headers['Authorization']; * // make validation * if (isValid) { * const user = await getUserFromToken(bearerAuth); * const requestWithUser = request.clone({ * context: { user }, * }); * return requestWithUser; * } * return Response.json({ message: 'Unauthorized' }, { status: HTTP_401_UNAUTHORIZED }); * }, * } * ``` * * @param request - An instance of {@link Request} with the data. * * @returns - A {@link Request} instance with the modified data or a {@link Response} instance if you want * to break the middleware chain. */ request = void 0; /** * This function is executed during the response lifecycle. It needs to return a {@link Response} instance. * Usually you will use this to either change the sent response entirely or to add some headers/data to * the response or filter out some properties. * * @example * ```ts * import { Middleware, Response, HTTP_401_UNAUTHORIZED } from '@palmares/server'; * * export class HelmetMiddleware extends Middleware { * response: async (response) => { * // Filter out properties * const responseWithHeaders = response.clone({ * headers: newHeaders * }); * return responseWithHeaders; * }, * }; * ``` * * @param response - An instance of {@link Response} with the data. * * @returns - A {@link Response} instance with the modified data. */ response = void 0; options = void 0; }; function middleware(options) { return new class extends Middleware { request = options.request; response = options.response; options = options.options; }(); } __name(middleware, "middleware"); function nestedMiddleware() { return (options) => { return new class extends Middleware { request = options.request; response = options.response; options = options.options; }(); }; } __name(nestedMiddleware, "nestedMiddleware"); function requestMiddleware() { return (options) => { return new class extends Middleware { request = options.request; response = options.response; options = options.options; }(); }; } __name(requestMiddleware, "requestMiddleware"); // src/response/status.ts var status_exports = {}; __export(status_exports, { HTTP_100_CONTINUE: () => HTTP_100_CONTINUE, HTTP_101_SWITCHING_PROTOCOLS: () => HTTP_101_SWITCHING_PROTOCOLS, HTTP_200_OK: () => HTTP_200_OK, HTTP_201_CREATED: () => HTTP_201_CREATED, HTTP_202_ACCEPTED: () => HTTP_202_ACCEPTED, HTTP_203_NON_AUTHORITATIVE_INFORMATION: () => HTTP_203_NON_AUTHORITATIVE_INFORMATION, HTTP_204_NO_CONTENT: () => HTTP_204_NO_CONTENT, HTTP_205_RESET_CONTENT: () => HTTP_205_RESET_CONTENT, HTTP_206_PARTIAL_CONTENT: () => HTTP_206_PARTIAL_CONTENT, HTTP_207_MULTI_STATUS: () => HTTP_207_MULTI_STATUS, HTTP_208_ALREADY_REPORTED: () => HTTP_208_ALREADY_REPORTED, HTTP_226_IM_USED: () => HTTP_226_IM_USED, HTTP_300_MULTIPLE_CHOICES: () => HTTP_300_MULTIPLE_CHOICES, HTTP_301_MOVED_PERMANENTLY: () => HTTP_301_MOVED_PERMANENTLY, HTTP_302_FOUND: () => HTTP_302_FOUND, HTTP_303_SEE_OTHER: () => HTTP_303_SEE_OTHER, HTTP_304_NOT_MODIFIED: () => HTTP_304_NOT_MODIFIED, HTTP_305_USE_PROXY: () => HTTP_305_USE_PROXY, HTTP_306_RESERVED: () => HTTP_306_RESERVED, HTTP_307_TEMPORARY_REDIRECT: () => HTTP_307_TEMPORARY_REDIRECT, HTTP_308_PERMANENT_REDIRECT: () => HTTP_308_PERMANENT_REDIRECT, HTTP_400_BAD_REQUEST: () => HTTP_400_BAD_REQUEST, HTTP_401_UNAUTHORIZED: () => HTTP_401_UNAUTHORIZED, HTTP_402_PAYMENT_REQUIRED: () => HTTP_402_PAYMENT_REQUIRED, HTTP_403_FORBIDDEN: () => HTTP_403_FORBIDDEN, HTTP_404_NOT_FOUND: () => HTTP_404_NOT_FOUND, HTTP_405_METHOD_NOT_ALLOWED: () => HTTP_405_METHOD_NOT_ALLOWED, HTTP_406_NOT_ACCEPTABLE: () => HTTP_406_NOT_ACCEPTABLE, HTTP_407_PROXY_AUTHENTICATION_REQUIRED: () => HTTP_407_PROXY_AUTHENTICATION_REQUIRED, HTTP_408_REQUEST_TIMEOUT: () => HTTP_408_REQUEST_TIMEOUT, HTTP_409_CONFLICT: () => HTTP_409_CONFLICT, HTTP_410_GONE: () => HTTP_410_GONE, HTTP_411_LENGTH_REQUIRED: () => HTTP_411_LENGTH_REQUIRED, HTTP_412_PRECONDITION_FAILED: () => HTTP_412_PRECONDITION_FAILED, HTTP_413_REQUEST_ENTITY_TOO_LARGE: () => HTTP_413_REQUEST_ENTITY_TOO_LARGE, HTTP_414_REQUEST_URI_TOO_LONG: () => HTTP_414_REQUEST_URI_TOO_LONG, HTTP_415_UNSUPPORTED_MEDIA_TYPE: () => HTTP_415_UNSUPPORTED_MEDIA_TYPE, HTTP_416_REQUESTED_RANGE_NOT_SATISFIABLE: () => HTTP_416_REQUESTED_RANGE_NOT_SATISFIABLE, HTTP_417_EXPECTATION_FAILED: () => HTTP_417_EXPECTATION_FAILED, HTTP_418_IM_A_TEAPOT: () => HTTP_418_IM_A_TEAPOT, HTTP_422_UNPROCESSABLE_ENTITY: () => HTTP_422_UNPROCESSABLE_ENTITY, HTTP_423_LOCKED: () => HTTP_423_LOCKED, HTTP_424_FAILED_DEPENDENCY: () => HTTP_424_FAILED_DEPENDENCY, HTTP_426_UPGRADE_REQUIRED: () => HTTP_426_UPGRADE_REQUIRED, HTTP_428_PRECONDITION_REQUIRED: () => HTTP_428_PRECONDITION_REQUIRED, HTTP_429_TOO_MANY_REQUESTS: () => HTTP_429_TOO_MANY_REQUESTS, HTTP_431_REQUEST_HEADER_FIELDS_TOO_LARGE: () => HTTP_431_REQUEST_HEADER_FIELDS_TOO_LARGE, HTTP_451_UNAVAILABLE_FOR_LEGAL_REASONS: () => HTTP_451_UNAVAILABLE_FOR_LEGAL_REASONS, HTTP_500_INTERNAL_SERVER_ERROR: () => HTTP_500_INTERNAL_SERVER_ERROR, HTTP_501_NOT_IMPLEMENTED: () => HTTP_501_NOT_IMPLEMENTED, HTTP_502_BAD_GATEWAY: () => HTTP_502_BAD_GATEWAY, HTTP_503_SERVICE_UNAVAILABLE: () => HTTP_503_SERVICE_UNAVAILABLE, HTTP_504_GATEWAY_TIMEOUT: () => HTTP_504_GATEWAY_TIMEOUT, HTTP_505_HTTP_VERSION_NOT_SUPPORTED: () => HTTP_505_HTTP_VERSION_NOT_SUPPORTED, HTTP_506_VARIANT_ALSO_NEGOTIATES: () => HTTP_506_VARIANT_ALSO_NEGOTIATES, HTTP_507_INSUFFICIENT_STORAGE: () => HTTP_507_INSUFFICIENT_STORAGE, HTTP_508_LOOP_DETECTED: () => HTTP_508_LOOP_DETECTED, HTTP_509_BANDWIDTH_LIMIT_EXCEEDED: () => HTTP_509_BANDWIDTH_LIMIT_EXCEEDED, HTTP_510_NOT_EXTENDED: () => HTTP_510_NOT_EXTENDED, HTTP_511_NETWORK_AUTHENTICATION_REQUIRED: () => HTTP_511_NETWORK_AUTHENTICATION_REQUIRED, isClientError: () => isClientError, isInformational: () => isInformational, isRedirect: () => isRedirect, isServerError: () => isServerError, isSuccess: () => isSuccess }); var isInformational = /* @__PURE__ */ __name((code) => code >= 100 && code <= 199, "isInformational"); var isSuccess = /* @__PURE__ */ __name((code) => code >= 200 && code <= 299, "isSuccess"); var isRedirect = /* @__PURE__ */ __name((code) => code >= 300 && code <= 399, "isRedirect"); var isClientError = /* @__PURE__ */ __name((code) => code >= 400 && code <= 499, "isClientError"); var isServerError = /* @__PURE__ */ __name((code) => code >= 500 && code <= 599, "isServerError"); var HTTP_100_CONTINUE = 100; var HTTP_101_SWITCHING_PROTOCOLS = 101; var HTTP_200_OK = 200; var HTTP_201_CREATED = 201; var HTTP_202_ACCEPTED = 202; var HTTP_203_NON_AUTHORITATIVE_INFORMATION = 203; var HTTP_204_NO_CONTENT = 204; var HTTP_205_RESET_CONTENT = 205; var HTTP_206_PARTIAL_CONTENT = 206; var HTTP_207_MULTI_STATUS = 207; var HTTP_208_ALREADY_REPORTED = 208; var HTTP_226_IM_USED = 226; var HTTP_300_MULTIPLE_CHOICES = 300; var HTTP_301_MOVED_PERMANENTLY = 301; var HTTP_302_FOUND = 302; var HTTP_303_SEE_OTHER = 303; var HTTP_304_NOT_MODIFIED = 304; var HTTP_305_USE_PROXY = 305; var HTTP_306_RESERVED = 306; var HTTP_307_TEMPORARY_REDIRECT = 307; var HTTP_308_PERMANENT_REDIRECT = 308; var HTTP_400_BAD_REQUEST = 400; var HTTP_401_UNAUTHORIZED = 401; var HTTP_402_PAYMENT_REQUIRED = 402; var HTTP_403_FORBIDDEN = 403; var HTTP_404_NOT_FOUND = 404; var HTTP_405_METHOD_NOT_ALLOWED = 405; var HTTP_406_NOT_ACCEPTABLE = 406; var HTTP_407_PROXY_AUTHENTICATION_REQUIRED = 407; var HTTP_408_REQUEST_TIMEOUT = 408; var HTTP_409_CONFLICT = 409; var HTTP_410_GONE = 410; var HTTP_411_LENGTH_REQUIRED = 411; var HTTP_412_PRECONDITION_FAILED = 412; var HTTP_413_REQUEST_ENTITY_TOO_LARGE = 413; var HTTP_414_REQUEST_URI_TOO_LONG = 414; var HTTP_415_UNSUPPORTED_MEDIA_TYPE = 415; var HTTP_416_REQUESTED_RANGE_NOT_SATISFIABLE = 416; var HTTP_417_EXPECTATION_FAILED = 417; var HTTP_418_IM_A_TEAPOT = 418; var HTTP_422_UNPROCESSABLE_ENTITY = 422; var HTTP_423_LOCKED = 423; var HTTP_424_FAILED_DEPENDENCY = 424; var HTTP_426_UPGRADE_REQUIRED = 426; var HTTP_428_PRECONDITION_REQUIRED = 428; var HTTP_429_TOO_MANY_REQUESTS = 429; var HTTP_431_REQUEST_HEADER_FIELDS_TOO_LARGE = 431; var HTTP_451_UNAVAILABLE_FOR_LEGAL_REASONS = 451; var HTTP_500_INTERNAL_SERVER_ERROR = 500; var HTTP_501_NOT_IMPLEMENTED = 501; var HTTP_502_BAD_GATEWAY = 502; var HTTP_503_SERVICE_UNAVAILABLE = 503; var HTTP_504_GATEWAY_TIMEOUT = 504; var HTTP_505_HTTP_VERSION_NOT_SUPPORTED = 505; var HTTP_506_VARIANT_ALSO_NEGOTIATES = 506; var HTTP_507_INSUFFICIENT_STORAGE = 507; var HTTP_508_LOOP_DETECTED = 508; var HTTP_509_BANDWIDTH_LIMIT_EXCEEDED = 509; var HTTP_510_NOT_EXTENDED = 510; var HTTP_511_NETWORK_AUTHENTICATION_REQUIRED = 511; // src/defaults/settings.ts var DEFAULT_SERVER_PORT = 4e3; var DEFAULT_STATUS_CODE_BY_METHOD = /* @__PURE__ */ __name((method) => { const methodLowerCased = method.toLowerCase(); switch (methodLowerCased) { case "post": return 201; default: return 200; } }, "DEFAULT_STATUS_CODE_BY_METHOD"); // src/utils/error-id.ts function generateErrorId() { let date = (/* @__PURE__ */ new Date()).getTime(); const performance = globalThis.performance; let performanceDate = performance && performance.now && performance.now() * 1e3 || 0; return "x-xx_x-xx_x-xx_x-xx_x-xx_y-xx_x-xx_x-xx_x-xx_x-xx_x".replace(/[xy]/g, (character) => { let randomNumber = Math.random() * 16; if (date > 0) { randomNumber = (date + randomNumber) % 16 | 0; date = Math.floor(date / 16); } else { randomNumber = (performanceDate + randomNumber) % 16 | 0; performanceDate = Math.floor(performanceDate / 16); } return (character === "x" ? randomNumber : randomNumber & 3 | 8).toString(16); }); } __name(generateErrorId, "generateErrorId"); // src/utils/launch-editor-on-error.ts var import_core = require("@palmares/core"); function isTerminalEditor(editor) { switch (editor) { case "vi": case "vim": case "emacs": case "nano": { return true; } default: { } } return false; } __name(isTerminalEditor, "isTerminalEditor"); var COMMON_EDITORS_MACOS = { "/Applications/Atom.app/Contents/MacOS/Atom": "atom", "/Applications/Atom Beta.app/Contents/MacOS/Atom Beta": "/Applications/Atom Beta.app/Contents/MacOS/Atom Beta", "/Applications/Brackets.app/Contents/MacOS/Brackets": "brackets", "/Applications/Sublime Text.app/Contents/MacOS/Sublime Text": "/Applications/Sublime Text.app/Contents/SharedSupport/bin/subl", "/Applications/Sublime Text Dev.app/Contents/MacOS/Sublime Text": "/Applications/Sublime Text Dev.app/Contents/SharedSupport/bin/subl", "/Applications/Sublime Text 2.app/Contents/MacOS/Sublime Text 2": "/Applications/Sublime Text 2.app/Contents/SharedSupport/bin/subl", "/Applications/Visual Studio Code.app/Contents/MacOS/Electron": "/Applications/Visual Studio Code.app/Contents/Resources/app/bin/code", "/Applications/Visual Studio Code - Insiders.app/Contents/MacOS/Electron": "/Applications/Visual Studio Code - Insiders.app/Contents/Resources/app/bin/code", "/Applications/VSCodium.app/Contents/MacOS/Electron": "/Applications/VSCodium.app/Contents/Resources/app/bin/code", "/Applications/AppCode.app/Contents/MacOS/appcode": "/Applications/AppCode.app/Contents/MacOS/appcode", "/Applications/CLion.app/Contents/MacOS/clion": "/Applications/CLion.app/Contents/MacOS/clion", "/Applications/IntelliJ IDEA.app/Contents/MacOS/idea": "/Applications/IntelliJ IDEA.app/Contents/MacOS/idea", "/Applications/PhpStorm.app/Contents/MacOS/phpstorm": "/Applications/PhpStorm.app/Contents/MacOS/phpstorm", "/Applications/PyCharm.app/Contents/MacOS/pycharm": "/Applications/PyCharm.app/Contents/MacOS/pycharm", "/Applications/PyCharm CE.app/Contents/MacOS/pycharm": "/Applications/PyCharm CE.app/Contents/MacOS/pycharm", "/Applications/RubyMine.app/Contents/MacOS/rubymine": "/Applications/RubyMine.app/Contents/MacOS/rubymine", "/Applications/WebStorm.app/Contents/MacOS/webstorm": "/Applications/WebStorm.app/Contents/MacOS/webstorm", "/Applications/MacVim.app/Contents/MacOS/MacVim": "mvim", "/Applications/GoLand.app/Contents/MacOS/goland": "/Applications/GoLand.app/Contents/MacOS/goland", "/Applications/Rider.app/Contents/MacOS/rider": "/Applications/Rider.app/Contents/MacOS/rider" }; var COMMON_EDITORS_LINUX = { atom: "atom", Brackets: "brackets", code: "code", "code-insiders": "code-insiders", vscodium: "vscodium", emacs: "emacs", gvim: "gvim", "idea.sh": "idea", "phpstorm.sh": "phpstorm", "pycharm.sh": "pycharm", "rubymine.sh": "rubymine", sublime_text: "sublime_text", vim: "vim", "webstorm.sh": "webstorm", "goland.sh": "goland", "rider.sh": "rider" }; var COMMON_EDITORS_WIN = [ "Brackets.exe", "Code.exe", "Code - Insiders.exe", "VSCodium.exe", "atom.exe", "sublime_text.exe", "notepad++.exe", "clion.exe", "clion64.exe", "idea.exe", "idea64.exe", "phpstorm.exe", "phpstorm64.exe", "pycharm.exe", "pycharm64.exe", "rubymine.exe", "rubymine64.exe", "webstorm.exe", "webstorm64.exe", "goland.exe", "goland64.exe", "rider.exe", "rider64.exe" ]; var WINDOWS_FILE_NAME_ACCESS_LIST = ( // eslint-disable-next-line max-len /^([A-Za-z]:[/\\])?(?:[\x2D-9A-Z\\_a-z\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u052F\u0531-\u0556\u0559\u0560-\u0588\u05D0-\u05EA\u05EF-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u0860-\u086A\u08A0-\u08B4\u08B6-\u08BD\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0980\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u09FC\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0AF9\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D\u0C58-\u0C5A\u0C60\u0C61\u0C80\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D54-\u0D56\u0D5F-\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F5\u13F8-\u13FD\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16F1-\u16F8\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1878\u1880-\u1884\u1887-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191E\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u1A00-\u1A16\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1C80-\u1C88\u1C90-\u1CBA\u1CBD-\u1CBF\u1CE9-\u1CEC\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2183\u2184\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005\u3006\u3031-\u3035\u303B\u303C\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312F\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FEF\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA67F-\uA69D\uA6A0-\uA6E5\uA717-\uA71F\uA722-\uA788\uA78B-\uA7B9\uA7F7-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA8FD\uA8FE\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uA9E0-\uA9E4\uA9E6-\uA9EF\uA9FA-\uA9FE\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA7E-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB65\uAB70-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]|\uD800[\uDC00-\uDC0B\uDC0D-\uDC26\uDC28-\uDC3A\uDC3C\uDC3D\uDC3F-\uDC4D\uDC50-\uDC5D\uDC80-\uDCFA\uDE80-\uDE9C\uDEA0-\uDED0\uDF00-\uDF1F\uDF2D-\uDF40\uDF42-\uDF49\uDF50-\uDF75\uDF80-\uDF9D\uDFA0-\uDFC3\uDFC8-\uDFCF]|\uD801[\uDC00-\uDC9D\uDCB0-\uDCD3\uDCD8-\uDCFB\uDD00-\uDD27\uDD30-\uDD63\uDE00-\uDF36\uDF40-\uDF55\uDF60-\uDF67]|\uD802[\uDC00-\uDC05\uDC08\uDC0A-\uDC35\uDC37\uDC38\uDC3C\uDC3F-\uDC55\uDC60-\uDC76\uDC80-\uDC9E\uDCE0-\uDCF2\uDCF4\uDCF5\uDD00-\uDD15\uDD20-\uDD39\uDD80-\uDDB7\uDDBE\uDDBF\uDE00\uDE10-\uDE13\uDE15-\uDE17\uDE19-\uDE35\uDE60-\uDE7C\uDE80-\uDE9C\uDEC0-\uDEC7\uDEC9-\uDEE4\uDF00-\uDF35\uDF40-\uDF55\uDF60-\uDF72\uDF80-\uDF91]|\uD803[\uDC00-\uDC48\uDC80-\uDCB2\uDCC0-\uDCF2\uDD00-\uDD23\uDF00-\uDF1C\uDF27\uDF30-\uDF45]|\uD804[\uDC03-\uDC37\uDC83-\uDCAF\uDCD0-\uDCE8\uDD03-\uDD26\uDD44\uDD50-\uDD72\uDD76\uDD83-\uDDB2\uDDC1-\uDDC4\uDDDA\uDDDC\uDE00-\uDE11\uDE13-\uDE2B\uDE80-\uDE86\uDE88\uDE8A-\uDE8D\uDE8F-\uDE9D\uDE9F-\uDEA8\uDEB0-\uDEDE\uDF05-\uDF0C\uDF0F\uDF10\uDF13-\uDF28\uDF2A-\uDF30\uDF32\uDF33\uDF35-\uDF39\uDF3D\uDF50\uDF5D-\uDF61]|\uD805[\uDC00-\uDC34\uDC47-\uDC4A\uDC80-\uDCAF\uDCC4\uDCC5\uDCC7\uDD80-\uDDAE\uDDD8-\uDDDB\uDE00-\uDE2F\uDE44\uDE80-\uDEAA\uDF00-\uDF1A]|\uD806[\uDC00-\uDC2B\uDCA0-\uDCDF\uDCFF\uDE00\uDE0B-\uDE32\uDE3A\uDE50\uDE5C-\uDE83\uDE86-\uDE89\uDE9D\uDEC0-\uDEF8]|\uD807[\uDC00-\uDC08\uDC0A-\uDC2E\uDC40\uDC72-\uDC8F\uDD00-\uDD06\uDD08\uDD09\uDD0B-\uDD30\uDD46\uDD60-\uDD65\uDD67\uDD68\uDD6A-\uDD89\uDD98\uDEE0-\uDEF2]|\uD808[\uDC00-\uDF99]|\uD809[\uDC80-\uDD43]|[\uD80C\uD81C-\uD820\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872\uD874-\uD879][\uDC00-\uDFFF]|\uD80D[\uDC00-\uDC2E]|\uD811[\uDC00-\uDE46]|\uD81A[\uDC00-\uDE38\uDE40-\uDE5E\uDED0-\uDEED\uDF00-\uDF2F\uDF40-\uDF43\uDF63-\uDF77\uDF7D-\uDF8F]|\uD81B[\uDE40-\uDE7F\uDF00-\uDF44\uDF50\uDF93-\uDF9F\uDFE0\uDFE1]|\uD821[\uDC00-\uDFF1]|\uD822[\uDC00-\uDEF2]|\uD82C[\uDC00-\uDD1E\uDD70-\uDEFB]|\uD82F[\uDC00-\uDC6A\uDC70-\uDC7C\uDC80-\uDC88\uDC90-\uDC99]|\uD835[\uDC00-\uDC54\uDC56-\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD1E-\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD52-\uDEA5\uDEA8-\uDEC0\uDEC2-\uDEDA\uDEDC-\uDEFA\uDEFC-\uDF14\uDF16-\uDF34\uDF36-\uDF4E\uDF50-\uDF6E\uDF70-\uDF88\uDF8A-\uDFA8\uDFAA-\uDFC2\uDFC4-\uDFCB]|\uD83A[\uDC00-\uDCC4\uDD00-\uDD43]|\uD83B[\uDE00-\uDE03\uDE05-\uDE1F\uDE21\uDE22\uDE24\uDE27\uDE29-\uDE32\uDE34-\uDE37\uDE39\uDE3B\uDE42\uDE47\uDE49\uDE4B\uDE4D-\uDE4F\uDE51\uDE52\uDE54\uDE57\uDE59\uDE5B\uDE5D\uDE5F\uDE61\uDE62\uDE64\uDE67-\uDE6A\uDE6C-\uDE72\uDE74-\uDE77\uDE79-\uDE7C\uDE7E\uDE80-\uDE89\uDE8B-\uDE9B\uDEA1-\uDEA3\uDEA5-\uDEA9\uDEAB-\uDEBB]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1\uDEB0-\uDFFF]|\uD87A[\uDC00-\uDFE0]|\uD87E[\uDC00-\uDE1D])+$/ ); async function getArgumentsForLineNumber(defaultStd, editor, fileName, lineNumber, colNumber) { const editorBasename = (await defaultStd.files.basename(editor)).replace(/\.(exe|cmd|bat)$/i, ""); switch (editorBasename) { case "atom": case "Atom": case "Atom Beta": case "subl": case "sublime": case "sublime_text": { return [ fileName + ":" + lineNumber + ":" + colNumber ]; } case "wstorm": case "charm": { return [ fileName + ":" + lineNumber ]; } case "notepad++": { return [ "-n" + lineNumber, "-c" + colNumber, fileName ]; } case "vim": case "mvim": case "joe": case "gvim": { return [ "+" + lineNumber, fileName ]; } case "emacs": case "emacsclient": { return [ "+" + lineNumber + ":" + colNumber, fileName ]; } case "rmate": case "mate": case "mine": { return [ "--line", lineNumber.toString(), fileName ]; } case "code": case "Code": case "code-insiders": case "Code - Insiders": case "vscodium": case "VSCodium": { return [ "-g", fileName + ":" + lineNumber + ":" + colNumber ]; } case "appcode": case "clion": case "clion64": case "idea": case "idea64": case "phpstorm": case "phpstorm64": case "pycharm": case "pycharm64": case "rubymine": case "rubymine64": case "webstorm": case "webstorm64": case "goland": case "goland64": case "rider": case "rider64": { return [ "--line", lineNumber.toString(), fileName ]; } default: { return [ fileName ]; } } } __name(getArgumentsForLineNumber, "getArgumentsForLineNumber"); async function guessEditor(defaultStd, platform) { const isMacOs = platform === "darwin"; const isWindows = platform === "windows"; try { if (isMacOs) { const output = await defaultStd.childProcess.executeAndOutput("ps x"); const processNames = Object.keys(COMMON_EDITORS_MACOS); for (let i = 0; i < processNames.length; i++) { const processName = processNames[i]; if (output.includes(processName)) return [ COMMON_EDITORS_MACOS[processName] ]; } } else if (isWindows) { const output = await defaultStd.childProcess.executeAndOutput('wmic process where "executablepath is not null" get executablepath'); const runningProcesses = output; for (let i = 0; i < runningProcesses.length; i++) { const processPath = runningProcesses[i].trim(); const processName = await defaultStd.files.basename(processPath); if (COMMON_EDITORS_WIN.includes(processName)) return [ processPath ]; } } else if (process.platform === "linux") { const output = await defaultStd.childProcess.executeAndOutput("ps x --no-heading -o comm --sort=comm"); const processNames = Object.keys(COMMON_EDITORS_LINUX); for (let i = 0; i < processNames.length; i++) { const processName = processNames[i]; if (output.includes(processName)) { return [ COMMON_EDITORS_LINUX[processName] ]; } } } } catch (error) { } if (process.env.VISUAL) { return [ process.env.VISUAL ]; } else if (process.env.EDITOR) { return [ process.env.EDITOR ]; } return []; } __name(guessEditor, "guessEditor"); async function printInstructions(defaultStd, fileName, errorMessage) { const baseNameOfFileName = defaultStd.files.basename(fileName); console.log(` Could not open ${baseNameOfFileName} in the editor. `); if (errorMessage) { if (errorMessage[errorMessage.length - 1] !== ".") { errorMessage += "."; } console.log(` The editor process exited with an error: ${errorMessage} `); } console.log("\nTo set up the editor integration, add something like `REACT_EDITOR=atom` to the `.env.local` file in your project folder and restart the development server.\n"); } __name(printInstructions, "printInstructions"); async function launchEditor(fileName, lineNumber, colNumber) { const doesNotExistFile = await import_core.std.files.exists(fileName) === false; if (doesNotExistFile) return; if (!(Number.isInteger(lineNumber) && lineNumber > 0)) return; if (!(Number.isInteger(colNumber) && colNumber > 0)) colNumber = 1; const [osRelease, osPlatform] = await Promise.all([ import_core.std.os.release(), import_core.std.os.platform() ]); let [editor, ...args] = await guessEditor(import_core.std, osPlatform); if (!editor) return printInstructions(import_core.std, fileName, null); if (editor.toLowerCase() === "none") return; if (osPlatform === "linux" && fileName.startsWith("/mnt/") && /Microsoft/i.test(osRelease)) { fileName = await import_core.std.files.relative("", fileName); } if (osPlatform === "windows" && !WINDOWS_FILE_NAME_ACCESS_LIST.test(fileName.trim())) { const baseNameOfFileName = await import_core.std.files.basename(fileName); console.log(` Could not open ${baseNameOfFileName} in the editor. `); console.log("\nWhen running on Windows, file names are checked against an access list to protect against remote code execution attacks. File names may consist only of alphanumeric characters (all languages), periods, dashes, slashes, and underscores.\n"); return; } const argumentsForLineNumber = await getArgumentsForLineNumber(import_core.std, editor, fileName, lineNumber, colNumber); if (lineNumber) args = args.concat(argumentsForLineNumber); else args.push(fileName); const onErrorOnProcess = /* @__PURE__ */ __name((error) => printInstructions(import_core.std, fileName, error.message), "onErrorOnProcess"); const onExitOnProcess = /* @__PURE__ */ __name((errorCode) => { if (errorCode) printInstructions(import_core.std, fileName, "(code " + errorCode + ")"); }, "onExitOnProcess"); if (osPlatform === "windows") import_core.std.childProcess.spawn("cmd.exe", [ "/C", editor ].concat(args), { stdio: [ "inherit" ], detached: true, onError: onErrorOnProcess, onExit: onExitOnProcess }); else if (isTerminalEditor(editor)) printInstructions(import_core.std, fileName, "Terminal editors are not supported."); else import_core.std.childProcess.spawn(editor, args, { stdio: [ "inherit" ], onError: onErrorOnProcess, onExit: onExitOnProcess }); } __name(launchEditor, "launchEditor"); // src/handlers/error-handler.ts var errorId = void 0; function getErrorId() { return errorId; } __name(getErrorId, "getErrorId"); function errorCaptureHandler() { errorId = generateErrorId(); return path(`/${errorId}`).post(async (request) => { const body = await request.json(); const { errorColumn, errorFile, errorLine } = body; launchEditor(errorFile, errorLine, errorColumn); return new Response(void 0, { status: HTTP_200_OK }); }); } __name(errorCaptureHandler, "errorCaptureHandler"); // src/defaults/response.ts var DEFAULT_RESPONSE_HEADERS_CONTENT_HEADER_KEY = "Content-Type"; var DEFAULT_RESPONSE_HEADERS_CONTENT_DISPOSITION_KEY = "Content-Disposition"; var DEFAULT_RESPONSE_CONTENT_HEADER_VALUE_JSON = "application/json"; var DEFAULT_RESPONSE_CONTENT_HEADER_VALUE_HTML = "text/html"; var DEFAULT_RESPONSE_CONTENT_HEADER_VALUE_TEXT = "plain/text"; var DEFAULT_RESPONSE_CONTENT_HEADER_VALUE_STREAM = "application/octet-stream"; var DEFAULT_RESPONSE_HEADERS_LOCATION_HEADER_KEY = "Location"; var DEFAULT_NOT_FOUND_STATUS_TEXT_MESSAGE = "Not Found"; var DEFAULT_SERVER_ERROR_STATUS_TEXT_MESSAGE = "Internal Server Error"; var DEFAULT_SERVER_ERROR_RESPONSE = /* @__PURE__ */ __name((error, settings, domains) => { const errorFileAndLines = error.stack?.split("\n"); let errorFile = ""; let errorLine = ""; let errorColumn = ""; while (errorFileAndLines?.length && errorFileAndLines.length > 0) { const errorFileAndLine = errorFileAndLines.shift()?.match(/\((.*)\)/)?.[1]; if (errorFileAndLine) { errorFile = errorFileAndLine.split(":")[0]; errorLine = errorFileAndLine.split(":")[1]; errorColumn = errorFileAndLine.split(":")[2]; if (errorFile && errorLine && errorColumn && errorFile !== "" && errorLine !== "" && errorColumn !== "") break; } } return new Response(` [Palmares] - Internal Server Error

Oops, looks like something happened to your Palmares application ):

Internal Server Error

${error.name}

${error.message}

Stack trace

${error.stack}

Domains

${domains.map((domain2, index) => `

${domain2.name}

${domain2.path}
${index !== domains.length - 1 ? "
" : ""}`).join("")}
`, { status: HTTP_500_INTERNAL_SERVER_ERROR, statusText: DEFAULT_SERVER_ERROR_STATUS_TEXT_MESSAGE, headers: { [DEFAULT_RESPONSE_HEADERS_CONTENT_HEADER_KEY]: DEFAULT_RESPONSE_CONTENT_HEADER_VALUE_HTML } }); }, "DEFAULT_SERVER_ERROR_RESPONSE"); var DEFAULT_SERVER_ERROR_INVALID_QUERY_OR_PARAMS = /* @__PURE__ */ __name(() => { return Response.html(` [Palmares] - Bad Request Error `, { status: HTTP_400_BAD_REQUEST, statusText: "Query params or Url Params invalid" }); }, "DEFAULT_SERVER_ERROR_INVALID_QUERY_OR_PARAMS"); // src/defaults/request.ts var DEFAULT_REQUEST_HEADERS_CONTENT_HEADER_KEY = "Content-Type"; var DEFAULT_REQUEST_CONTENT_HEADER_VALUE_URLENCODED = "application/x-www-form-urlencoded"; // src/response/index.ts var Response = class _Response { static { __name(this, "Response"); } /** * This is data sent by the server, you can use it to translate your request and response during the * lifecycle of Request/Response. * * Think like that, on express: * * ```ts * app.use((req, res, next) => { * const serverRequestAndResponseData = { req, res }; * await wrappedHandler(serverRequestAndResponseData); * }); * ``` */ $$type = "$PResponse"; __serverRequestAndResponseData = void 0; __error = void 0; url = ""; ok = false; redirected = false; type = "basic"; bodyUsed = false; responses; statusText; status; body; headers; context; /** * # IMPORTANT * We advise you to use the static methods instead of this constructor directly, it will not set the * headers and status correctly so it can lead to unexpected behavior. * Need to clone a response? Use the {@link Response.clone} method instead. * * @param body - The body of the response, it doesn't support FormData, but it supports Blob, ArrayBuffer, * string and object. * @param options - The options of the response. */ constructor(body, options) { const isAJsonObject = typeof body === "object" && body !== null && !(body instanceof Blob) && !(body.$$type === "$PFileLike") && !(body instanceof ArrayBuffer); this.body = isAJsonObject ? JSON.stringify(body) : body; this.context = options?.context; this.headers = options?.headers; this.status = options?.status; this.statusText = options?.statusText; this.ok = options?.status ? isSuccess(options.status) : false; this.redirected = options?.status ? isRedirect(options.status) : false; this.type = options?.status ? isServerError(options.status) ? "error" : "basic" : "basic"; } /** * This method is a factory method that should be used to send a response with a json body. * * By default, it will set the status to 200 and set the content-type header to application/json. * * @example * ```ts * import { Response, path } from '@palmares/server'; * * path('/users').get(async () => { * const users = await getUsers(); * return Response.json(users); * }); * ``` * * @param body - The body to send as json. * @param options - The options to pass to the response. * * @returns - A response with the status set to 200 and the content-type header set to application/json. */ static json(body, options) { const isStatusNotDefined = typeof options?.status !== "number"; const hasNotDefinedJsonHeader = options?.headers?.[DEFAULT_RESPONSE_HEADERS_CONTENT_HEADER_KEY] !== DEFAULT_RESPONSE_CONTENT_HEADER_VALUE_JSON; if (isStatusNotDefined) { if (options) options.status = HTTP_200_OK; else options = { status: HTTP_200_OK }; } if (hasNotDefinedJsonHeader) { if (options) { if (options.headers) options.headers[DEFAULT_RESPONSE_HEADERS_CONTENT_HEADER_KEY] = DEFAULT_RESPONSE_CONTENT_HEADER_VALUE_JSON; else options.headers = { [DEFAULT_RESPONSE_HEADERS_CONTENT_HEADER_KEY]: DEFAULT_RESPONSE_CONTENT_HEADER_VALUE_JSON }; } else options = { headers: { [DEFAULT_RESPONSE_HEADERS_CONTENT_HEADER_KEY]: DEFAULT_RESPONSE_CONTENT_HEADER_VALUE_JSON } }; } const optionsFormatted = options; return new _Response(JSON.stringify(body), optionsFormatted); } /** * Streams a response back to the client. Instead of using a ReadableStream (which is not Supported by * things like React Native.) We opted to use a generator function instead. * You just need to return a generator function that yields chunks of data, and we will stream it back to * the client. Seems easy enough, right? * * @example * ```ts * import { Response, path } from '@palmares/server'; * * path('/users').get(async () => { * const users = await getUsers(); * return Response.stream(function* () { * for (const user of users) { * yield JSON.stringify(user); * } * }); * }); * ``` * * @param body - The generator function to stream back to the client. * @param options - The options to pass to the response. * * @returns - A response with the status set to 200 and the content-type header set to application/octet-stream. */ static stream(body, options) { const isStatusNotDefined = typeof options?.status !== "number"; const hasNotDefinedStreamHeader = options?.headers?.[DEFAULT_RESPONSE_HEADERS_CONTENT_HEADER_KEY] !== DEFAULT_RESPONSE_CONTENT_HEADER_VALUE_STREAM; if (isStatusNotDefined) { if (options) options.status = HTTP_200_OK; else options = { status: HTTP_200_OK }; options.statusText = typeof options.statusText === "string" ? options.statusText : "OK"; } if (hasNotDefinedStreamHeader) { if (options) { if (options.headers) options.headers[DEFAULT_RESPONSE_HEADERS_CONTENT_HEADER_KEY] = DEFAULT_RESPONSE_CONTENT_HEADER_VALUE_STREAM; else options.headers = { [DEFAULT_RESPONSE_HEADERS_CONTENT_HEADER_KEY]: DEFAULT_RESPONSE_CONTENT_HEADER_VALUE_STREAM }; } else options = { headers: { [DEFAULT_RESPONSE_HEADERS_CONTENT_HEADER_KEY]: DEFAULT_RESPONSE_CONTENT_HEADER_VALUE_JSON } }; } const optionsFormatted = options; return new _Response(body, optionsFormatted); } /** * Sends a response back to the client, by default it will set the status to 200 and we will try to * retrieve the content-type from the Blob body sent. * If you also want to send the filename, you can pass it as the second argument using the `filename` * key, OR you can send a FileLike object as the body. * * @example * ```ts * import { Response, FileLike, path } from '@palmares/server'; * * path('/users').get(async () => { * const blob = new Blob(['Hello, world!'], { type: 'text/plain;charset=utf-8' }); * return Response.file(blob, { filename: 'hello.txt' }); * }); * * // OR * * path('/users').get(async () => { * const blob = new Blob(['Hello, world!'], { type: 'text/plain;charset=utf-8' }); * return Response.file(new FileLike(blob, 'hello.txt')); * }); * ``` * * @example * ```ts * import { Response, path } from '@palmares/server'; * * path('/users').get(async () => { * const blob = new Blob(['Hello, world!'], { type: 'text/plain;charset=utf-8' }); * return Response.file(blob); * }); * ``` * * @example * ```ts * import { Response, path } from '@palmares/server'; * * path('/users').get(async () => { * const blob = new Blob(['Hello, world!'], { type: 'text/plain;charset=utf-8' }); * const arrayBuffer = await blob.arrayBuffer(); * return Response.file(arrayBuffer); * }); * ``` * * @param body - The generator function to stream back to the client. * @param options - The options to pass to the response. * * @returns - A response with the status set to 200 and the content-type header set to application/octet-stream. */ static file(body, options) { const isStatusNotDefined = typeof options?.status !== "number"; const hasNotDefinedFileHeader = typeof options?.headers?.[DEFAULT_RESPONSE_HEADERS_CONTENT_HEADER_KEY] !== "string" && typeof options?.headers?.[DEFAULT_RESPONSE_HEADERS_CONTENT_DISPOSITION_KEY] !== "string"; if (isStatusNotDefined) { if (options) options.status = HTTP_200_OK; else options = { status: HTTP_200_OK }; options.statusText = typeof options.statusText === "string" ? options.statusText : "OK"; } if (hasNotDefinedFileHeader && (body.$$type === "$PFileLike" || body instanceof Blob)) { const contentType = body.$$type === "$PFileLike" ? body.blob.type : body.type; const fileName = body.$$type === "$PFileLike" ? body : options?.filename ? options.filename : void 0; if (options) { if (options.headers) { if (!options.headers[DEFAULT_RESPONSE_HEADERS_CONTENT_HEADER_KEY]) options.headers[DEFAULT_RESPONSE_HEADERS_CONTENT_HEADER_KEY] = contentType; if (!options.headers[DEFAULT_RESPONSE_HEADERS_CONTENT_DISPOSITION_KEY]) options.headers[DEFAULT_RESPONSE_HEADERS_CONTENT_HEADER_KEY] = `attachment` + (fileName ? `; filename="${fileName}"` : ""); } else { options.headers = { [DEFAULT_RESPONSE_HEADERS_CONTENT_HEADER_KEY]: contentType, [DEFAULT_RESPONSE_HEADERS_CONTENT_DISPOSITION_KEY]: `attachment` + (fileName ? `; filename="${fileName}"` : "") }; } } else options = { headers: { [DEFAULT_RESPONSE_HEADERS_CONTENT_HEADER_KEY]: contentType, [DEFAULT_RESPONSE_HEADERS_CONTENT_DISPOSITION_KEY]: `attachment` + (fileName ? `; filename="${fileName}"` : "") } }; } const optionsFormatted = options; return new _Response(body, optionsFormatted); } /** * This method should be used to redirect to another page. * By default, it will set the status to 302 and set the location header to the url passed as argument. * * @param url - The url to redirect to. * @param options - The options to pass to the response. * * @example * ```ts * import { Response, path } from '@palmares/server'; * * path('/login').post(async (request) => { * const { username, password } = await request.json(); * if (username === 'admin' && password === 'admin') return Response.redirect('/admin'); * return Response.redirect('/login'); * }); * ``` * * @returns - A response with the status set to 302 and the location header set to the url passed as argument. */ static redirect(url, options) { if (options) { if (options.headers) options.headers[DEFAULT_RESPONSE_HEADERS_LOCATION_HEADER_KEY] = url; else options.headers = { [DEFAULT_RESPONSE_HEADERS_LOCATION_HEADER_KEY]: url }; } else options = { headers: { [DEFAULT_RESPONSE_HEADERS_LOCATION_HEADER_KEY]: url } }; options.status = HTTP_302_FOUND; const optionsFormatted = options; return new _Response(void 0, optionsFormatted); } /** * Factory method to create a response with a html body. This will set the content-type header to text/html. * * @example * ``` * import { Response, path } from '@palmares/server'; * * path('/users').get(async () => { * return Response.html('

Hello World

'); * }); * ``` * * @param htmlBody - The html body to send as a string. * @param options - The options to pass to the response object. * * @returns - A response with the status set to 200 and the content-type header set to text/html. */ static html(htmlBody, options) { const isStatusNotDefined = typeof options?.status !== "number"; const hasNotDefinedJsonHeader = options?.headers?.[DEFAULT_RESPONSE_HEADERS_CONTENT_HEADER_KEY] !== DEFAULT_RESPONSE_CONTENT_HEADER_VALUE_HTML; if (isStatusNotDefined) { if (options) options.status = HTTP_200_OK; else options = { status: HTTP_200_OK }; options.statusText = typeof options.statusText === "string" ? options.statusText : "OK"; } if (hasNotDefinedJsonHeader) { if (options) { if (options.headers) options.headers[DEFAULT_RESPONSE_HEADERS_CONTENT_HEADER_KEY] = DEFAULT_RESPONSE_CONTENT_HEADER_VALUE_HTML; else options.headers = { [DEFAULT_RESPONSE_HEADERS_CONTENT_HEADER_KEY]: DEFAULT_RESPONSE_CONTENT_HEADER_VALUE_HTML }; } else options = { headers: { [DEFAULT_RESPONSE_HEADERS_CONTENT_HEADER_KEY]: DEFAULT_RESPONSE_CONTENT_HEADER_VALUE_HTML } }; } const optionsFormatted = options; return new _Response(htmlBody, optionsFormatted); } /** * Factory method to create a response with a html body. This will set the content-type header to text/html. * * @example * ``` * import { Response, path } from '@palmares/server'; * * path('/users').get(async () => { * return Response.html('

Hello World

'); * }); * ``` * * @param htmlBody - The html body to send as a string. * @param options - The options to pass to the response object. * * @returns - A response with the status set to 200 and the content-type header set to text/html. */ static text(text, options) { const isStatusNotDefined = typeof options?.status !== "number"; const hasNotDefinedJsonHeader = options?.headers?.[DEFAULT_RESPONSE_HEADERS_CONTENT_HEADER_KEY] !== DEFAULT_RESPONSE_CONTENT_HEADER_VALUE_TEXT; if (isStatusNotDefined) { if (options) options.status = HTTP_200_OK; else options = { status: HTTP_200_OK }; options.statusText = typeof options.statusText === "string" ? options.statusText : "OK"; } if (hasNotDefinedJsonHeader) { if (options) { if (options.headers) options.headers[DEFAULT_RESPONSE_HEADERS_CONTENT_HEADER_KEY] = DEFAULT_RESPONSE_CONTENT_HEADER_VALUE_TEXT; else options.headers = { [DEFAULT_RESPONSE_HEADERS_CONTENT_HEADER_KEY]: DEFAULT_RESPONSE_CONTENT_HEADER_VALUE_TEXT }; } else options = { headers: { [DEFAULT_RESPONSE_HEADERS_CONTENT_HEADER_KEY]: DEFAULT_RESPONSE_CONTENT_HEADER_VALUE_TEXT } }; } const optionsFormatted = options; return new _Response(text, optionsFormatted); } /** * This method should be used to send a response with a 500 status code. It will NOT call the error handler. * * @example * ```ts * import { Response, path } from '@palmares/server'; * * path('/users').get(async () => { * const users = await getUsers(); * return Response.error(); * }); * ``` * * @returns - A response with the status set to 500. */ static error() { return new _Response(void 0, { status: HTTP_500_INTERNAL_SERVER_ERROR }); } /** * You know? Sometimes s*it happens, and you need to send an error back to the client. This method is u * sed so you can retrieve the error metadata. This is helpful on the `handler500` on your settings. * You can also extract errors on custom middlewares so you can properly handle them. * * @example * ```ts * import { middleware, Response, path } from '@palmares/server'; * * const validationMiddleware = middleware({ * response: (response) => { * const error = response.error(); * if (error) { * // Do something with the error. * } * return response; * } * }); * * * path('/users').get(async () => { * const users = await getUsers(); * throw new Error('Something went wrong'); * }).middlewares([validationMiddleware]); * ```` * * @returns - The error object. */ error() { return this.__error; } /** * This method should be used to throw a {@link Response}. Throwing a Response will not trigger the * `handler500` function. * * Use it when you want to throw stuff like 404, 403, 401, etc. This is a syntatic sugar for `throw * Response(response)`. * * @example * ```ts * import { Response, path, HTTP_404_NOT_FOUND } from '@palmares/server'; * * function fetchUsersOrThrow() { * const users = await getUsers(); * if (!users) Response.json({ message: 'Users not found' }, { status: HTTP_404_NOT_FOUND }).throw(); * return users; * } * * path('/users').get(async () => { * const users = await fetchUsersOrThrow(); * return Response.json(users); * }); * */ throw() { throw this; } /** * This is similar to the {@link Request.clone()} method. By default it will modify the response in place, * but you can set the `inPlace` option to false to return a new response. * * @param args - The arguments to pass to the new response. * @param options - The options to pass to the new response. */ clone(args, options) { const isInPlace = options?.inPlace !== false; const newResponse = isInPlace ? this : new _Response(args?.body ? args.body : this.body, { headers: args?.headers ? args.headers : this.headers, status: args?.status ? args.status : this.status, context: args?.context ? { ...args.context, ...this.context } : this.context }); newResponse.__serverRequestAndResponseData = this.__serverRequestAndResponseData; newResponse.url = this.url; if (args?.status) { newResponse.ok = isSuccess(args.status); newResponse.redirected = isRedirect(args.status); newResponse.type = isServerError(args.status) ? "error" : "basic"; } return newResponse; } /** * This method is used to get the underlying server data. This is similar to {@link Request.serverData()} * method. This is useful usually on middlewares, not on handlers. * This is the underlying serverData. The documentation of this should be provided by the framework you * are using underlined with Palmares. * So, the idea is simple, when a request is made, the underlying framework will call a callback we * provide passing the data it needs to handle both the request and the response. For Express.js for * example this will be an object containing both the `req` and `res` objects. If for some reason you * need some data or some functionality we do not support by default you can, at any time, call this * function and get this data. * * ### IMPORTANT * * It's not up for us to document this, ask the library author of the adapter to provide a documentation * and properly type this. * * ### IMPORTANT2 * * Understand that when you create a new instance of response we will not have the server data attached to * it, so calling this method will return undefined. * You should use the request to attach the server data to the response. This method is useful for * middlewares, and only that. * * @example * ```ts * // on settings.ts * import { ExpressServerAdapter } from '@palmares/express-adapter'; * import ServerDomain from '@palmares/server'; * * export default defineSettings({ * //...other configs, * installedDomains: [ * [ * ServerDomain, * { * servers: { * default: { * server: ExpressServerAdapter, * // ...other configs, * }, * }, * }, * ], * ], * }); * * // on controllers.ts * import { middleware, path } from '@palmares/server'; * import type { Request, Response } from 'express'; * * const request = new Request(); * request.serverData(); // undefined * * path('/test').get((request) => { * const response = Response.json({ hello: 'World' }); * response.serverData(); // undefined, we have not appended the server data just yet, you should use * // request for that. * return response * }).middlewares([ * middleware({ * response: (response) => { * response.serverData(); // { req: Request, res: Response } * } * }) * }); * ``` * * @returns - The underlying server data. */ serverData() { return this.__serverRequestAndResponseData; } /** * This method will extract the body of the response as a json object. * If the response is not a json response, it will return undefined. * * @example * ```ts * import { Response, path } from '@palmares/server'; * * path('/users').get(async () => { * const users = await getUsers(); * const response = Response.json(users); * await response.json(); // This will return the users object. * return response; * }); * ``` * * @returns - The body of the response as a json object. */ // eslint-disable-next-line ts/require-await async json() { const isNotAJsonResponse = this.headers?.[DEFAULT_RESPONSE_HEADERS_CONTENT_HEADER_KEY] !== DEFAULT_RESPONSE_CONTENT_HEADER_VALUE_JSON && typeof this.body !== "string"; if (isNotAJsonResponse) return void 0; return JSON.parse(this.body); } /** * This method will extract the body of the response as a string. * * @example * ```ts * import { Response, path } from '@palmares/server'; * * path('/users').get(async () => { * const users = await getUsers(); * const response = Response.json(users); * await response.text(); // This will return the users object as a string. * return response; * }); * ``` * * @returns - The body of the response as a string. */ async text() { if (typeof this.body === "object") return JSON.stringify(this.body); else if (typeof this.body === "string") return this.body; else if (this.body instanceof Blob) return this.body.text(); else return void 0; } async arrayBuffer() { if (this.body instanceof ArrayBuffer) return this.body; else if (this.body instanceof Blob) return this.body.arrayBuffer(); else return void 0; } // eslint-disable-next-line ts/require-await async blob() { if (this.body instanceof Blob) return this.body; else if (this.body instanceof ArrayBuffer) return new Blob([ this.body ]); else return void 0; } /** * You can use this method to get the body of the response as a FormData, you cannot send FormData though, * we don't currently support it. * * @example * ```ts * import { Response, path } from '@palmares/server'; * * path('/users').post(async (request) => { * const formData = await request.formData(); * const response = new Response(formData); * * await response.formData() // This will return the formData passed as argument. * * return response; * }); * ``` * * @returns - The body of the response as a {@link FormDataLike} object. */ // eslint-disable-next-line ts/require-await async formData() { const formDataLike = formDataLikeFactory(); if (this.body && this.body?.["$$type"] === "$PFormDataLike") return this.body; else if (typeof this.body === "object") { return new formDataLike({ getKeys: /* @__PURE__ */ __name(() => Object.keys(this.body), "getKeys"), getValue: /* @__PURE__ */ __name((key) => this.body[key], "getValue") }); } else return void 0; } }; // src/response/utils.ts var FileLike = class { static { __name(this, "FileLike"); } $$type = "$PFileLike"; blob; name; constructor(blob, name) { this.blob = blob; this.name = name; } }; var GeneratorFunction = function* () { yield void 0; }.constructor; var AsyncGeneratorFunction = async function* () { yield void 0; }.constructor; // src/request/exceptions.ts var AbortedRequestError = class extends Error { static { __name(this, "AbortedRequestError"); } constructor(reason) { super(reason); this.name = "AbortedRequestError"; } }; // src/request/index.ts var Request = class _Request { static { __name(this, "Request"); } /** * All of those private methods are not really private, we use them internally so we do a typescript * mangling to use them. * * But the intellisense on VSCODE or other editors will not show them. */ __queryParams = void 0; __urlParams = void 0; __serverAdapter = void 0; __requestAdapter = void 0; /** * This is data sent by the server, you can use it to translate your request and response during the * lifecycle of Request/Response. * * Think like that, on express: * * @example * ```ts * app.use((req, res, next) => { * const serverRequestAndResponseData = { req, res }; * await wrappedHandler(serverRequestAndResponseData); * }); * ``` */ __serverRequestAndResponseData = void 0; __query; __headers; __destination; __cachedMethod; __params; __body; __cache; __credentials; __mode; __redirect; __referrer; __referrerPolicy; __integrity; __signal; __validationErrors; __url; __responses; __validation; context; /** * @deprecated - DO NOT create an instance of Request directly, unless you know what you are doing. * If you want to change the request use {@link clone()} instead. */ constructor(options) { const abortController = new AbortController(); this.__signal = { controller: abortController, signal: abortController.signal }; this.context = options?.context; if (options?.destination) this.__destination = Object.freeze({ value: options.destination }); if (options?.cache) this.__cache = Object.freeze({ value: options.cache }); if (options?.credentials) this.__credentials = Object.freeze({ value: options.credentials }); if (options?.mode) this.__mode = Object.freeze({ value: options.mode }); if (options?.redirect) this.__redirect = Object.freeze({ value: options.redirect }); if (options?.referrer) this.__referrer = Object.freeze({ value: options.referrer }); if (options?.integrity) this.__integrity = Object.freeze({ value: options.integrity }); if (options?.method) this.__cachedMethod = Object.freeze({ value: options.method }); if (options?.body) this.__body = Object.freeze({ value: options.body }); this.__headers = new Proxy(options?.headers || {}, { set: /* @__PURE__ */ __name((target, prop, value) => { const propAsString = prop; target[propAsString] = value; return true; }, "set"), get: /* @__PURE__ */ __name((target, prop) => { const propAsString = prop; if (this.__requestAdapter) { const propNotYetCached = !(prop in target); if (propNotYetCached) { const dataFromHeader = this.__requestAdapter.headers(this.__serverAdapter, this.__serverRequestAndResponseData, propAsString); if (dataFromHeader) target[propAsString] = dataFromHeader; } return target[propAsString]; } return void 0; }, "get") }); } /** * This is the method that will be used to get the url of the request, it will be lazy loaded and cached * and cannot be changed. This is because we don't want to parse the url if the user doesn't need it. * * @example * ```ts * const request = new Request({ url: '/test' }); * request.url; //'/test' * * path('/test').get((request) => { * request.url; //'http:mycustomdomain.com/test' * }); * ``` * * @returns - The url of the request. */ get url() { if (this.__url?.value) return this.__url.value; if (this.__requestAdapter && this.__serverAdapter) { const url = this.__requestAdapter.url(this.__serverAdapter, this.__serverRequestAndResponseData); this.__url = Object.freeze({ value: url }); return url; } else return ""; } get cache() { return this.__cache?.value; } get credentials() { return this.__credentials?.value; } get mode() { return this.__mode?.value; } get redirect() { return this.__redirect?.value; } get referrer() { if (this.__referrer?.value) return this.__referrer.value; else { const value = this.headers["Referer"]; if (value) { this.__referrer = Object.freeze({ value }); return value; } } } get referrerPolicy() { if (this.__referrerPolicy?.value) return this.__referrerPolicy.value; else { const value = this.headers["Referrer-Policy"]; if (value) { this.__referrerPolicy = Object.freeze({ value }); return value; } } } get integrity() { return this.__integrity?.value; } get destination() { return this.__destination?.value; } get signal() { return this.__signal.signal; } get responses() { return this.__responses?.value; } /** * This will show the errors that happened on the request. This way you can validate them during the * request response lifecycle. * * By default we give you the data parsed, we just parse the data when you use it. So in other words. * If the request is made and you don't use the data we just don't validate. * * This is nice to keep your application fast and don't get in your way. */ get validationErrors() { return this.__validationErrors; } /** * This will cancel the request lifecycle and will return an 500 error to the client. * * @example * ```ts * path('/test').get((request) => { * request.abort(); * }); * * fetch('/test'); // 500 error * ``` * * @param reason - The reason why the request was aborted. */ abort(reason) { this.__signal.controller.abort(); throw new AbortedRequestError(reason); } /** * This is the method that will be used to get the method of the request, it will be lazy loaded and * cached and cannot be changed. * * @example * ```ts * const request = new Request({ method: 'GET' }); * request.method; //'GET' * * path('/test').get((request) => { * request.method; //'GET' * }); * ``` * * @returns - The method of the request. For reference, see: https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods */ get method() { if (this.__cachedMethod?.value) return this.__cachedMethod.value; else if (this.__requestAdapter && this.__serverAdapter) { const method = this.__requestAdapter.method(this.__serverAdapter, this.__serverRequestAndResponseData); const upperCased = method.toUpperCase(); this.__cachedMethod = Object.freeze({ value: upperCased }); return this.__cachedMethod.value; } else return void 0; } /** * By default this will return nothing, you need to use one of the following methods {@link formData()}, * {@link json()}, {@link text()}, {@link blob()} or {@link arrayBuffer()} to get the body. * This is because we don't want to parse the body if the user doesn't need it. This will JUST have a * value if you use either use {@link clone()} passing a new body or if you create a new instance of * Request passing a body. Otherwise it will always be undefined. * * @example * ```ts * const request = new Request({ body: 'Hello World' }); * request.body; //'Hello World' * * path('/test').get((request) => { * request.body; //undefined * }) * ``` * * @returns - The body of the request. */ get body() { return this.__body?.value; } /** * This will lazy load the headers of the request. Instead of returning the headers directly it is a * proxy, so it's only parsed and translated when needed. * * @example * ```ts * const request = new Request({ headers: { 'Content-Type': 'application/json' } }); * request.headers; // { 'Content-Type': 'application/json' } * * path('/test').get((request) => { * request.headers; // Proxy instance * request.headers['Content-Type']; // 'application/json' * JSON.stringify(request.headers); // '{"Content-Type":"application/json"}' * }); * ``` * * @returns - Returns a proxy that will lazy load the headers of the request. */ get headers() { return this.__headers; } /** * This is an extraction of a piece of code that repeats inside of `query` getter. * * @param target - The target to append the parsed query param. * @param key - The key of the query param. */ __appendUrlParamParsedToTarget(target, key) { if (!this.__urlParams) return void 0; const nonNullableRequestAdapter = this.__requestAdapter; const parserData = this.__urlParams.get(key); const dataFromUrl = nonNullableRequestAdapter.params?.(this.__serverAdapter, this.__serverRequestAndResponseData, key); if (dataFromUrl && parserData) { const parsedData = parseParamsValue(dataFromUrl, parserData); this.__validateParamsAndThrow(key, parsedData, parserData); target[key] = parsedData; } } /** * This is really similar to {@link headers} but it's used for url params instead. * This will lazy load and parse the url parameters of the request. Instead of returning the params * directly it is a proxy, so it's only parsed and translated when needed. * * @example * ```ts * path('/test/').get((request) => { * request.params; // Proxy instance * request.params['filter']; // string type * JSON.stringify(request.headers); // '{"filter":"string"}' * }); * ``` * * @returns - Returns a proxy that will lazy load the headers of the request. */ get params() { if (this.__requestAdapter && this.__serverAdapter) { if (this.__params !== void 0) return this.__params; else { const paramsProxy = new Proxy({}, { get: /* @__PURE__ */ __name((target, prop) => { if (prop.toString() === "toJSON") { if (this.__requestAdapter && this.__urlParams) { return () => { if (!this.__urlParams) return void 0; for (const key of this.__urlParams.keys()) { if (key in target) continue; this.__appendUrlParamParsedToTarget(target, key); } return target; }; } return void 0; } const propAsString = prop; const existsDataOnQuery = this.__urlParams && this.__urlParams.has(propAsString); if (this.__requestAdapter && existsDataOnQuery) { const propNotYetCached = !(prop in target); if (propNotYetCached) this.__appendUrlParamParsedToTarget(target, propAsString); return target[propAsString]; } return void 0; }, "get") }); this.__params = paramsProxy; return paramsProxy; } } else return {}; } __validateQueryParamsAndThrow(name, data, type) { const queryParamIsNotOptional = type.isOptional !== true; const isDataFromQueryUndefinedOrNull = data === void 0 || data === null; const isRequiredQueryParamUndefinedOrNull = isDataFromQueryUndefinedOrNull && queryParamIsNotOptional; const isArrayQueryParamEmpty = queryParamIsNotOptional && Array.isArray(data) && type.isArray && data.length === 0; const isStringQueryParamEmpty = queryParamIsNotOptional && typeof data === "string" && data === ""; const errorsOn = []; if (isArrayQueryParamEmpty) errorsOn.push("isArray"); if (isRequiredQueryParamUndefinedOrNull) errorsOn.push("isOptional", "type"); if (type.regex) errorsOn.push("regex"); if (isRequiredQueryParamUndefinedOrNull || isArrayQueryParamEmpty || isStringQueryParamEmpty) { const errorData = { [name]: { data, errorsOn, type } }; this.__validationErrors = Object.freeze({ query: errorData }); if (this.__validation?.handler) throw this.__validation.handler(this); else throw DEFAULT_SERVER_ERROR_INVALID_QUERY_OR_PARAMS(); } } __validateParamsAndThrow(name, data, type) { const isDataFromParamUndefinedOrNull = data === void 0 || data === null; const isStringParamEmpty = typeof data === "string" && data === ""; if (isDataFromParamUndefinedOrNull || isStringParamEmpty) { const errorData = { [name]: { data, errorsOn: type.regex ? [ "type", "regex" ] : [ "type" ], type } }; this.__validationErrors = Object.freeze({ url: errorData }); if (this.__validation?.handler) throw this.__validation.handler(this); else throw DEFAULT_SERVER_ERROR_INVALID_QUERY_OR_PARAMS(); } } /** * This is an extraction of a piece of code that repeats inside of `query` getter. * * @param target - The target to append the parsed query param. * @param key - The key of the query param. */ __appendQueryParamParsedToTarget(target, key) { if (!this.__queryParams) return void 0; const nonNullableRequestAdapter = this.__requestAdapter; const parserData = this.__queryParams.get(key); const dataFromQuery = nonNullableRequestAdapter.query(this.__serverAdapter, this.__serverRequestAndResponseData, key); if (parserData) { if (dataFromQuery === void 0 && parserData.isOptional !== true) this.__validateQueryParamsAndThrow(key, dataFromQuery, parserData); const parsedData = parseQueryParams(dataFromQuery, parserData); this.__validateQueryParamsAndThrow(key, parsedData, parserData); target[key] = parsedData; } } /** * This is really similar to {@link headers} but it's used for query params instead. * This will lazy load and parse query parameters of the request. Instead of returning the query params * directly it is a proxy, so it's only parsed and translated when needed. * * @example * ```ts * path('/test?filter=string&world=string[]?').get((request) => { * request.query; // Proxy instance * request.query['filter']; // string type * request.query['world']; // string[] | undefined type * JSON.stringify(request.headers); // '{"filter":"string"}' * }); * ``` * * @returns - Returns a proxy that will lazy load the headers of the request. */ get query() { if (this.__requestAdapter) { if (this.__query !== void 0) return this.__query; else { const queryProxy = new Proxy({}, { get: /* @__PURE__ */ __name((target, prop) => { if (prop.toString() === "toJSON") { if (this.__requestAdapter && this.__queryParams) { return () => { if (!this.__queryParams) return void 0; for (const key of this.__queryParams.keys()) { if (key in target) continue; this.__appendQueryParamParsedToTarget(target, key); } return target; }; } return void 0; } const propAsString = prop; const existsDataOnQuery = this.__queryParams && this.__queryParams.has(propAsString); if (this.__requestAdapter && existsDataOnQuery) { const propNotYetCached = !(prop in target); if (propNotYetCached) this.__appendQueryParamParsedToTarget(target, propAsString); return target[propAsString]; } return void 0; }, "get") }); this.__query = queryProxy; return queryProxy; } } else return {}; } /** * This function is used to clone the object, it is the only and the prefered way to make changes to your * request (besides making changes to the `context`). You can use it to change the headers, body, context, * mode, cache, credentials, integrity, destination, referrer and redirect. To improve performance this * will change the values in-place. This means it will change itself and return it again, but you can do * a copy of the object using `{ options: inPlace: false }` * * @example * ```ts * const request = new Request({ headers: { 'Content-Type': 'application/json' } }); * const newRequest = request.clone({ headers: { 'Content-Type': 'application/x-www-form-urlencoded' } }); * request.headers; // { 'Content-Type': 'application/x-www-form-urlencoded' } * newRequest.headers; // { 'Content-Type': 'application/x-www-form-urlencoded' } * * const request = new Request({ headers: { 'Content-Type': 'application/json' } }); * const newRequest = request.clone( * { headers: { 'Content-Type': 'application/x-www-form-urlencoded' } }, * { inPlace: false } * ); * request.headers; // { 'Content-Type': 'application/json' } * newRequest.headers; // { 'Content-Type': 'application/x-www-form-urlencoded' } * ``` * * @param args - The new values you want to set on the request, the values you don't pass will not be overridden. * @param options - The options you want to use when cloning the request. * @param options.inPlace - If you want to clone the request or change it in-place. By default it will * change it in-place. IMPORTANT: The header will NOT be overridden you can just change an existing value * or add a new one. * * @returns - Either a new Request instance or the same instance with new values. */ clone(args, options) { const isInPlace = options?.inPlace !== false; const newRequest = isInPlace ? this : new _Request(); if (args?.body) newRequest.__body = Object.freeze({ value: args.body }); else newRequest.__body = this.__body; if (args?.headers) { const allHeaders = isInPlace ? args.headers : Object.assign(JSON.parse(JSON.stringify(this.__headers)), args.headers); for (const key of Object.keys(allHeaders)) newRequest.__headers[key] = args.headers[key]; } else newRequest.__headers = this.__headers; if (args?.context) newRequest.context = Object.assign(this.context || {}, args.context); else newRequest.context = this.context; if (args?.mode) newRequest.__mode = Object.freeze({ value: args.mode }); else newRequest.__mode = this.__mode; if (args?.cache) newRequest.__cache = Object.freeze({ value: args.cache }); else newRequest.__cache = this.__cache; if (args?.credentials) newRequest.__credentials = Object.freeze({ value: args.credentials }); else newRequest.__credentials = this.__credentials; if (args?.integrity) newRequest.__integrity = Object.freeze({ value: args.integrity }); else newRequest.__integrity = this.__integrity; if (args?.destination) newRequest.__destination = Object.freeze({ value: args.destination }); else newRequest.__destination = this.__destination; if (args?.referrer) newRequest.__referrer = Object.freeze({ value: args.referrer }); else newRequest.__referrer = this.__referrer; if (args?.redirect) newRequest.__redirect = Object.freeze({ value: args.redirect }); else newRequest.__redirect = this.__redirect; if (args?.referrerPolicy) newRequest.__referrerPolicy = Object.freeze({ value: args.referrerPolicy }); else newRequest.__referrerPolicy = this.__referrerPolicy; newRequest.__validation = this.__validation; newRequest.__responses = this.__responses; newRequest.__queryParams = this.__queryParams; newRequest.__urlParams = this.__urlParams; newRequest.__serverAdapter = this.__serverAdapter; newRequest.__requestAdapter = this.__requestAdapter; newRequest.__serverRequestAndResponseData = this.__serverRequestAndResponseData; return newRequest; } /** * This is the underlying serverData. The documentation of this should be provided by the framework you * are using underlined with Palmares. * So, the idea is simple, when a request is made, the underlying framework will call a callback we * provide passing the data it needs to handle both the request and the response. For Express.js for * example this will be an object containing both the `req` and `res` objects. If for some reason you need * some data or some functionality we do not support by default you can, at any time, call this function * and get this data. * * IMPORTANT: It's not up for us to document this, ask the library author of the adapter to provide a * documentation and properly type this. * * @example * ```ts * // on settings.ts * import { ExpressServerAdapter } from '@palmares/express-adapter'; * import ServerDomain from '@palmares/server'; * * export default defineSettings({ * //...other configs, * installedDomains: [ * [ * ServerDomain, * { * servers: { * default: { * server: ExpressServerAdapter, * // ...other configs, * }, * }, * }, * ], * ], * }); * * // on controllers.ts * import type { Request, Response } from 'express'; * * const request = new Request(); * request.serverData(); // undefined * * path('/test').get((request) => { * request.serverData(); // { req: Request, res: Response } * }); * ``` * * @returns - The underlying server data. */ serverData() { return this.__serverRequestAndResponseData; } /** * This should return the body as an ArrayBuffer instance. If the body is not an ArrayBuffer it should * return undefined. You should search for documentation of the underlying adapter to understand WHEN * it will return an ArrayBuffer (usually might depend of 'Content-Type' header) * * @example * ```ts * const request = new Request({ body: new ArrayBuffer(10) }); * await request.arrayBuffer(); // ArrayBuffer(10) * * path('/test').post(async (request) => { * await request.arrayBuffer(); // ArrayBuffer | undefined * }); * * fetch('/test', { * method: 'POST', * headers: { * 'Content-Type': 'application/octet-stream' * }, * body: new ArrayBuffer(10) * }); * ``` * * @param options - Those options are custom options you want to pass to the underlying adapter instance * when retrieving the array buffer, see the documentation of the underlying adapter. You can retrieve * those options by: 'MyCustomFrameworkRequestAdapter.customToArrayBufferOptions?.()' if it is implemented. */ async arrayBuffer(options) { if (this.body instanceof ArrayBuffer) return this.body; if (this.__serverRequestAndResponseData && this.__requestAdapter && this.__serverAdapter) return this.__requestAdapter.toArrayBuffer(this.__serverAdapter, this.__serverRequestAndResponseData, options); return void 0; } /** * This SHOULD return a json body when the 'Content-Type' on the request header is `application/json`. * * @example * ```ts * const request = new Request({ body: { hello: 'world' } }); * await request.json(); // { hello: 'world' } * * path('/test').post(async (request) => { * await request.json(); // { hello: 'world' } | undefined * }); * * fetch('/test', { * method: 'POST', * headers: { * 'Content-Type': 'application/json' * }, * body: JSON.stringify({ hello: 'world' }) * }); * ``` * * @param options - Those options are custom options you want to pass to the underlying adapter instance * when retrieving the json, see the documentation of the underlying adapter. You can retrieve those * options by: 'MyCustomFrameworkRequestAdapter.customToJsonOptions?.()' if it is implemented. */ async json(options) { if (typeof this.body === "object" && this.body !== null) return this.body; if (this.__serverRequestAndResponseData && this.__requestAdapter && this.__serverAdapter) return this.__requestAdapter.toJson(this.__serverAdapter, this.__serverRequestAndResponseData, options); return void 0; } /** * This should return the body as a Blob instance. If the body is not a Blob it should return undefined. * You should search for documentation of the underlying adapter to understand WHEN it will return a * Blob (usually might depend of 'Content-Type' header) * * @example * ```ts * const request = new Request({ body: new Blob() }); * request.blob(); // Blob * * path('/test').post((request) => { * request.blob(); // Blob | undefined * }); * * fetch('/test', { * method: 'POST', * headers: { * 'Content-Type': 'application/octet-stream' * }, * body: new Blob() * }); * ``` * * @param options - Those options are custom options you want to pass to the underlying adapter instance * when retrieving the blob, see the documentation of the underlying adapter. You can retrieve those * options by: 'MyCustomFrameworkRequestAdapter.customToBlobOptions?.()' if it is implemented. */ async blob(options) { if (this.body instanceof Blob || this.body instanceof File) return this.body; if (this.__serverRequestAndResponseData && this.__requestAdapter && this.__serverAdapter) return this.__requestAdapter.toBlob(this.__serverAdapter, this.__serverRequestAndResponseData, options); return void 0; } /** * This should contain data when the 'Content-Type' on the request is a `multipart/form-data` or * `application/x-www-form-urlencoded`. Otherwise it should be undefined. * * This should be used for retrieving a FormData-like instance. FormData is not available on Node.js and * might not be supported on other runtimes, * so in order to support it we have created a FormData-like class that has the same API as the original * FormData with some extensions. * * See: https://developer.mozilla.org/en-US/docs/Web/API/FormData * * @example * ```ts * const request = new Request({ body: new FormData() }); * await request.formData(); // Blob * * path('/test').post(async (request) => { * request.formData(); // FormDataLike | undefined * }); * * fetch('/test', { * method: 'POST', * headers: { * 'Content-Type': 'application/form-data' * }, * body: new FormData() * }); * ``` * * @param options - Those options are custom options you want to pass to the underlying framework instance * when retrieving the form data. * You can retrieve those options by: 'MyCustomFrameworkRequestAdapter.customToBlobOptions?.()' if it is implemented. */ async formData(options) { if (this.__serverRequestAndResponseData && this.__requestAdapter && this.__serverAdapter) return this.__requestAdapter.toFormData(this.__serverAdapter, this.__serverRequestAndResponseData, formDataLikeFactory(), this.headers[DEFAULT_REQUEST_HEADERS_CONTENT_HEADER_KEY] === DEFAULT_REQUEST_CONTENT_HEADER_VALUE_URLENCODED, options); return void 0; } /** * This should return the body as a string. If the body is not a string it should return undefined. * You should search for documentation of the underlying adapter to understand WHEN it will return a * string (usually might depend of 'Content-Type' header) * * @example * ```ts * const request = new Request({ body: 'Hello World' }); * await request.text(); // 'Hello World' * * path('/test').post(async (request) => { * await request.text(); // 'Hello World' | undefined * }); * * fetch('/test', { * method: 'POST', * headers: { * 'Content-Type': 'text/plain' * }, * body: 'Hello World' * }); * ``` * * @param options - Those options are custom options you want to pass to the underlying adapter instance * when retrieving the text, see the documentation of the underlying adapter. You can retrieve those options by: * 'MyCustomFrameworkRequestAdapter.customToTextOptions?.()' if it is implemented. */ async text(options) { if (typeof this.body === "string") return this.body; if (this.__serverRequestAndResponseData && this.__requestAdapter && this.__serverAdapter) return this.__requestAdapter.toText(this.__serverAdapter, this.__serverRequestAndResponseData, options); return void 0; } /** * Should return the raw data of the request, whatever you have on the request body should be returned here. * * @example * ```ts * const request = new Request({ body: 'Hello World' }); * await request.raw(); // 'Hello World' * * path('/test').post(async (request) => { * await request.raw(); // 'Hello World' | undefined * }); * ``` * * @param options - Those options are custom options you want to pass to the underlying adapter instance * when retrieving the raw data, see the documentation of the underlying adapter. You can retrieve those * options by: 'MyCustomFrameworkRequestAdapter.customToRawOptions?.()' if it is implemented. */ async raw(options) { if (this.__serverRequestAndResponseData && this.__requestAdapter && this.__serverAdapter) return this.__requestAdapter.toRaw(this.__serverAdapter, this.__serverRequestAndResponseData, options); return void 0; } }; // src/domain/index.ts var import_core5 = require("@palmares/core"); // src/app/index.ts var import_core3 = require("@palmares/core"); // src/app/exceptions.ts var ServerAlreadyInitializedError = class extends Error { static { __name(this, "ServerAlreadyInitializedError"); } constructor() { super("Server was already initialized"); } }; var ResponseNotReturnedFromResponseOnMiddlewareError = class extends Error { static { __name(this, "ResponseNotReturnedFromResponseOnMiddlewareError"); } constructor() { super(`Response was not returned from '.response()' method on middleware.`); } }; var RedirectionStatusCodesMustHaveALocationHeaderError = class extends Error { static { __name(this, "RedirectionStatusCodesMustHaveALocationHeaderError"); } constructor() { super(`Redirection status codes must have a 'Location' header. You can set it by using the 'headers' option when creating a new 'Response' instance. Or just use 'Response.redirect()' method.`); } }; var HandlerOrHandlersShouldBeDefinedOnRouterAdapterError = class _HandlerOrHandlersShouldBeDefinedOnRouterAdapterError extends Error { static { __name(this, "HandlerOrHandlersShouldBeDefinedOnRouterAdapterError"); } constructor() { super(`Either 'parseHandler' or 'parseHandlers' methods/functions should be defined on router adapter. If none of them are defined, the router will not work.`); this.name = _HandlerOrHandlersShouldBeDefinedOnRouterAdapterError.name; } }; // src/app/utils.ts var import_core2 = require("@palmares/core"); // src/logging.ts var import_logging = require("@palmares/logging"); var serverLogger = new import_logging.Logger({ domainName: "@palmares/server" }, { START_SERVER: { category: "log", handler: /* @__PURE__ */ __name((args) => `Server ${args.serverName} started on port ${args.port}`, "handler") }, STOP_SERVER: { category: "log", handler: /* @__PURE__ */ __name((args) => `Server ${args.serverName} stopped`, "handler") }, REQUEST_RECEIVED: { category: "info", handler: /* @__PURE__ */ __name((args) => `\x1B[3m${args.method}\x1B[0m ${args.url} ${args.timePassed}`, "handler") }, SERVERLESS_HANDLER_CREATED: { category: "info", handler: /* @__PURE__ */ __name((args) => `Serverless handler created for ${args.url} on \x1B[3m${args.path}\x1B[0m`, "handler") }, SERVERLESS_HANDLER_UPDATED: { category: "info", handler: /* @__PURE__ */ __name((args) => `Serverless handler updated for \x1B[1m${args.method}\x1B[0m ${args.url} on \x1B[3m${args.path}\x1B[0m`, "handler") } }); // src/app/utils.ts async function getRootRouterCompletePaths(domains, settings, isDebugModeEnabled = true) { const extractedRouterInterceptors = []; const extractedRoutes = []; for (const domain2 of domains) { if (domain2.getRoutes) extractedRoutes.push(Promise.resolve(domain2.getRoutes()).then((route) => { const routeWithProtected = route; routeWithProtected.__domain = domain2; return routeWithProtected; })); if (domain2.routerInterceptor) extractedRouterInterceptors.push(domain2.routerInterceptor); } const allRoutes = await Promise.all(extractedRoutes); const allRoutesWithOrWithoutErrorHandler = isDebugModeEnabled ? allRoutes.concat([ errorCaptureHandler() ]) : allRoutes; const rootRouter = path(settings.prefix ? settings.prefix : "").nested(allRoutesWithOrWithoutErrorHandler); const rootRouterCompletePaths = rootRouter.__completePaths; if (extractedRouterInterceptors.length > 0) await Promise.all(extractedRouterInterceptors.map(async (routerInterceptor) => await routerInterceptor(rootRouterCompletePaths))); return rootRouter.__completePaths; } __name(getRootRouterCompletePaths, "getRootRouterCompletePaths"); async function* wrappedMiddlewareRequests(middlewares, request) { let middlewareIndex = 0; for (const middleware2 of middlewares) { middlewareIndex++; if (middleware2.request) { const responseOrRequest = await middleware2.request(request); if (responseOrRequest?.["$$type"] === "$PResponse") yield [ middlewareIndex, responseOrRequest ]; else { request = responseOrRequest; yield [ middlewareIndex, responseOrRequest ]; } } } } __name(wrappedMiddlewareRequests, "wrappedMiddlewareRequests"); async function* wrappedMiddlewareResponses(middlewares, response, middlewareOnionIndex) { for (let i = middlewareOnionIndex; i >= 0; i--) { const middleware2 = middlewares[i]; if (!middleware2) continue; if (middleware2.response) { response = await middleware2.response(response); yield response; } } } __name(wrappedMiddlewareResponses, "wrappedMiddlewareResponses"); async function appendErrorToResponseAndReturnResponseOrThrow(response, error, handler500) { if (error?.["$$type"] === "$PResponse") return error; else if (!handler500) throw error; response = await Promise.resolve(handler500(response)); if (response?.["$$type"] === "$PResponse") return response; else throw error; } __name(appendErrorToResponseAndReturnResponseOrThrow, "appendErrorToResponseAndReturnResponseOrThrow"); function appendTranslatorToRequest(request, serverAdapter2, serverRequestAdapter2, serverRequestAndResponseData, queryParams, urlParams, validation, options) { const requestWithoutPrivateMethods = request; if (options?.responses) requestWithoutPrivateMethods.__responses = Object.freeze({ value: options.responses }); requestWithoutPrivateMethods.__validation = validation; requestWithoutPrivateMethods.__serverAdapter = serverAdapter2; requestWithoutPrivateMethods.__serverRequestAndResponseData = serverRequestAndResponseData; requestWithoutPrivateMethods.__requestAdapter = serverRequestAdapter2; requestWithoutPrivateMethods.__queryParams = queryParams; requestWithoutPrivateMethods.__urlParams = urlParams; return request; } __name(appendTranslatorToRequest, "appendTranslatorToRequest"); function appendTranslatorToResponse(response, serverAdapter2, serverResponseAdapter2, serverRequestAndResponseData, options) { const responseWithoutPrivateMethods = response; if (options?.responses) responseWithoutPrivateMethods.responses = Object.freeze({ value: options.responses }); responseWithoutPrivateMethods.__serverAdapter = serverAdapter2; responseWithoutPrivateMethods.__serverRequestAndResponseData = serverRequestAndResponseData; responseWithoutPrivateMethods.__responseAdapter = serverResponseAdapter2; return response; } __name(appendTranslatorToResponse, "appendTranslatorToResponse"); async function translateResponseToServerResponse(response, method, server, serverRequestAndResponseData) { const responseStatus = response.status || DEFAULT_STATUS_CODE_BY_METHOD(method); const isRedirectResponse = isRedirect(responseStatus); const isStreamResponse = ( // eslint-disable-next-line ts/no-unnecessary-condition response.body && response.body instanceof GeneratorFunction || response.body instanceof AsyncGeneratorFunction ); const isFileResponse = ( // eslint-disable-next-line ts/no-unnecessary-condition response.body && response.body instanceof Blob || response.body?.$$type === "$PFileLike" || response.body instanceof ArrayBuffer ); if (isRedirectResponse && !response.headers?.[DEFAULT_RESPONSE_HEADERS_LOCATION_HEADER_KEY]) throw new RedirectionStatusCodesMustHaveALocationHeaderError(); if (isRedirectResponse) return server.response.redirect(server, serverRequestAndResponseData, responseStatus, response.headers, response.headers[DEFAULT_RESPONSE_HEADERS_LOCATION_HEADER_KEY]); if (isStreamResponse) return server.response.stream(server, serverRequestAndResponseData, responseStatus, response.headers, response.body(), response.body instanceof AsyncGeneratorFunction); if (isFileResponse) return server.response.sendFile(server, serverRequestAndResponseData, responseStatus, response.headers, response.body); return server.response.send(server, serverRequestAndResponseData, responseStatus, response.headers, response.body); } __name(translateResponseToServerResponse, "translateResponseToServerResponse"); function translatePathFactory(serverAdapter2) { const translatedPathsByRawPath = /* @__PURE__ */ new Map(); return (path2, partsOfPath, urlParams) => { let fullPath = translatedPathsByRawPath.get(path2) || ""; if (fullPath === "") { for (const path3 of partsOfPath) { const urlParamType = path3.isUrlParam ? urlParams.get(path3.part) : void 0; const translatedPartOfPath = serverAdapter2.routers.parseRoute(serverAdapter2, path3.part, urlParamType); if (translatedPartOfPath === void 0) continue; fullPath += "/" + translatedPartOfPath; } } return fullPath; }; } __name(translatePathFactory, "translatePathFactory"); function wrapHandlerAndMiddlewares(method, middlewares, queryParams, urlParams, handler, options, server, handler500, validation) { const wrappedHandler = /* @__PURE__ */ __name(async (serverRequestAndResponseData) => { const startTime = (/* @__PURE__ */ new Date()).getTime(); let request = appendTranslatorToRequest(new Request(), server, server.request, serverRequestAndResponseData, queryParams, urlParams, validation, options); let response = void 0; let wasErrorAlreadyHandledInRequestLifecycle = false; let middlewareOnionIndex = 0; try { for await (const [middlewareIndex, responseOrRequest] of wrappedMiddlewareRequests(middlewares, request)) { middlewareOnionIndex = middlewareIndex; const isResponse = responseOrRequest?.["$$type"] === "$PResponse"; if (isResponse) response = appendTranslatorToResponse(responseOrRequest, server, server.response, serverRequestAndResponseData, options); else request = appendTranslatorToRequest(responseOrRequest, server, server.request, serverRequestAndResponseData, queryParams, urlParams, validation, options); } const responseNotSet = response === void 0; if (responseNotSet) { const handlerResponse = appendTranslatorToResponse(await Promise.resolve(handler(request)), server, server.response, serverRequestAndResponseData, options); if (handlerResponse) response = handlerResponse; } } catch (error) { const isResponseError = error?.["$$type"] === "$PResponse"; const errorAsError = error; let errorResponse = isResponseError ? error : server.settings.debug === true ? DEFAULT_SERVER_ERROR_RESPONSE(errorAsError, server.allSettings, server.domains) : new Response(void 0, { status: HTTP_500_INTERNAL_SERVER_ERROR }); wasErrorAlreadyHandledInRequestLifecycle = true; errorResponse = appendTranslatorToResponse(errorResponse, server, server.response, serverRequestAndResponseData, options); errorResponse = isResponseError ? errorResponse : await appendErrorToResponseAndReturnResponseOrThrow(errorResponse, errorAsError, handler500); response = appendTranslatorToResponse(errorResponse, server, server.response, serverRequestAndResponseData, options); } try { if (response) { for await (const modifiedResponse of wrappedMiddlewareResponses(middlewares, response, middlewareOnionIndex)) { const isResponse = modifiedResponse?.["$$type"] === "$PResponse"; if (isResponse) response = appendTranslatorToResponse(modifiedResponse, server, server.response, serverRequestAndResponseData, options); else throw new ResponseNotReturnedFromResponseOnMiddlewareError(); } serverLogger.logMessage("REQUEST_RECEIVED", { method: request.method, url: request.url, timePassed: (/* @__PURE__ */ new Date()).getTime() - startTime }); return translateResponseToServerResponse(response, method, server, serverRequestAndResponseData); } } catch (error) { if (wasErrorAlreadyHandledInRequestLifecycle === false) { const isResponseError = error?.["$$type"] === "$PResponse"; let errorResponse = isResponseError ? error : server.settings.debug === true ? DEFAULT_SERVER_ERROR_RESPONSE(error, server.allSettings, server.domains) : new Response(void 0, { status: HTTP_500_INTERNAL_SERVER_ERROR }); errorResponse = appendTranslatorToResponse(errorResponse, server, server.response, serverRequestAndResponseData, options); errorResponse = isResponseError ? errorResponse : await appendErrorToResponseAndReturnResponseOrThrow(errorResponse, error, handler500); response = appendTranslatorToResponse(errorResponse, server, server.response, serverRequestAndResponseData, options); } serverLogger.logMessage("REQUEST_RECEIVED", { method: request.method, url: request.url, timePassed: (/* @__PURE__ */ new Date()).getTime() - startTime }); if (response) return translateResponseToServerResponse(response, method, server, serverRequestAndResponseData); else throw error; } }, "wrappedHandler"); return wrappedHandler.bind(wrappedHandler); } __name(wrapHandlerAndMiddlewares, "wrapHandlerAndMiddlewares"); function generateServerlessHandler(settings, allSettings, serverName, domainName, method, path2, pathOfHandler) { const shouldBeTypeAnnotated = allSettings.settingsLocation.endsWith(".ts"); const extension = allSettings.settingsLocation.split(".").pop(); return { appendBody: /* @__PURE__ */ __name((args) => { if (pathOfHandler === void 0) throw new Error("You should call writeFile before appendBody"); serverLogger.logMessage("SERVERLESS_HANDLER_UPDATED", { method: method.toUpperCase(), path: pathOfHandler.pathOfHandler, url: path2 }); return import_core2.std.files.appendFile(pathOfHandler.pathOfHandler, ` async function ${args.functionName}(${args.parameters.map((parameter) => { if (shouldBeTypeAnnotated && typeof parameter !== "object" || typeof parameter?.type !== "string") throw new Error("The parameter must have a type when generating a serverless handler."); if (typeof parameter === "object") return `${parameter.name}: ${parameter.type}`; return parameter; }).join(", ")}) { return Serverless.handleServerless(settings, { requestAndResponseData: ${args.requestAndResponseData}, getRoute: () => ${args.getRouteFunctionBody}, serverName: '${serverName}', adapter: ${args.adapter}, getMethod: () => ${args.getMethodFunctionBody}${args.isSpecificMethod || args.isSpecificRoute ? "," : ""} ` + (args.isSpecificMethod ? ` method: '${method}', ` : "") + (args.isSpecificRoute ? ` route: '${path2}', domainRoutes: ['${domainName}'] ` : ` domainRoutes: [] `) + ` }); } ` + (args.customExport ? args.customExport : args.isCJSModule ? `exports.${args.functionName} = ${args.functionName};` : args.isDefaultExport ? `export default ${args.functionName};` : `export { ${args.functionName} }; `)); }, "appendBody"), writeFile: /* @__PURE__ */ __name(async (args) => { args.pathOfHandlerFile[args.pathOfHandlerFile.length - 1] = `${args.pathOfHandlerFile[args.pathOfHandlerFile.length - 1]}.${extension}`; let numberOfTwoDotsOnServerlessLocation = 0; let numberOfDirectoriesToGoBackOnSettingsFromServerlessFolderLocation = 0; for (const pathParts of (settings.serverlessFolderLocation || "").split("/")) { if (pathParts === "..") numberOfTwoDotsOnServerlessLocation++; if (pathParts !== "." && pathParts !== ".." && pathParts !== "") numberOfDirectoriesToGoBackOnSettingsFromServerlessFolderLocation++; } const basePathGoingBackFromServerlessLocation = await import_core2.std.files.join(allSettings.basePath, ...Array.from({ length: numberOfTwoDotsOnServerlessLocation }).map(() => "..")); const pathWithoutBasePath = allSettings.settingsLocation.replace(basePathGoingBackFromServerlessLocation, ""); const baseDirectoryOfHandlerFile = settings.serverlessFolderLocation ? await import_core2.std.files.join(allSettings.basePath, settings.serverlessFolderLocation, await import_core2.std.files.join(...args.pathOfHandlerFile.slice(0, -1))) : await import_core2.std.files.join(allSettings.basePath, await import_core2.std.files.join(...args.pathOfHandlerFile.slice(0, -1))); const existsDirectory = await import_core2.std.files.exists(baseDirectoryOfHandlerFile); if (existsDirectory === false) await import_core2.std.files.makeDirectory(baseDirectoryOfHandlerFile); const pathWithFile = await import_core2.std.files.join(baseDirectoryOfHandlerFile, args.pathOfHandlerFile[args.pathOfHandlerFile.length - 1]); pathOfHandler.pathOfHandler = pathWithFile; const numberOfDirectoriesToGoBackOnSettings = numberOfDirectoriesToGoBackOnSettingsFromServerlessFolderLocation + args.pathOfHandlerFile.length - 1; serverLogger.logMessage("SERVERLESS_HANDLER_CREATED", { path: pathWithFile, url: path2 }); return import_core2.std.files.writeFile(pathWithFile, `import { Serverless } from '@palmares/server'; import { ${args.adapter.name} } from '${args.projectName}'; import settings from '${Array.from({ length: numberOfDirectoriesToGoBackOnSettings }).map(() => "..").join("/") + pathWithoutBasePath.replace(`.${extension}`, "")}'; `); }, "writeFile") }; } __name(generateServerlessHandler, "generateServerlessHandler"); function doTheRoutingForServerlessOnly(serverAdapter2, partsOfPath, urlParams, routeToFilter) { const regex = new RegExp(`^(\\/?)${partsOfPath.map((part) => { if (part.isUrlParam) return `(${urlParams.get(part.part)?.regex?.toString().replace(/(\/(\^)?(\()?|(\))?(\$)?\/)/g, "")})`; return part.part; }).join("\\/")}(\\/?)$`); const groups = routeToFilter.match(regex); if (regex.test(routeToFilter) === false) return false; const existingRequestParams = serverAdapter2.request.params; serverAdapter2.request.params = (_server, _serverRequestAndResponseData, key) => { const result = existingRequestParams?.(_server, _serverRequestAndResponseData, key); if (result === "" || result === void 0) return groups?.groups?.[key] || ""; return result; }; return true; } __name(doTheRoutingForServerlessOnly, "doTheRoutingForServerlessOnly"); async function* getAllRouters(domains, settings, allSettings, serverAdapter2, options) { const methodToFilterWhenOnServerlessEnvironment = options?.serverless?.use.method; const routeToFilterWhenOnServerlessEnvironment = options?.serverless?.use.route; const isUseServerless = ( // eslint-disable-next-line ts/no-unnecessary-condition serverAdapter2?.$$type === "$PServerlessAdapter" && typeof options?.serverless?.use === "object" ); const isGeneratingServerless = ( // eslint-disable-next-line ts/no-unnecessary-condition serverAdapter2?.$$type === "$PServerlessAdapter" && options?.serverless?.generate === true ); const translatePath = translatePathFactory(serverAdapter2); const existsRootMiddlewares = Array.isArray(settings.middlewares) && settings.middlewares.length > 0; const rootRouterCompletePaths = await getRootRouterCompletePaths(domains, settings, settings.debug === true); for (const [path2, router] of rootRouterCompletePaths) { const handlerByMethod = Object.entries(router.handlers || {}); if (handlerByMethod.length === 0) continue; const [, firstHandler] = handlerByMethod[0]; if (!firstHandler) continue; let translatedPath = ""; if (isUseServerless && typeof routeToFilterWhenOnServerlessEnvironment === "string") { if (doTheRoutingForServerlessOnly(serverAdapter2, router.partsOfPath, router.urlParams, routeToFilterWhenOnServerlessEnvironment) === false) continue; } else translatedPath = translatePath(path2, router.partsOfPath, router.urlParams); if (isGeneratingServerless) { const pathOfHandler = { pathOfHandler: "" }; yield { translatedPath, handlers: handlerByMethod.reduce((accumulator, currentValue) => { const [method, handler] = currentValue; const routerWithProtected = router.router; accumulator.set(method, { handler: generateServerlessHandler(settings, allSettings, serverAdapter2.serverName, routerWithProtected.__domain.name, method, path2, pathOfHandler), options: handler.options?.customRouterOptions }); return accumulator; }, /* @__PURE__ */ new Map()), queryParams: router.queryParams }; } const shouldFilterMethod = isUseServerless && typeof methodToFilterWhenOnServerlessEnvironment === "string"; const handlersOfRouterByMethod = handlerByMethod.reduce((accumulator, currentValue) => { const [method, handler] = currentValue; const shouldBypassMethodWrapperOnServerless = shouldFilterMethod && method !== methodToFilterWhenOnServerlessEnvironment && method !== "all"; if (shouldBypassMethodWrapperOnServerless) return accumulator; const wrappedHandler = wrapHandlerAndMiddlewares(method, existsRootMiddlewares ? settings.middlewares.concat(router.middlewares) : router.middlewares, router.queryParams, router.urlParams, handler.handler, handler.options, serverAdapter2, settings.handler500, settings.validation); accumulator.set(method, { handler: wrappedHandler, options: handler.options?.customRouterOptions }); return accumulator; }, /* @__PURE__ */ new Map()); yield { translatedPath, handlers: handlersOfRouterByMethod, queryParams: router.queryParams }; } } __name(getAllRouters, "getAllRouters"); async function* getAllHandlers(domains, settings, serverAdapter2) { const existsRootMiddlewares = Array.isArray(settings.middlewares) && settings.middlewares.length > 0; const rootRouterCompletePaths = await getRootRouterCompletePaths(domains, settings); for (const [path2, router] of rootRouterCompletePaths) { const handlerByMethod = Object.entries(router.handlers || {}); if (handlerByMethod.length === 0) continue; for (const [method, handler] of handlerByMethod) { const wrappedHandler = wrapHandlerAndMiddlewares(method, existsRootMiddlewares ? settings.middlewares.concat(router.middlewares) : router.middlewares, router.queryParams, router.urlParams, handler.handler, handler.options, serverAdapter2, settings.handler500); yield { path: path2, method, options: handler.options?.customRouterOptions, handler: wrappedHandler, partsOfPath: router.partsOfPath, queryParams: router.queryParams, urlParams: router.urlParams }; } } } __name(getAllHandlers, "getAllHandlers"); function wrap404HandlerAndRootMiddlewares(serverAdapter2, middlewares, handler404, handler500) { async function wrapped404Handler(serverRequestAndResponseData) { if (!handler404) return; let response = appendTranslatorToResponse(new Response(void 0, { status: HTTP_404_NOT_FOUND, statusText: DEFAULT_NOT_FOUND_STATUS_TEXT_MESSAGE }), serverAdapter2, serverAdapter2.response, serverRequestAndResponseData, void 0); try { response = await handler404(response); if (response) { for await (const modifiedResponse of wrappedMiddlewareResponses(middlewares, response, middlewares.length - 1)) { const isResponse = modifiedResponse?.["$$type"] === "$PResponse"; if (isResponse) response = appendTranslatorToResponse(modifiedResponse, serverAdapter2, serverAdapter2.response, serverRequestAndResponseData, void 0); else throw new ResponseNotReturnedFromResponseOnMiddlewareError(); } return translateResponseToServerResponse(response, "get", serverAdapter2, serverRequestAndResponseData); } } catch (error) { if (handler500) response = await handler500(response); if (response) return translateResponseToServerResponse(response, "get", serverAdapter2, serverRequestAndResponseData); else throw error; } } __name(wrapped404Handler, "wrapped404Handler"); return wrapped404Handler; } __name(wrap404HandlerAndRootMiddlewares, "wrap404HandlerAndRootMiddlewares"); async function initializeRouters(domains, settings, allSettings, serverAdapter2, options) { const generateServerless = options?.serverless?.generate === true; const useServerless = typeof options?.serverless?.use === "object"; const method = (options?.serverless?.use?.getMethod() || "").toLowerCase(); const route = options?.serverless?.use?.getRoute(); const serverRequestAndResponseData = options?.serverless?.use?.requestAndResponseData; let wrapped404Handler = /* @__PURE__ */ __name(async () => void 0, "wrapped404Handler"); if (!useServerless) { wrapped404Handler = wrap404HandlerAndRootMiddlewares(serverAdapter2, settings.middlewares || [], settings.handler404, settings.handler500); } if (serverAdapter2.routers.parseHandlers || useServerless) { const routers = getAllRouters(domains, settings, allSettings, serverAdapter2, { serverless: { generate: generateServerless, use: { method, route } } }); for await (const router of routers) { if (useServerless && router.handlers.has(method) || router.handlers.get("all")) { if (router.handlers.has(method)) return router.handlers.get(method)?.handler(serverRequestAndResponseData); else return router.handlers.get("all")?.handler(serverRequestAndResponseData); } else if (useServerless === false && serverAdapter2.routers.parseHandlers) { if (serverAdapter2.$$type === "$PServerAdapter") { serverAdapter2 = serverAdapter2; serverAdapter2.routers.parseHandlers?.(serverAdapter2, router.translatedPath, router.handlers, router.queryParams, wrapped404Handler); } else if (serverAdapter2.$$type === "$PServerlessAdapter") { await serverAdapter2.routers.parseHandlers(serverAdapter2, allSettings.basePath, router.translatedPath, router.handlers, router.queryParams, wrapped404Handler); } } } } else if (serverAdapter2.$$type === "$PServerAdapter" && // eslint-disable-next-line ts/no-unnecessary-condition serverAdapter2.routers.parseHandler !== void 0) { const translatePath = translatePathFactory(serverAdapter2); const handlers = getAllHandlers(domains, settings, serverAdapter2); for await (const handler of handlers) { const translatedPath = translatePath(handler.path, handler.partsOfPath, handler.urlParams); serverAdapter2.routers.parseHandler(serverAdapter2, translatedPath, handler.method, handler.handler, handler.options, handler.queryParams); } } else throw new HandlerOrHandlersShouldBeDefinedOnRouterAdapterError(); if (useServerless) return wrapped404Handler(serverRequestAndResponseData); if (settings.handler404) serverAdapter2.routers.load404(serverAdapter2, wrapped404Handler); } __name(initializeRouters, "initializeRouters"); // src/app/index.ts function getServerInstances() { if (!globalThis.$PServerInstances) globalThis.$PServerInstances = /* @__PURE__ */ new Map(); return globalThis.$PServerInstances; } __name(getServerInstances, "getServerInstances"); var httpAppServer = (0, import_core3.appServer)({ load: /* @__PURE__ */ __name(async (args) => { const serverEntries = Object.entries(args.settings.servers); for (const [serverName, serverSettings] of serverEntries) { const serverInstances = getServerInstances(); const serverWasNotInitialized = !serverInstances.has(serverName); if (serverWasNotInitialized) { const newServerInstance = new serverSettings.server(serverName, args.settings, args.settings.servers[serverName], args.domains); serverInstances.set(serverName, { server: newServerInstance, settings: serverSettings }); await newServerInstance.load(serverName, args.domains, serverSettings); await initializeRouters(args.domains, serverSettings, args.settings, newServerInstance); } else throw new ServerAlreadyInitializedError(); } }, "load"), start: /* @__PURE__ */ __name(async (configureCleanup) => { const promises = []; const serverInstances = getServerInstances(); for (const [serverName, { server, settings }] of serverInstances.entries()) { if (server?.$$type === "$PServerAdapter") { promises.push(server.start(serverName, settings.port || DEFAULT_SERVER_PORT, () => { serverLogger.logMessage("START_SERVER", { port: settings.port || DEFAULT_SERVER_PORT, serverName }); })); } } await Promise.all(promises.concat(Promise.resolve(configureCleanup()))); }, "start"), close: /* @__PURE__ */ __name(async () => { const serverInstances = getServerInstances(); for (const [serverName, { server }] of serverInstances.entries()) { serverLogger.logMessage("STOP_SERVER", { serverName }); if (server?.$$type === "$PServerAdapter") await server.close(); } }, "close") }); // src/serverless.ts var import_core4 = require("@palmares/core"); var Serverless = class { static { __name(this, "Serverless"); } /** * Generate the serverless functions. We still use initializeRouters to generate the routes. * Similarly to an actual server adapter. * * Generate the serverless functions is just creating files, for that we use the `@palmares/std` package. * The adapter is a little bit different than the others. * * @param args The arguments to generate the serverless functions. */ async load(args) { const serverEntries = Object.entries(args.settings.servers); const [serverName, serverSettings] = serverEntries[serverEntries.length - 1]; const newServerInstance = new serverSettings.server(serverName, args.settings, args.settings.servers[serverName], args.domains); await newServerInstance.load(serverName, args.domains, serverSettings); await initializeRouters(args.domains, serverSettings, args.settings, newServerInstance, { serverless: { generate: true } }); await newServerInstance.load(serverName, args.domains, serverSettings); } /** * Handle the serverless functions. This is the function that will be called when the serverless functions are * executed. Your serverless function should call this function directly. * * @param settings The settings to load. * @param args The arguments to handle the serverless functions. * @param args.requestAndResponseData The request and response data to handle the serverless functions. * The generated data should be left as is. The adapter defines that. But if it expects an object, you can add * custom data to that object. You can use that on your routes. * @param args.domainRoutes The domain routes to handle. This will filter the domains to certain routes only. * some serverless functions handle doing the routing. * @param args.serverName The server name to handle the serverless functions, should be left untouched. * @param args.getRoute The function to get the route, should be left untouched. * @param args.route Like i said, some serverless functions handle the routing, this is the route to handle. * @param args.method Like i said, some serverless functions handle the routing, and also the method to handle. If * defined, should be left untouched. * @param args.adapter The adapter to handle the serverless functions, should be left untouched. * @param args.getMethod The function to get the method, should be left untouched. * * @returns Returns the response data from the serverless function */ static async handleServerless(settings, args) { const { domains, settings: formattedSettings } = await (0, import_core4.initializeDomains)(settings); const settingsServers = formattedSettings; const initializedAdapter = new args.adapter(args.serverName, settingsServers, settingsServers.servers[args.serverName], domains); const domainRoutes = Array.isArray(args.domainRoutes) && args.domainRoutes.length > 0 ? domains.filter((domain2) => args.domainRoutes.includes(domain2.name)) : domains; return await initializeRouters(domainRoutes, settingsServers.servers[args.serverName], settings, initializedAdapter, { serverless: { use: { getMethod: args.getMethod, getRoute: args.getRoute, requestAndResponseData: args.requestAndResponseData } } }); } }; // src/domain/index.ts var serverDomainModifier = (0, import_core5.domain)("@palmares/server", "", {}); var serverDomain = (0, import_core5.domain)("@palmares/server", "", { commands: { runserver: { description: "Start the server in development mode", keywordArgs: { port: { description: "The port to run the server on", type: "number", default: 4e3, hasFlag: true } }, positionalArgs: void 0, handler: /* @__PURE__ */ __name(() => { return httpAppServer; }, "handler") }, serverless: { description: "Generate the serverless configuration from the server", keywordArgs: void 0, positionalArgs: void 0, handler: /* @__PURE__ */ __name(async ({ domains, settings }) => { const serverlessInstance = new Serverless(); await serverlessInstance.load({ settings, domains }); }, "handler") } }, // eslint-disable-next-line ts/require-await load: /* @__PURE__ */ __name(async (_) => void 0, "load") }); // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { BaseRouter, FileLike, IncludesRouter, MethodsRouter, Middleware, Request, Response, ServerAdapter, ServerDomain, ServerRequestAdapter, ServerResponseAdapter, ServerRouterAdapter, Serverless, ServerlessAdapter, ServerlessRouterAdapter, formDataLikeFactory, middleware, nestedMiddleware, path, pathNested, requestMiddleware, serverAdapter, serverDomainModifier, serverRequestAdapter, serverResponseAdapter, serverRouterAdapter, serverlessAdapter, serverlessRouterAdapter, status });