diff --git a/.gitignore b/.gitignore index 0f5fc4dd5..988cc3f2a 100644 --- a/.gitignore +++ b/.gitignore @@ -199,3 +199,4 @@ fastagent.jsonl # JetBrains IDEs .idea/ +tests/e2e/smoke/base/weather_location.txt diff --git a/schema/mcp-agent.config.schema.json b/.vscode/fastagent.config.schema.json similarity index 85% rename from schema/mcp-agent.config.schema.json rename to .vscode/fastagent.config.schema.json index 6b87d0abc..6020d050d 100644 --- a/schema/mcp-agent.config.schema.json +++ b/.vscode/fastagent.config.schema.json @@ -96,6 +96,38 @@ "title": "GenericSettings", "type": "object" }, + "GoogleSettings": { + "additionalProperties": true, + "description": "Settings for using OpenAI models in the fast-agent application.", + "properties": { + "api_key": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Api Key" + }, + "base_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Base Url" + } + }, + "title": "GoogleSettings", + "type": "object" + }, "LoggerSettings": { "description": "Logger settings for the fast-agent application.", "properties": { @@ -365,16 +397,9 @@ "description": "The timeout in seconds for the session." }, "read_transport_sse_timeout_seconds": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], "default": 300, - "title": "Read Transport SSE Timeout Seconds", + "title": "Read Transport Sse Timeout Seconds", + "type": "integer", "description": "The timeout in seconds for the server connection." }, "url": { @@ -461,6 +486,19 @@ ], "default": null, "description": "Sampling settings for this Client/Server pair" + }, + "cwd": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Cwd", + "description": "Working directory for the executed server command." } }, "title": "MCPServerSettings", @@ -524,20 +562,11 @@ "title": "OpenAISettings", "type": "object" }, - "OpenTelemetrySettings": { - "description": "OTEL settings for the fast-agent application.", + "OpenRouterSettings": { + "additionalProperties": true, + "description": "Settings for using OpenRouter models via its OpenAI-compatible API.", "properties": { - "enabled": { - "default": true, - "title": "Enabled", - "type": "boolean" - }, - "service_name": { - "default": "fast-agent", - "title": "Service Name", - "type": "string" - }, - "service_instance_id": { + "api_key": { "anyOf": [ { "type": "string" @@ -547,9 +576,9 @@ } ], "default": null, - "title": "Service Instance Id" + "title": "Api Key" }, - "service_version": { + "base_url": { "anyOf": [ { "type": "string" @@ -559,19 +588,29 @@ } ], "default": null, - "title": "Service Version" + "title": "Base Url" + } + }, + "title": "OpenRouterSettings", + "type": "object" + }, + "OpenTelemetrySettings": { + "description": "OTEL settings for the fast-agent application.", + "properties": { + "enabled": { + "default": false, + "title": "Enabled", + "type": "boolean" + }, + "service_name": { + "default": "fast-agent", + "title": "Service Name", + "type": "string" }, "otlp_endpoint": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "default": null, + "default": "http://localhost:4318/v1/traces", "title": "Otlp Endpoint", + "type": "string", "description": "OTLP endpoint for OpenTelemetry tracing" }, "console_debug": { @@ -589,6 +628,38 @@ }, "title": "OpenTelemetrySettings", "type": "object" + }, + "TensorZeroSettings": { + "additionalProperties": true, + "description": "Settings for using TensorZero via its OpenAI-compatible API.", + "properties": { + "base_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Base Url" + }, + "api_key": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Api Key" + } + }, + "title": "TensorZeroSettings", + "type": "object" } }, "additionalProperties": true, @@ -609,10 +680,8 @@ "description": "MCP config, such as MCP servers" }, "execution_engine": { + "const": "asyncio", "default": "asyncio", - "enum": [ - "asyncio" - ], "title": "Execution Engine", "type": "string", "description": "Execution engine for the fast-agent application" @@ -651,11 +720,9 @@ } ], "default": { - "enabled": true, + "enabled": false, "service_name": "fast-agent", - "service_instance_id": null, - "service_version": null, - "otlp_endpoint": null, + "otlp_endpoint": "http://localhost:4318/v1/traces", "console_debug": false, "sample_rate": 1.0 }, @@ -685,6 +752,30 @@ "default": null, "description": "Settings for using DeepSeek models in the fast-agent application" }, + "google": { + "anyOf": [ + { + "$ref": "#/$defs/GoogleSettings" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Settings for using DeepSeek models in the fast-agent application" + }, + "openrouter": { + "anyOf": [ + { + "$ref": "#/$defs/OpenRouterSettings" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Settings for using OpenRouter models in the fast-agent application" + }, "generic": { "anyOf": [ { @@ -697,6 +788,18 @@ "default": null, "description": "Settings for using Generic models in the fast-agent application" }, + "tensorzero": { + "anyOf": [ + { + "$ref": "#/$defs/TensorZeroSettings" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Settings for using TensorZero inference gateway" + }, "logger": { "anyOf": [ { @@ -727,4 +830,4 @@ "title": "MCP Agent Configuration Schema", "type": "object", "$schema": "http://json-schema.org/draft-07/schema#" -} +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index d8ac240e0..46b1feba8 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -7,11 +7,9 @@ "editor.rulers": [] }, "yaml.schemas": { - "https://raw.githubusercontent.com/lastmile-ai/mcp-agent/main/schema/mcp-agent.config.schema.json": [ - "mcp-agent.config.yaml", - "mcp_agent.config.yaml", - "mcp-agent.secrets.yaml", - "mcp_agent.secrets.yaml" + "./.vscode/fastagent.config.schema.json": [ + "fastagent.config.yaml", + "fastagent.secrets.yaml" ] }, "editor.fontFamily": "BlexMono Nerd Font", diff --git a/pyproject.toml b/pyproject.toml index c00a9e9c5..01a8907e4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "fast-agent-mcp" -version = "0.2.21" +version = "0.2.22" description = "Define, Prompt and Test MCP enabled Agents and Workflows" readme = "README.md" license = { file = "LICENSE" } @@ -16,7 +16,7 @@ classifiers = [ requires-python = ">=3.10" dependencies = [ "fastapi>=0.115.6", - "mcp~=1.7.0", + "mcp>=1.8.0", "opentelemetry-distro>=0.50b0", "opentelemetry-exporter-otlp-proto-http>=1.29.0", "pydantic-settings>=2.7.0", diff --git a/scripts/gen_schema.py b/scripts/gen_schema.py index 8d32f4f85..4904c8438 100644 --- a/scripts/gen_schema.py +++ b/scripts/gen_schema.py @@ -163,7 +163,9 @@ def load_settings_class( return namespace["Settings"], model_info -def apply_descriptions_to_schema(schema: Dict[str, Any], model_info: Dict[str, Dict[str, str]]) -> None: +def apply_descriptions_to_schema( + schema: Dict[str, Any], model_info: Dict[str, Dict[str, str]] +) -> None: """Recursively apply descriptions to schema and all its nested models.""" if not isinstance(schema, dict): return @@ -199,7 +201,7 @@ def generate( help="Path to the config.py file", ), output: Path = typer.Option( - Path("schema/mcp-agent.config.schema.json"), + Path(".vscode/fastagent.config.schema.json"), "--output", "-o", help="Output path for the schema file", diff --git a/src/mcp_agent/llm/providers/augmented_llm_openai.py b/src/mcp_agent/llm/providers/augmented_llm_openai.py index 0f7acbc8b..906502a20 100644 --- a/src/mcp_agent/llm/providers/augmented_llm_openai.py +++ b/src/mcp_agent/llm/providers/augmented_llm_openai.py @@ -144,7 +144,7 @@ async def _openai_completion( function={ "name": tool.name, "description": tool.description if tool.description else "", - "parameters": tool.inputSchema, + "parameters": adjust_schema(tool.inputSchema), }, ) for tool in response.tools @@ -351,3 +351,12 @@ def _prepare_api_request( base_args, request_params, self.OPENAI_EXCLUDE_FIELDS.union(self.BASE_EXCLUDE_FIELDS) ) return arguments + + +def adjust_schema(inputSchema: Dict) -> Dict: + if "proprties" in inputSchema: + return inputSchema + + result = inputSchema.copy() + result["properties"] = {} + return result diff --git a/tests/e2e/smoke/base/fastagent.config.yaml b/tests/e2e/smoke/base/fastagent.config.yaml index 7652a1cbc..eab7dbc92 100644 --- a/tests/e2e/smoke/base/fastagent.config.yaml +++ b/tests/e2e/smoke/base/fastagent.config.yaml @@ -35,3 +35,6 @@ mcp: hyphen-name: command: "uv" args: ["run", "test_server.py"] + temp_issue_ts: + transport: "sse" + url: "http://localhost:8080/sse" diff --git a/tests/e2e/smoke/base/index.js b/tests/e2e/smoke/base/index.js new file mode 100755 index 000000000..126228bd1 --- /dev/null +++ b/tests/e2e/smoke/base/index.js @@ -0,0 +1,35431 @@ +import { createRequire as __WEBPACK_EXTERNAL_createRequire } from "module"; +/******/ var __webpack_modules__ = { + /***/ 8591: /***/ (module, __unused_webpack_exports, __nccwpck_require__) => { + /*! + * accepts + * Copyright(c) 2014 Jonathan Ong + * Copyright(c) 2015 Douglas Christopher Wilson + * MIT Licensed + */ + + /** + * Module dependencies. + * @private + */ + + var Negotiator = __nccwpck_require__(6143); + var mime = __nccwpck_require__(5143); + + /** + * Module exports. + * @public + */ + + module.exports = Accepts; + + /** + * Create a new Accepts object for the given req. + * + * @param {object} req + * @public + */ + + function Accepts(req) { + if (!(this instanceof Accepts)) { + return new Accepts(req); + } + + this.headers = req.headers; + this.negotiator = new Negotiator(req); + } + + /** + * Check if the given `type(s)` is acceptable, returning + * the best match when true, otherwise `undefined`, in which + * case you should respond with 406 "Not Acceptable". + * + * The `type` value may be a single mime type string + * such as "application/json", the extension name + * such as "json" or an array `["json", "html", "text/plain"]`. When a list + * or array is given the _best_ match, if any is returned. + * + * Examples: + * + * // Accept: text/html + * this.types('html'); + * // => "html" + * + * // Accept: text/*, application/json + * this.types('html'); + * // => "html" + * this.types('text/html'); + * // => "text/html" + * this.types('json', 'text'); + * // => "json" + * this.types('application/json'); + * // => "application/json" + * + * // Accept: text/*, application/json + * this.types('image/png'); + * this.types('png'); + * // => undefined + * + * // Accept: text/*;q=.5, application/json + * this.types(['html', 'json']); + * this.types('html', 'json'); + * // => "json" + * + * @param {String|Array} types... + * @return {String|Array|Boolean} + * @public + */ + + Accepts.prototype.type = Accepts.prototype.types = function (types_) { + var types = types_; + + // support flattened arguments + if (types && !Array.isArray(types)) { + types = new Array(arguments.length); + for (var i = 0; i < types.length; i++) { + types[i] = arguments[i]; + } + } + + // no types, return all requested types + if (!types || types.length === 0) { + return this.negotiator.mediaTypes(); + } + + // no accept header, return first given type + if (!this.headers.accept) { + return types[0]; + } + + var mimes = types.map(extToMime); + var accepts = this.negotiator.mediaTypes(mimes.filter(validMime)); + var first = accepts[0]; + + return first ? types[mimes.indexOf(first)] : false; + }; + + /** + * Return accepted encodings or best fit based on `encodings`. + * + * Given `Accept-Encoding: gzip, deflate` + * an array sorted by quality is returned: + * + * ['gzip', 'deflate'] + * + * @param {String|Array} encodings... + * @return {String|Array} + * @public + */ + + Accepts.prototype.encoding = Accepts.prototype.encodings = function ( + encodings_ + ) { + var encodings = encodings_; + + // support flattened arguments + if (encodings && !Array.isArray(encodings)) { + encodings = new Array(arguments.length); + for (var i = 0; i < encodings.length; i++) { + encodings[i] = arguments[i]; + } + } + + // no encodings, return all requested encodings + if (!encodings || encodings.length === 0) { + return this.negotiator.encodings(); + } + + return this.negotiator.encodings(encodings)[0] || false; + }; + + /** + * Return accepted charsets or best fit based on `charsets`. + * + * Given `Accept-Charset: utf-8, iso-8859-1;q=0.2, utf-7;q=0.5` + * an array sorted by quality is returned: + * + * ['utf-8', 'utf-7', 'iso-8859-1'] + * + * @param {String|Array} charsets... + * @return {String|Array} + * @public + */ + + Accepts.prototype.charset = Accepts.prototype.charsets = function ( + charsets_ + ) { + var charsets = charsets_; + + // support flattened arguments + if (charsets && !Array.isArray(charsets)) { + charsets = new Array(arguments.length); + for (var i = 0; i < charsets.length; i++) { + charsets[i] = arguments[i]; + } + } + + // no charsets, return all requested charsets + if (!charsets || charsets.length === 0) { + return this.negotiator.charsets(); + } + + return this.negotiator.charsets(charsets)[0] || false; + }; + + /** + * Return accepted languages or best fit based on `langs`. + * + * Given `Accept-Language: en;q=0.8, es, pt` + * an array sorted by quality is returned: + * + * ['es', 'pt', 'en'] + * + * @param {String|Array} langs... + * @return {Array|String} + * @public + */ + + Accepts.prototype.lang = + Accepts.prototype.langs = + Accepts.prototype.language = + Accepts.prototype.languages = + function (languages_) { + var languages = languages_; + + // support flattened arguments + if (languages && !Array.isArray(languages)) { + languages = new Array(arguments.length); + for (var i = 0; i < languages.length; i++) { + languages[i] = arguments[i]; + } + } + + // no languages, return all requested languages + if (!languages || languages.length === 0) { + return this.negotiator.languages(); + } + + return this.negotiator.languages(languages)[0] || false; + }; + + /** + * Convert extnames to mime. + * + * @param {String} type + * @return {String} + * @private + */ + + function extToMime(type) { + return type.indexOf("/") === -1 ? mime.lookup(type) : type; + } + + /** + * Check if mime is valid. + * + * @param {String} type + * @return {String} + * @private + */ + + function validMime(type) { + return typeof type === "string"; + } + + /***/ + }, + + /***/ 609: /***/ (module) => { + /** + * Expose `arrayFlatten`. + */ + module.exports = arrayFlatten; + + /** + * Recursive flatten function with depth. + * + * @param {Array} array + * @param {Array} result + * @param {Number} depth + * @return {Array} + */ + function flattenWithDepth(array, result, depth) { + for (var i = 0; i < array.length; i++) { + var value = array[i]; + + if (depth > 0 && Array.isArray(value)) { + flattenWithDepth(value, result, depth - 1); + } else { + result.push(value); + } + } + + return result; + } + + /** + * Recursive flatten function. Omitting depth is slightly faster. + * + * @param {Array} array + * @param {Array} result + * @return {Array} + */ + function flattenForever(array, result) { + for (var i = 0; i < array.length; i++) { + var value = array[i]; + + if (Array.isArray(value)) { + flattenForever(value, result); + } else { + result.push(value); + } + } + + return result; + } + + /** + * Flatten an array, with the ability to define a depth. + * + * @param {Array} array + * @param {Number} depth + * @return {Array} + */ + function arrayFlatten(array, depth) { + if (depth == null) { + return flattenForever(array, []); + } + + return flattenWithDepth(array, [], depth); + } + + /***/ + }, + + /***/ 1301: /***/ (module, exports, __nccwpck_require__) => { + /*! + * body-parser + * Copyright(c) 2014-2015 Douglas Christopher Wilson + * MIT Licensed + */ + + /** + * Module dependencies. + * @private + */ + + var deprecate = __nccwpck_require__(972)("body-parser"); + + /** + * Cache of loaded parsers. + * @private + */ + + var parsers = Object.create(null); + + /** + * @typedef Parsers + * @type {function} + * @property {function} json + * @property {function} raw + * @property {function} text + * @property {function} urlencoded + */ + + /** + * Module exports. + * @type {Parsers} + */ + + exports = module.exports = deprecate.function( + bodyParser, + "bodyParser: use individual json/urlencoded middlewares" + ); + + /** + * JSON parser. + * @public + */ + + Object.defineProperty(exports, "json", { + configurable: true, + enumerable: true, + get: createParserGetter("json"), + }); + + /** + * Raw parser. + * @public + */ + + Object.defineProperty(exports, "raw", { + configurable: true, + enumerable: true, + get: createParserGetter("raw"), + }); + + /** + * Text parser. + * @public + */ + + Object.defineProperty(exports, "text", { + configurable: true, + enumerable: true, + get: createParserGetter("text"), + }); + + /** + * URL-encoded parser. + * @public + */ + + Object.defineProperty(exports, "urlencoded", { + configurable: true, + enumerable: true, + get: createParserGetter("urlencoded"), + }); + + /** + * Create a middleware to parse json and urlencoded bodies. + * + * @param {object} [options] + * @return {function} + * @deprecated + * @public + */ + + function bodyParser(options) { + // use default type for parsers + var opts = Object.create(options || null, { + type: { + configurable: true, + enumerable: true, + value: undefined, + writable: true, + }, + }); + + var _urlencoded = exports.urlencoded(opts); + var _json = exports.json(opts); + + return function bodyParser(req, res, next) { + _json(req, res, function (err) { + if (err) return next(err); + _urlencoded(req, res, next); + }); + }; + } + + /** + * Create a getter for loading a parser. + * @private + */ + + function createParserGetter(name) { + return function get() { + return loadParser(name); + }; + } + + /** + * Load a parser module. + * @private + */ + + function loadParser(parserName) { + var parser = parsers[parserName]; + + if (parser !== undefined) { + return parser; + } + + // this uses a switch for static require analysis + switch (parserName) { + case "json": + parser = __nccwpck_require__(2909); + break; + case "raw": + parser = __nccwpck_require__(6345); + break; + case "text": + parser = __nccwpck_require__(9540); + break; + case "urlencoded": + parser = __nccwpck_require__(4070); + break; + } + + // store to prevent invoking require() + return (parsers[parserName] = parser); + } + + /***/ + }, + + /***/ 4409: /***/ (module, __unused_webpack_exports, __nccwpck_require__) => { + /*! + * body-parser + * Copyright(c) 2014-2015 Douglas Christopher Wilson + * MIT Licensed + */ + + /** + * Module dependencies. + * @private + */ + + var createError = __nccwpck_require__(5173); + var destroy = __nccwpck_require__(2791); + var getBody = __nccwpck_require__(9712); + var iconv = __nccwpck_require__(1803); + var onFinished = __nccwpck_require__(7939); + var unpipe = __nccwpck_require__(1520); + var zlib = __nccwpck_require__(3106); + + /** + * Module exports. + */ + + module.exports = read; + + /** + * Read a request into a buffer and parse. + * + * @param {object} req + * @param {object} res + * @param {function} next + * @param {function} parse + * @param {function} debug + * @param {object} options + * @private + */ + + function read(req, res, next, parse, debug, options) { + var length; + var opts = options; + var stream; + + // flag as parsed + req._body = true; + + // read options + var encoding = opts.encoding !== null ? opts.encoding : null; + var verify = opts.verify; + + try { + // get the content stream + stream = contentstream(req, debug, opts.inflate); + length = stream.length; + stream.length = undefined; + } catch (err) { + return next(err); + } + + // set raw-body options + opts.length = length; + opts.encoding = verify ? null : encoding; + + // assert charset is supported + if ( + opts.encoding === null && + encoding !== null && + !iconv.encodingExists(encoding) + ) { + return next( + createError( + 415, + 'unsupported charset "' + encoding.toUpperCase() + '"', + { + charset: encoding.toLowerCase(), + type: "charset.unsupported", + } + ) + ); + } + + // read body + debug("read body"); + getBody(stream, opts, function (error, body) { + if (error) { + var _error; + + if (error.type === "encoding.unsupported") { + // echo back charset + _error = createError( + 415, + 'unsupported charset "' + encoding.toUpperCase() + '"', + { + charset: encoding.toLowerCase(), + type: "charset.unsupported", + } + ); + } else { + // set status code on error + _error = createError(400, error); + } + + // unpipe from stream and destroy + if (stream !== req) { + unpipe(req); + destroy(stream, true); + } + + // read off entire request + dump(req, function onfinished() { + next(createError(400, _error)); + }); + return; + } + + // verify + if (verify) { + try { + debug("verify body"); + verify(req, res, body, encoding); + } catch (err) { + next( + createError(403, err, { + body: body, + type: err.type || "entity.verify.failed", + }) + ); + return; + } + } + + // parse + var str = body; + try { + debug("parse body"); + str = + typeof body !== "string" && encoding !== null + ? iconv.decode(body, encoding) + : body; + req.body = parse(str); + } catch (err) { + next( + createError(400, err, { + body: str, + type: err.type || "entity.parse.failed", + }) + ); + return; + } + + next(); + }); + } + + /** + * Get the content stream of the request. + * + * @param {object} req + * @param {function} debug + * @param {boolean} [inflate=true] + * @return {object} + * @api private + */ + + function contentstream(req, debug, inflate) { + var encoding = ( + req.headers["content-encoding"] || "identity" + ).toLowerCase(); + var length = req.headers["content-length"]; + var stream; + + debug('content-encoding "%s"', encoding); + + if (inflate === false && encoding !== "identity") { + throw createError(415, "content encoding unsupported", { + encoding: encoding, + type: "encoding.unsupported", + }); + } + + switch (encoding) { + case "deflate": + stream = zlib.createInflate(); + debug("inflate body"); + req.pipe(stream); + break; + case "gzip": + stream = zlib.createGunzip(); + debug("gunzip body"); + req.pipe(stream); + break; + case "identity": + stream = req; + stream.length = length; + break; + default: + throw createError( + 415, + 'unsupported content encoding "' + encoding + '"', + { + encoding: encoding, + type: "encoding.unsupported", + } + ); + } + + return stream; + } + + /** + * Dump the contents of a request. + * + * @param {object} req + * @param {function} callback + * @api private + */ + + function dump(req, callback) { + if (onFinished.isFinished(req)) { + callback(null); + } else { + onFinished(req, callback); + req.resume(); + } + } + + /***/ + }, + + /***/ 2909: /***/ (module, __unused_webpack_exports, __nccwpck_require__) => { + /*! + * body-parser + * Copyright(c) 2014 Jonathan Ong + * Copyright(c) 2014-2015 Douglas Christopher Wilson + * MIT Licensed + */ + + /** + * Module dependencies. + * @private + */ + + var bytes = __nccwpck_require__(6074); + var contentType = __nccwpck_require__(607); + var createError = __nccwpck_require__(5173); + var debug = __nccwpck_require__(4503)("body-parser:json"); + var read = __nccwpck_require__(4409); + var typeis = __nccwpck_require__(2722); + + /** + * Module exports. + */ + + module.exports = json; + + /** + * RegExp to match the first non-space in a string. + * + * Allowed whitespace is defined in RFC 7159: + * + * ws = *( + * %x20 / ; Space + * %x09 / ; Horizontal tab + * %x0A / ; Line feed or New line + * %x0D ) ; Carriage return + */ + + var FIRST_CHAR_REGEXP = /^[\x20\x09\x0a\x0d]*([^\x20\x09\x0a\x0d])/; // eslint-disable-line no-control-regex + + var JSON_SYNTAX_CHAR = "#"; + var JSON_SYNTAX_REGEXP = /#+/g; + + /** + * Create a middleware to parse JSON bodies. + * + * @param {object} [options] + * @return {function} + * @public + */ + + function json(options) { + var opts = options || {}; + + var limit = + typeof opts.limit !== "number" + ? bytes.parse(opts.limit || "100kb") + : opts.limit; + var inflate = opts.inflate !== false; + var reviver = opts.reviver; + var strict = opts.strict !== false; + var type = opts.type || "application/json"; + var verify = opts.verify || false; + + if (verify !== false && typeof verify !== "function") { + throw new TypeError("option verify must be function"); + } + + // create the appropriate type checking function + var shouldParse = typeof type !== "function" ? typeChecker(type) : type; + + function parse(body) { + if (body.length === 0) { + // special-case empty json body, as it's a common client-side mistake + // TODO: maybe make this configurable or part of "strict" option + return {}; + } + + if (strict) { + var first = firstchar(body); + + if (first !== "{" && first !== "[") { + debug("strict violation"); + throw createStrictSyntaxError(body, first); + } + } + + try { + debug("parse json"); + return JSON.parse(body, reviver); + } catch (e) { + throw normalizeJsonSyntaxError(e, { + message: e.message, + stack: e.stack, + }); + } + } + + return function jsonParser(req, res, next) { + if (req._body) { + debug("body already parsed"); + next(); + return; + } + + req.body = req.body || {}; + + // skip requests without bodies + if (!typeis.hasBody(req)) { + debug("skip empty body"); + next(); + return; + } + + debug("content-type %j", req.headers["content-type"]); + + // determine if request should be parsed + if (!shouldParse(req)) { + debug("skip parsing"); + next(); + return; + } + + // assert charset per RFC 7159 sec 8.1 + var charset = getCharset(req) || "utf-8"; + if (charset.slice(0, 4) !== "utf-") { + debug("invalid charset"); + next( + createError( + 415, + 'unsupported charset "' + charset.toUpperCase() + '"', + { + charset: charset, + type: "charset.unsupported", + } + ) + ); + return; + } + + // read + read(req, res, next, parse, debug, { + encoding: charset, + inflate: inflate, + limit: limit, + verify: verify, + }); + }; + } + + /** + * Create strict violation syntax error matching native error. + * + * @param {string} str + * @param {string} char + * @return {Error} + * @private + */ + + function createStrictSyntaxError(str, char) { + var index = str.indexOf(char); + var partial = ""; + + if (index !== -1) { + partial = str.substring(0, index) + JSON_SYNTAX_CHAR; + + for (var i = index + 1; i < str.length; i++) { + partial += JSON_SYNTAX_CHAR; + } + } + + try { + JSON.parse(partial); + /* istanbul ignore next */ throw new SyntaxError("strict violation"); + } catch (e) { + return normalizeJsonSyntaxError(e, { + message: e.message.replace( + JSON_SYNTAX_REGEXP, + function (placeholder) { + return str.substring(index, index + placeholder.length); + } + ), + stack: e.stack, + }); + } + } + + /** + * Get the first non-whitespace character in a string. + * + * @param {string} str + * @return {function} + * @private + */ + + function firstchar(str) { + var match = FIRST_CHAR_REGEXP.exec(str); + + return match ? match[1] : undefined; + } + + /** + * Get the charset of a request. + * + * @param {object} req + * @api private + */ + + function getCharset(req) { + try { + return (contentType.parse(req).parameters.charset || "").toLowerCase(); + } catch (e) { + return undefined; + } + } + + /** + * Normalize a SyntaxError for JSON.parse. + * + * @param {SyntaxError} error + * @param {object} obj + * @return {SyntaxError} + */ + + function normalizeJsonSyntaxError(error, obj) { + var keys = Object.getOwnPropertyNames(error); + + for (var i = 0; i < keys.length; i++) { + var key = keys[i]; + if (key !== "stack" && key !== "message") { + delete error[key]; + } + } + + // replace stack before message for Node.js 0.10 and below + error.stack = obj.stack.replace(error.message, obj.message); + error.message = obj.message; + + return error; + } + + /** + * Get the simple type checker. + * + * @param {string} type + * @return {function} + */ + + function typeChecker(type) { + return function checkType(req) { + return Boolean(typeis(req, type)); + }; + } + + /***/ + }, + + /***/ 6345: /***/ (module, __unused_webpack_exports, __nccwpck_require__) => { + /*! + * body-parser + * Copyright(c) 2014-2015 Douglas Christopher Wilson + * MIT Licensed + */ + + /** + * Module dependencies. + */ + + var bytes = __nccwpck_require__(6074); + var debug = __nccwpck_require__(4503)("body-parser:raw"); + var read = __nccwpck_require__(4409); + var typeis = __nccwpck_require__(2722); + + /** + * Module exports. + */ + + module.exports = raw; + + /** + * Create a middleware to parse raw bodies. + * + * @param {object} [options] + * @return {function} + * @api public + */ + + function raw(options) { + var opts = options || {}; + + var inflate = opts.inflate !== false; + var limit = + typeof opts.limit !== "number" + ? bytes.parse(opts.limit || "100kb") + : opts.limit; + var type = opts.type || "application/octet-stream"; + var verify = opts.verify || false; + + if (verify !== false && typeof verify !== "function") { + throw new TypeError("option verify must be function"); + } + + // create the appropriate type checking function + var shouldParse = typeof type !== "function" ? typeChecker(type) : type; + + function parse(buf) { + return buf; + } + + return function rawParser(req, res, next) { + if (req._body) { + debug("body already parsed"); + next(); + return; + } + + req.body = req.body || {}; + + // skip requests without bodies + if (!typeis.hasBody(req)) { + debug("skip empty body"); + next(); + return; + } + + debug("content-type %j", req.headers["content-type"]); + + // determine if request should be parsed + if (!shouldParse(req)) { + debug("skip parsing"); + next(); + return; + } + + // read + read(req, res, next, parse, debug, { + encoding: null, + inflate: inflate, + limit: limit, + verify: verify, + }); + }; + } + + /** + * Get the simple type checker. + * + * @param {string} type + * @return {function} + */ + + function typeChecker(type) { + return function checkType(req) { + return Boolean(typeis(req, type)); + }; + } + + /***/ + }, + + /***/ 9540: /***/ (module, __unused_webpack_exports, __nccwpck_require__) => { + /*! + * body-parser + * Copyright(c) 2014-2015 Douglas Christopher Wilson + * MIT Licensed + */ + + /** + * Module dependencies. + */ + + var bytes = __nccwpck_require__(6074); + var contentType = __nccwpck_require__(607); + var debug = __nccwpck_require__(4503)("body-parser:text"); + var read = __nccwpck_require__(4409); + var typeis = __nccwpck_require__(2722); + + /** + * Module exports. + */ + + module.exports = text; + + /** + * Create a middleware to parse text bodies. + * + * @param {object} [options] + * @return {function} + * @api public + */ + + function text(options) { + var opts = options || {}; + + var defaultCharset = opts.defaultCharset || "utf-8"; + var inflate = opts.inflate !== false; + var limit = + typeof opts.limit !== "number" + ? bytes.parse(opts.limit || "100kb") + : opts.limit; + var type = opts.type || "text/plain"; + var verify = opts.verify || false; + + if (verify !== false && typeof verify !== "function") { + throw new TypeError("option verify must be function"); + } + + // create the appropriate type checking function + var shouldParse = typeof type !== "function" ? typeChecker(type) : type; + + function parse(buf) { + return buf; + } + + return function textParser(req, res, next) { + if (req._body) { + debug("body already parsed"); + next(); + return; + } + + req.body = req.body || {}; + + // skip requests without bodies + if (!typeis.hasBody(req)) { + debug("skip empty body"); + next(); + return; + } + + debug("content-type %j", req.headers["content-type"]); + + // determine if request should be parsed + if (!shouldParse(req)) { + debug("skip parsing"); + next(); + return; + } + + // get charset + var charset = getCharset(req) || defaultCharset; + + // read + read(req, res, next, parse, debug, { + encoding: charset, + inflate: inflate, + limit: limit, + verify: verify, + }); + }; + } + + /** + * Get the charset of a request. + * + * @param {object} req + * @api private + */ + + function getCharset(req) { + try { + return (contentType.parse(req).parameters.charset || "").toLowerCase(); + } catch (e) { + return undefined; + } + } + + /** + * Get the simple type checker. + * + * @param {string} type + * @return {function} + */ + + function typeChecker(type) { + return function checkType(req) { + return Boolean(typeis(req, type)); + }; + } + + /***/ + }, + + /***/ 4070: /***/ (module, __unused_webpack_exports, __nccwpck_require__) => { + /*! + * body-parser + * Copyright(c) 2014 Jonathan Ong + * Copyright(c) 2014-2015 Douglas Christopher Wilson + * MIT Licensed + */ + + /** + * Module dependencies. + * @private + */ + + var bytes = __nccwpck_require__(6074); + var contentType = __nccwpck_require__(607); + var createError = __nccwpck_require__(5173); + var debug = __nccwpck_require__(4503)("body-parser:urlencoded"); + var deprecate = __nccwpck_require__(972)("body-parser"); + var read = __nccwpck_require__(4409); + var typeis = __nccwpck_require__(2722); + + /** + * Module exports. + */ + + module.exports = urlencoded; + + /** + * Cache of parser modules. + */ + + var parsers = Object.create(null); + + /** + * Create a middleware to parse urlencoded bodies. + * + * @param {object} [options] + * @return {function} + * @public + */ + + function urlencoded(options) { + var opts = options || {}; + + // notice because option default will flip in next major + if (opts.extended === undefined) { + deprecate("undefined extended: provide extended option"); + } + + var extended = opts.extended !== false; + var inflate = opts.inflate !== false; + var limit = + typeof opts.limit !== "number" + ? bytes.parse(opts.limit || "100kb") + : opts.limit; + var type = opts.type || "application/x-www-form-urlencoded"; + var verify = opts.verify || false; + var depth = + typeof opts.depth !== "number" ? Number(opts.depth || 32) : opts.depth; + + if (verify !== false && typeof verify !== "function") { + throw new TypeError("option verify must be function"); + } + + // create the appropriate query parser + var queryparse = extended ? extendedparser(opts) : simpleparser(opts); + + // create the appropriate type checking function + var shouldParse = typeof type !== "function" ? typeChecker(type) : type; + + function parse(body) { + return body.length ? queryparse(body) : {}; + } + + return function urlencodedParser(req, res, next) { + if (req._body) { + debug("body already parsed"); + next(); + return; + } + + req.body = req.body || {}; + + // skip requests without bodies + if (!typeis.hasBody(req)) { + debug("skip empty body"); + next(); + return; + } + + debug("content-type %j", req.headers["content-type"]); + + // determine if request should be parsed + if (!shouldParse(req)) { + debug("skip parsing"); + next(); + return; + } + + // assert charset + var charset = getCharset(req) || "utf-8"; + if (charset !== "utf-8") { + debug("invalid charset"); + next( + createError( + 415, + 'unsupported charset "' + charset.toUpperCase() + '"', + { + charset: charset, + type: "charset.unsupported", + } + ) + ); + return; + } + + // read + read(req, res, next, parse, debug, { + debug: debug, + encoding: charset, + inflate: inflate, + limit: limit, + verify: verify, + depth: depth, + }); + }; + } + + /** + * Get the extended query parser. + * + * @param {object} options + */ + + function extendedparser(options) { + var parameterLimit = + options.parameterLimit !== undefined ? options.parameterLimit : 1000; + + var depth = + typeof options.depth !== "number" + ? Number(options.depth || 32) + : options.depth; + var parse = parser("qs"); + + if (isNaN(parameterLimit) || parameterLimit < 1) { + throw new TypeError("option parameterLimit must be a positive number"); + } + + if (isNaN(depth) || depth < 0) { + throw new TypeError("option depth must be a zero or a positive number"); + } + + if (isFinite(parameterLimit)) { + parameterLimit = parameterLimit | 0; + } + + return function queryparse(body) { + var paramCount = parameterCount(body, parameterLimit); + + if (paramCount === undefined) { + debug("too many parameters"); + throw createError(413, "too many parameters", { + type: "parameters.too.many", + }); + } + + var arrayLimit = Math.max(100, paramCount); + + debug("parse extended urlencoding"); + try { + return parse(body, { + allowPrototypes: true, + arrayLimit: arrayLimit, + depth: depth, + strictDepth: true, + parameterLimit: parameterLimit, + }); + } catch (err) { + if (err instanceof RangeError) { + throw createError(400, "The input exceeded the depth", { + type: "querystring.parse.rangeError", + }); + } else { + throw err; + } + } + }; + } + + /** + * Get the charset of a request. + * + * @param {object} req + * @api private + */ + + function getCharset(req) { + try { + return (contentType.parse(req).parameters.charset || "").toLowerCase(); + } catch (e) { + return undefined; + } + } + + /** + * Count the number of parameters, stopping once limit reached + * + * @param {string} body + * @param {number} limit + * @api private + */ + + function parameterCount(body, limit) { + var count = 0; + var index = 0; + + while ((index = body.indexOf("&", index)) !== -1) { + count++; + index++; + + if (count === limit) { + return undefined; + } + } + + return count; + } + + /** + * Get parser for module name dynamically. + * + * @param {string} name + * @return {function} + * @api private + */ + + function parser(name) { + var mod = parsers[name]; + + if (mod !== undefined) { + return mod.parse; + } + + // this uses a switch for static require analysis + switch (name) { + case "qs": + mod = __nccwpck_require__(8203); + break; + case "querystring": + mod = __nccwpck_require__(3480); + break; + } + + // store to prevent invoking require() + parsers[name] = mod; + + return mod.parse; + } + + /** + * Get the simple query parser. + * + * @param {object} options + */ + + function simpleparser(options) { + var parameterLimit = + options.parameterLimit !== undefined ? options.parameterLimit : 1000; + var parse = parser("querystring"); + + if (isNaN(parameterLimit) || parameterLimit < 1) { + throw new TypeError("option parameterLimit must be a positive number"); + } + + if (isFinite(parameterLimit)) { + parameterLimit = parameterLimit | 0; + } + + return function queryparse(body) { + var paramCount = parameterCount(body, parameterLimit); + + if (paramCount === undefined) { + debug("too many parameters"); + throw createError(413, "too many parameters", { + type: "parameters.too.many", + }); + } + + debug("parse urlencoding"); + return parse(body, undefined, undefined, { maxKeys: parameterLimit }); + }; + } + + /** + * Get the simple type checker. + * + * @param {string} type + * @return {function} + */ + + function typeChecker(type) { + return function checkType(req) { + return Boolean(typeis(req, type)); + }; + } + + /***/ + }, + + /***/ 9712: /***/ (module, __unused_webpack_exports, __nccwpck_require__) => { + /*! + * raw-body + * Copyright(c) 2013-2014 Jonathan Ong + * Copyright(c) 2014-2022 Douglas Christopher Wilson + * MIT Licensed + */ + + /** + * Module dependencies. + * @private + */ + + var asyncHooks = tryRequireAsyncHooks(); + var bytes = __nccwpck_require__(6074); + var createError = __nccwpck_require__(5173); + var iconv = __nccwpck_require__(1803); + var unpipe = __nccwpck_require__(1520); + + /** + * Module exports. + * @public + */ + + module.exports = getRawBody; + + /** + * Module variables. + * @private + */ + + var ICONV_ENCODING_MESSAGE_REGEXP = /^Encoding not recognized: /; + + /** + * Get the decoder for a given encoding. + * + * @param {string} encoding + * @private + */ + + function getDecoder(encoding) { + if (!encoding) return null; + + try { + return iconv.getDecoder(encoding); + } catch (e) { + // error getting decoder + if (!ICONV_ENCODING_MESSAGE_REGEXP.test(e.message)) throw e; + + // the encoding was not found + throw createError(415, "specified encoding unsupported", { + encoding: encoding, + type: "encoding.unsupported", + }); + } + } + + /** + * Get the raw body of a stream (typically HTTP). + * + * @param {object} stream + * @param {object|string|function} [options] + * @param {function} [callback] + * @public + */ + + function getRawBody(stream, options, callback) { + var done = callback; + var opts = options || {}; + + // light validation + if (stream === undefined) { + throw new TypeError("argument stream is required"); + } else if ( + typeof stream !== "object" || + stream === null || + typeof stream.on !== "function" + ) { + throw new TypeError("argument stream must be a stream"); + } + + if (options === true || typeof options === "string") { + // short cut for encoding + opts = { + encoding: options, + }; + } + + if (typeof options === "function") { + done = options; + opts = {}; + } + + // validate callback is a function, if provided + if (done !== undefined && typeof done !== "function") { + throw new TypeError("argument callback must be a function"); + } + + // require the callback without promises + if (!done && !global.Promise) { + throw new TypeError("argument callback is required"); + } + + // get encoding + var encoding = opts.encoding !== true ? opts.encoding : "utf-8"; + + // convert the limit to an integer + var limit = bytes.parse(opts.limit); + + // convert the expected length to an integer + var length = + opts.length != null && !isNaN(opts.length) + ? parseInt(opts.length, 10) + : null; + + if (done) { + // classic callback style + return readStream(stream, encoding, length, limit, wrap(done)); + } + + return new Promise(function executor(resolve, reject) { + readStream(stream, encoding, length, limit, function onRead(err, buf) { + if (err) return reject(err); + resolve(buf); + }); + }); + } + + /** + * Halt a stream. + * + * @param {Object} stream + * @private + */ + + function halt(stream) { + // unpipe everything from the stream + unpipe(stream); + + // pause stream + if (typeof stream.pause === "function") { + stream.pause(); + } + } + + /** + * Read the data from the stream. + * + * @param {object} stream + * @param {string} encoding + * @param {number} length + * @param {number} limit + * @param {function} callback + * @public + */ + + function readStream(stream, encoding, length, limit, callback) { + var complete = false; + var sync = true; + + // check the length and limit options. + // note: we intentionally leave the stream paused, + // so users should handle the stream themselves. + if (limit !== null && length !== null && length > limit) { + return done( + createError(413, "request entity too large", { + expected: length, + length: length, + limit: limit, + type: "entity.too.large", + }) + ); + } + + // streams1: assert request encoding is buffer. + // streams2+: assert the stream encoding is buffer. + // stream._decoder: streams1 + // state.encoding: streams2 + // state.decoder: streams2, specifically < 0.10.6 + var state = stream._readableState; + if (stream._decoder || (state && (state.encoding || state.decoder))) { + // developer error + return done( + createError(500, "stream encoding should not be set", { + type: "stream.encoding.set", + }) + ); + } + + if (typeof stream.readable !== "undefined" && !stream.readable) { + return done( + createError(500, "stream is not readable", { + type: "stream.not.readable", + }) + ); + } + + var received = 0; + var decoder; + + try { + decoder = getDecoder(encoding); + } catch (err) { + return done(err); + } + + var buffer = decoder ? "" : []; + + // attach listeners + stream.on("aborted", onAborted); + stream.on("close", cleanup); + stream.on("data", onData); + stream.on("end", onEnd); + stream.on("error", onEnd); + + // mark sync section complete + sync = false; + + function done() { + var args = new Array(arguments.length); + + // copy arguments + for (var i = 0; i < args.length; i++) { + args[i] = arguments[i]; + } + + // mark complete + complete = true; + + if (sync) { + process.nextTick(invokeCallback); + } else { + invokeCallback(); + } + + function invokeCallback() { + cleanup(); + + if (args[0]) { + // halt the stream on error + halt(stream); + } + + callback.apply(null, args); + } + } + + function onAborted() { + if (complete) return; + + done( + createError(400, "request aborted", { + code: "ECONNABORTED", + expected: length, + length: length, + received: received, + type: "request.aborted", + }) + ); + } + + function onData(chunk) { + if (complete) return; + + received += chunk.length; + + if (limit !== null && received > limit) { + done( + createError(413, "request entity too large", { + limit: limit, + received: received, + type: "entity.too.large", + }) + ); + } else if (decoder) { + buffer += decoder.write(chunk); + } else { + buffer.push(chunk); + } + } + + function onEnd(err) { + if (complete) return; + if (err) return done(err); + + if (length !== null && received !== length) { + done( + createError(400, "request size did not match content length", { + expected: length, + length: length, + received: received, + type: "request.size.invalid", + }) + ); + } else { + var string = decoder + ? buffer + (decoder.end() || "") + : Buffer.concat(buffer); + done(null, string); + } + } + + function cleanup() { + buffer = null; + + stream.removeListener("aborted", onAborted); + stream.removeListener("data", onData); + stream.removeListener("end", onEnd); + stream.removeListener("error", onEnd); + stream.removeListener("close", cleanup); + } + } + + /** + * Try to require async_hooks + * @private + */ + + function tryRequireAsyncHooks() { + try { + return __nccwpck_require__(290); + } catch (e) { + return {}; + } + } + + /** + * Wrap function with async resource, if possible. + * AsyncResource.bind static method backported. + * @private + */ + + function wrap(fn) { + var res; + + // create anonymous resource + if (asyncHooks.AsyncResource) { + res = new asyncHooks.AsyncResource(fn.name || "bound-anonymous-fn"); + } + + // incompatible node.js + if (!res || !res.runInAsyncScope) { + return fn; + } + + // return bound function + return res.runInAsyncScope.bind(res, fn, null); + } + + /***/ + }, + + /***/ 6074: /***/ (module) => { + /*! + * bytes + * Copyright(c) 2012-2014 TJ Holowaychuk + * Copyright(c) 2015 Jed Watson + * MIT Licensed + */ + + /** + * Module exports. + * @public + */ + + module.exports = bytes; + module.exports.format = format; + module.exports.parse = parse; + + /** + * Module variables. + * @private + */ + + var formatThousandsRegExp = /\B(?=(\d{3})+(?!\d))/g; + + var formatDecimalsRegExp = /(?:\.0*|(\.[^0]+)0+)$/; + + var map = { + b: 1, + kb: 1 << 10, + mb: 1 << 20, + gb: 1 << 30, + tb: Math.pow(1024, 4), + pb: Math.pow(1024, 5), + }; + + var parseRegExp = /^((-|\+)?(\d+(?:\.\d+)?)) *(kb|mb|gb|tb|pb)$/i; + + /** + * Convert the given value in bytes into a string or parse to string to an integer in bytes. + * + * @param {string|number} value + * @param {{ + * case: [string], + * decimalPlaces: [number] + * fixedDecimals: [boolean] + * thousandsSeparator: [string] + * unitSeparator: [string] + * }} [options] bytes options. + * + * @returns {string|number|null} + */ + + function bytes(value, options) { + if (typeof value === "string") { + return parse(value); + } + + if (typeof value === "number") { + return format(value, options); + } + + return null; + } + + /** + * Format the given value in bytes into a string. + * + * If the value is negative, it is kept as such. If it is a float, + * it is rounded. + * + * @param {number} value + * @param {object} [options] + * @param {number} [options.decimalPlaces=2] + * @param {number} [options.fixedDecimals=false] + * @param {string} [options.thousandsSeparator=] + * @param {string} [options.unit=] + * @param {string} [options.unitSeparator=] + * + * @returns {string|null} + * @public + */ + + function format(value, options) { + if (!Number.isFinite(value)) { + return null; + } + + var mag = Math.abs(value); + var thousandsSeparator = (options && options.thousandsSeparator) || ""; + var unitSeparator = (options && options.unitSeparator) || ""; + var decimalPlaces = + options && options.decimalPlaces !== undefined + ? options.decimalPlaces + : 2; + var fixedDecimals = Boolean(options && options.fixedDecimals); + var unit = (options && options.unit) || ""; + + if (!unit || !map[unit.toLowerCase()]) { + if (mag >= map.pb) { + unit = "PB"; + } else if (mag >= map.tb) { + unit = "TB"; + } else if (mag >= map.gb) { + unit = "GB"; + } else if (mag >= map.mb) { + unit = "MB"; + } else if (mag >= map.kb) { + unit = "KB"; + } else { + unit = "B"; + } + } + + var val = value / map[unit.toLowerCase()]; + var str = val.toFixed(decimalPlaces); + + if (!fixedDecimals) { + str = str.replace(formatDecimalsRegExp, "$1"); + } + + if (thousandsSeparator) { + str = str + .split(".") + .map(function (s, i) { + return i === 0 + ? s.replace(formatThousandsRegExp, thousandsSeparator) + : s; + }) + .join("."); + } + + return str + unitSeparator + unit; + } + + /** + * Parse the string value into an integer in bytes. + * + * If no unit is given, it is assumed the value is in bytes. + * + * @param {number|string} val + * + * @returns {number|null} + * @public + */ + + function parse(val) { + if (typeof val === "number" && !isNaN(val)) { + return val; + } + + if (typeof val !== "string") { + return null; + } + + // Test if the string passed is valid + var results = parseRegExp.exec(val); + var floatValue; + var unit = "b"; + + if (!results) { + // Nothing could be extracted from the given string + floatValue = parseInt(val, 10); + unit = "b"; + } else { + // Retrieve the value and the unit + floatValue = parseFloat(results[1]); + unit = results[4].toLowerCase(); + } + + if (isNaN(floatValue)) { + return null; + } + + return Math.floor(map[unit] * floatValue); + } + + /***/ + }, + + /***/ 5450: /***/ (module, __unused_webpack_exports, __nccwpck_require__) => { + var bind = __nccwpck_require__(5145); + + var $apply = __nccwpck_require__(9484); + var $call = __nccwpck_require__(7838); + var $reflectApply = __nccwpck_require__(3237); + + /** @type {import('./actualApply')} */ + module.exports = $reflectApply || bind.call($call, $apply); + + /***/ + }, + + /***/ 9484: /***/ (module) => { + /** @type {import('./functionApply')} */ + module.exports = Function.prototype.apply; + + /***/ + }, + + /***/ 7838: /***/ (module) => { + /** @type {import('./functionCall')} */ + module.exports = Function.prototype.call; + + /***/ + }, + + /***/ 4496: /***/ (module, __unused_webpack_exports, __nccwpck_require__) => { + var bind = __nccwpck_require__(5145); + var $TypeError = __nccwpck_require__(5777); + + var $call = __nccwpck_require__(7838); + var $actualApply = __nccwpck_require__(5450); + + /** @type {(args: [Function, thisArg?: unknown, ...args: unknown[]]) => Function} TODO FIXME, find a way to use import('.') */ + module.exports = function callBindBasic(args) { + if (args.length < 1 || typeof args[0] !== "function") { + throw new $TypeError("a function is required"); + } + return $actualApply(bind, $call, args); + }; + + /***/ + }, + + /***/ 3237: /***/ (module) => { + /** @type {import('./reflectApply')} */ + module.exports = typeof Reflect !== "undefined" && Reflect && Reflect.apply; + + /***/ + }, + + /***/ 9366: /***/ (module, __unused_webpack_exports, __nccwpck_require__) => { + var GetIntrinsic = __nccwpck_require__(3947); + + var callBindBasic = __nccwpck_require__(4496); + + /** @type {(thisArg: string, searchString: string, position?: number) => number} */ + var $indexOf = callBindBasic([GetIntrinsic("%String.prototype.indexOf%")]); + + /** @type {import('./index.js')} */ + module.exports = function callBoundIntrinsic(name, allowMissing) { + /* eslint no-extra-parens: 0 */ + + var intrinsic = + /** @type {(this: unknown, ...args: unknown[]) => unknown} */ ( + GetIntrinsic(name, !!allowMissing) + ); + if ( + typeof intrinsic === "function" && + $indexOf(name, ".prototype.") > -1 + ) { + return callBindBasic(/** @type {const} */ ([intrinsic])); + } + return intrinsic; + }; + + /***/ + }, + + /***/ 2814: /***/ (module, __unused_webpack_exports, __nccwpck_require__) => { + /*! + * content-disposition + * Copyright(c) 2014-2017 Douglas Christopher Wilson + * MIT Licensed + */ + + /** + * Module exports. + * @public + */ + + module.exports = contentDisposition; + module.exports.parse = parse; + + /** + * Module dependencies. + * @private + */ + + var basename = __nccwpck_require__(6928).basename; + var Buffer = __nccwpck_require__(4731).Buffer; + + /** + * RegExp to match non attr-char, *after* encodeURIComponent (i.e. not including "%") + * @private + */ + + var ENCODE_URL_ATTR_CHAR_REGEXP = /[\x00-\x20"'()*,/:;<=>?@[\\\]{}\x7f]/g; // eslint-disable-line no-control-regex + + /** + * RegExp to match percent encoding escape. + * @private + */ + + var HEX_ESCAPE_REGEXP = /%[0-9A-Fa-f]{2}/; + var HEX_ESCAPE_REPLACE_REGEXP = /%([0-9A-Fa-f]{2})/g; + + /** + * RegExp to match non-latin1 characters. + * @private + */ + + var NON_LATIN1_REGEXP = /[^\x20-\x7e\xa0-\xff]/g; + + /** + * RegExp to match quoted-pair in RFC 2616 + * + * quoted-pair = "\" CHAR + * CHAR = + * @private + */ + + var QESC_REGEXP = /\\([\u0000-\u007f])/g; // eslint-disable-line no-control-regex + + /** + * RegExp to match chars that must be quoted-pair in RFC 2616 + * @private + */ + + var QUOTE_REGEXP = /([\\"])/g; + + /** + * RegExp for various RFC 2616 grammar + * + * parameter = token "=" ( token | quoted-string ) + * token = 1* + * separators = "(" | ")" | "<" | ">" | "@" + * | "," | ";" | ":" | "\" | <"> + * | "/" | "[" | "]" | "?" | "=" + * | "{" | "}" | SP | HT + * quoted-string = ( <"> *(qdtext | quoted-pair ) <"> ) + * qdtext = > + * quoted-pair = "\" CHAR + * CHAR = + * TEXT = + * LWS = [CRLF] 1*( SP | HT ) + * CRLF = CR LF + * CR = + * LF = + * SP = + * HT = + * CTL = + * OCTET = + * @private + */ + + var PARAM_REGEXP = + /;[\x09\x20]*([!#$%&'*+.0-9A-Z^_`a-z|~-]+)[\x09\x20]*=[\x09\x20]*("(?:[\x20!\x23-\x5b\x5d-\x7e\x80-\xff]|\\[\x20-\x7e])*"|[!#$%&'*+.0-9A-Z^_`a-z|~-]+)[\x09\x20]*/g; // eslint-disable-line no-control-regex + var TEXT_REGEXP = /^[\x20-\x7e\x80-\xff]+$/; + var TOKEN_REGEXP = /^[!#$%&'*+.0-9A-Z^_`a-z|~-]+$/; + + /** + * RegExp for various RFC 5987 grammar + * + * ext-value = charset "'" [ language ] "'" value-chars + * charset = "UTF-8" / "ISO-8859-1" / mime-charset + * mime-charset = 1*mime-charsetc + * mime-charsetc = ALPHA / DIGIT + * / "!" / "#" / "$" / "%" / "&" + * / "+" / "-" / "^" / "_" / "`" + * / "{" / "}" / "~" + * language = ( 2*3ALPHA [ extlang ] ) + * / 4ALPHA + * / 5*8ALPHA + * extlang = *3( "-" 3ALPHA ) + * value-chars = *( pct-encoded / attr-char ) + * pct-encoded = "%" HEXDIG HEXDIG + * attr-char = ALPHA / DIGIT + * / "!" / "#" / "$" / "&" / "+" / "-" / "." + * / "^" / "_" / "`" / "|" / "~" + * @private + */ + + var EXT_VALUE_REGEXP = + /^([A-Za-z0-9!#$%&+\-^_`{}~]+)'(?:[A-Za-z]{2,3}(?:-[A-Za-z]{3}){0,3}|[A-Za-z]{4,8}|)'((?:%[0-9A-Fa-f]{2}|[A-Za-z0-9!#$&+.^_`|~-])+)$/; + + /** + * RegExp for various RFC 6266 grammar + * + * disposition-type = "inline" | "attachment" | disp-ext-type + * disp-ext-type = token + * disposition-parm = filename-parm | disp-ext-parm + * filename-parm = "filename" "=" value + * | "filename*" "=" ext-value + * disp-ext-parm = token "=" value + * | ext-token "=" ext-value + * ext-token = + * @private + */ + + var DISPOSITION_TYPE_REGEXP = + /^([!#$%&'*+.0-9A-Z^_`a-z|~-]+)[\x09\x20]*(?:$|;)/; // eslint-disable-line no-control-regex + + /** + * Create an attachment Content-Disposition header. + * + * @param {string} [filename] + * @param {object} [options] + * @param {string} [options.type=attachment] + * @param {string|boolean} [options.fallback=true] + * @return {string} + * @public + */ + + function contentDisposition(filename, options) { + var opts = options || {}; + + // get type + var type = opts.type || "attachment"; + + // get parameters + var params = createparams(filename, opts.fallback); + + // format into string + return format(new ContentDisposition(type, params)); + } + + /** + * Create parameters object from filename and fallback. + * + * @param {string} [filename] + * @param {string|boolean} [fallback=true] + * @return {object} + * @private + */ + + function createparams(filename, fallback) { + if (filename === undefined) { + return; + } + + var params = {}; + + if (typeof filename !== "string") { + throw new TypeError("filename must be a string"); + } + + // fallback defaults to true + if (fallback === undefined) { + fallback = true; + } + + if (typeof fallback !== "string" && typeof fallback !== "boolean") { + throw new TypeError("fallback must be a string or boolean"); + } + + if (typeof fallback === "string" && NON_LATIN1_REGEXP.test(fallback)) { + throw new TypeError("fallback must be ISO-8859-1 string"); + } + + // restrict to file base name + var name = basename(filename); + + // determine if name is suitable for quoted string + var isQuotedString = TEXT_REGEXP.test(name); + + // generate fallback name + var fallbackName = + typeof fallback !== "string" + ? fallback && getlatin1(name) + : basename(fallback); + var hasFallback = + typeof fallbackName === "string" && fallbackName !== name; + + // set extended filename parameter + if (hasFallback || !isQuotedString || HEX_ESCAPE_REGEXP.test(name)) { + params["filename*"] = name; + } + + // set filename parameter + if (isQuotedString || hasFallback) { + params.filename = hasFallback ? fallbackName : name; + } + + return params; + } + + /** + * Format object to Content-Disposition header. + * + * @param {object} obj + * @param {string} obj.type + * @param {object} [obj.parameters] + * @return {string} + * @private + */ + + function format(obj) { + var parameters = obj.parameters; + var type = obj.type; + + if (!type || typeof type !== "string" || !TOKEN_REGEXP.test(type)) { + throw new TypeError("invalid type"); + } + + // start with normalized type + var string = String(type).toLowerCase(); + + // append parameters + if (parameters && typeof parameters === "object") { + var param; + var params = Object.keys(parameters).sort(); + + for (var i = 0; i < params.length; i++) { + param = params[i]; + + var val = + param.substr(-1) === "*" + ? ustring(parameters[param]) + : qstring(parameters[param]); + + string += "; " + param + "=" + val; + } + } + + return string; + } + + /** + * Decode a RFC 5987 field value (gracefully). + * + * @param {string} str + * @return {string} + * @private + */ + + function decodefield(str) { + var match = EXT_VALUE_REGEXP.exec(str); + + if (!match) { + throw new TypeError("invalid extended field value"); + } + + var charset = match[1].toLowerCase(); + var encoded = match[2]; + var value; + + // to binary string + var binary = encoded.replace(HEX_ESCAPE_REPLACE_REGEXP, pdecode); + + switch (charset) { + case "iso-8859-1": + value = getlatin1(binary); + break; + case "utf-8": + value = Buffer.from(binary, "binary").toString("utf8"); + break; + default: + throw new TypeError("unsupported charset in extended field"); + } + + return value; + } + + /** + * Get ISO-8859-1 version of string. + * + * @param {string} val + * @return {string} + * @private + */ + + function getlatin1(val) { + // simple Unicode -> ISO-8859-1 transformation + return String(val).replace(NON_LATIN1_REGEXP, "?"); + } + + /** + * Parse Content-Disposition header string. + * + * @param {string} string + * @return {object} + * @public + */ + + function parse(string) { + if (!string || typeof string !== "string") { + throw new TypeError("argument string is required"); + } + + var match = DISPOSITION_TYPE_REGEXP.exec(string); + + if (!match) { + throw new TypeError("invalid type format"); + } + + // normalize type + var index = match[0].length; + var type = match[1].toLowerCase(); + + var key; + var names = []; + var params = {}; + var value; + + // calculate index to start at + index = PARAM_REGEXP.lastIndex = + match[0].substr(-1) === ";" ? index - 1 : index; + + // match parameters + while ((match = PARAM_REGEXP.exec(string))) { + if (match.index !== index) { + throw new TypeError("invalid parameter format"); + } + + index += match[0].length; + key = match[1].toLowerCase(); + value = match[2]; + + if (names.indexOf(key) !== -1) { + throw new TypeError("invalid duplicate parameter"); + } + + names.push(key); + + if (key.indexOf("*") + 1 === key.length) { + // decode extended value + key = key.slice(0, -1); + value = decodefield(value); + + // overwrite existing value + params[key] = value; + continue; + } + + if (typeof params[key] === "string") { + continue; + } + + if (value[0] === '"') { + // remove quotes and escapes + value = value.substr(1, value.length - 2).replace(QESC_REGEXP, "$1"); + } + + params[key] = value; + } + + if (index !== -1 && index !== string.length) { + throw new TypeError("invalid parameter format"); + } + + return new ContentDisposition(type, params); + } + + /** + * Percent decode a single character. + * + * @param {string} str + * @param {string} hex + * @return {string} + * @private + */ + + function pdecode(str, hex) { + return String.fromCharCode(parseInt(hex, 16)); + } + + /** + * Percent encode a single character. + * + * @param {string} char + * @return {string} + * @private + */ + + function pencode(char) { + return "%" + String(char).charCodeAt(0).toString(16).toUpperCase(); + } + + /** + * Quote a string for HTTP. + * + * @param {string} val + * @return {string} + * @private + */ + + function qstring(val) { + var str = String(val); + + return '"' + str.replace(QUOTE_REGEXP, "\\$1") + '"'; + } + + /** + * Encode a Unicode string for HTTP (RFC 5987). + * + * @param {string} val + * @return {string} + * @private + */ + + function ustring(val) { + var str = String(val); + + // percent encode as UTF-8 + var encoded = encodeURIComponent(str).replace( + ENCODE_URL_ATTR_CHAR_REGEXP, + pencode + ); + + return "UTF-8''" + encoded; + } + + /** + * Class for parsed Content-Disposition header for v8 optimization + * + * @public + * @param {string} type + * @param {object} parameters + * @constructor + */ + + function ContentDisposition(type, parameters) { + this.type = type; + this.parameters = parameters; + } + + /***/ + }, + + /***/ 607: /***/ (__unused_webpack_module, exports) => { + /*! + * content-type + * Copyright(c) 2015 Douglas Christopher Wilson + * MIT Licensed + */ + + /** + * RegExp to match *( ";" parameter ) in RFC 7231 sec 3.1.1.1 + * + * parameter = token "=" ( token / quoted-string ) + * token = 1*tchar + * tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" + * / "+" / "-" / "." / "^" / "_" / "`" / "|" / "~" + * / DIGIT / ALPHA + * ; any VCHAR, except delimiters + * quoted-string = DQUOTE *( qdtext / quoted-pair ) DQUOTE + * qdtext = HTAB / SP / %x21 / %x23-5B / %x5D-7E / obs-text + * obs-text = %x80-FF + * quoted-pair = "\" ( HTAB / SP / VCHAR / obs-text ) + */ + var PARAM_REGEXP = + /; *([!#$%&'*+.^_`|~0-9A-Za-z-]+) *= *("(?:[\u000b\u0020\u0021\u0023-\u005b\u005d-\u007e\u0080-\u00ff]|\\[\u000b\u0020-\u00ff])*"|[!#$%&'*+.^_`|~0-9A-Za-z-]+) */g; // eslint-disable-line no-control-regex + var TEXT_REGEXP = /^[\u000b\u0020-\u007e\u0080-\u00ff]+$/; // eslint-disable-line no-control-regex + var TOKEN_REGEXP = /^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/; + + /** + * RegExp to match quoted-pair in RFC 7230 sec 3.2.6 + * + * quoted-pair = "\" ( HTAB / SP / VCHAR / obs-text ) + * obs-text = %x80-FF + */ + var QESC_REGEXP = /\\([\u000b\u0020-\u00ff])/g; // eslint-disable-line no-control-regex + + /** + * RegExp to match chars that must be quoted-pair in RFC 7230 sec 3.2.6 + */ + var QUOTE_REGEXP = /([\\"])/g; + + /** + * RegExp to match type in RFC 7231 sec 3.1.1.1 + * + * media-type = type "/" subtype + * type = token + * subtype = token + */ + var TYPE_REGEXP = + /^[!#$%&'*+.^_`|~0-9A-Za-z-]+\/[!#$%&'*+.^_`|~0-9A-Za-z-]+$/; + + /** + * Module exports. + * @public + */ + + exports.format = format; + exports.parse = parse; + + /** + * Format object to media type. + * + * @param {object} obj + * @return {string} + * @public + */ + + function format(obj) { + if (!obj || typeof obj !== "object") { + throw new TypeError("argument obj is required"); + } + + var parameters = obj.parameters; + var type = obj.type; + + if (!type || !TYPE_REGEXP.test(type)) { + throw new TypeError("invalid type"); + } + + var string = type; + + // append parameters + if (parameters && typeof parameters === "object") { + var param; + var params = Object.keys(parameters).sort(); + + for (var i = 0; i < params.length; i++) { + param = params[i]; + + if (!TOKEN_REGEXP.test(param)) { + throw new TypeError("invalid parameter name"); + } + + string += "; " + param + "=" + qstring(parameters[param]); + } + } + + return string; + } + + /** + * Parse media type to object. + * + * @param {string|object} string + * @return {Object} + * @public + */ + + function parse(string) { + if (!string) { + throw new TypeError("argument string is required"); + } + + // support req/res-like objects as argument + var header = typeof string === "object" ? getcontenttype(string) : string; + + if (typeof header !== "string") { + throw new TypeError("argument string is required to be a string"); + } + + var index = header.indexOf(";"); + var type = index !== -1 ? header.slice(0, index).trim() : header.trim(); + + if (!TYPE_REGEXP.test(type)) { + throw new TypeError("invalid media type"); + } + + var obj = new ContentType(type.toLowerCase()); + + // parse parameters + if (index !== -1) { + var key; + var match; + var value; + + PARAM_REGEXP.lastIndex = index; + + while ((match = PARAM_REGEXP.exec(header))) { + if (match.index !== index) { + throw new TypeError("invalid parameter format"); + } + + index += match[0].length; + key = match[1].toLowerCase(); + value = match[2]; + + if (value.charCodeAt(0) === 0x22 /* " */) { + // remove quotes + value = value.slice(1, -1); + + // remove escapes + if (value.indexOf("\\") !== -1) { + value = value.replace(QESC_REGEXP, "$1"); + } + } + + obj.parameters[key] = value; + } + + if (index !== header.length) { + throw new TypeError("invalid parameter format"); + } + } + + return obj; + } + + /** + * Get content-type from req/res objects. + * + * @param {object} + * @return {Object} + * @private + */ + + function getcontenttype(obj) { + var header; + + if (typeof obj.getHeader === "function") { + // res-like + header = obj.getHeader("content-type"); + } else if (typeof obj.headers === "object") { + // req-like + header = obj.headers && obj.headers["content-type"]; + } + + if (typeof header !== "string") { + throw new TypeError("content-type header is missing from object"); + } + + return header; + } + + /** + * Quote a string if necessary. + * + * @param {string} val + * @return {string} + * @private + */ + + function qstring(val) { + var str = String(val); + + // no need to quote tokens + if (TOKEN_REGEXP.test(str)) { + return str; + } + + if (str.length > 0 && !TEXT_REGEXP.test(str)) { + throw new TypeError("invalid parameter value"); + } + + return '"' + str.replace(QUOTE_REGEXP, "\\$1") + '"'; + } + + /** + * Class to represent a content type. + * @private + */ + function ContentType(type) { + this.parameters = Object.create(null); + this.type = type; + } + + /***/ + }, + + /***/ 4806: /***/ (__unused_webpack_module, exports, __nccwpck_require__) => { + /** + * Module dependencies. + */ + + var crypto = __nccwpck_require__(6982); + + /** + * Sign the given `val` with `secret`. + * + * @param {String} val + * @param {String} secret + * @return {String} + * @api private + */ + + exports.sign = function (val, secret) { + if ("string" != typeof val) + throw new TypeError("Cookie value must be provided as a string."); + if ("string" != typeof secret) + throw new TypeError("Secret string must be provided."); + return ( + val + + "." + + crypto + .createHmac("sha256", secret) + .update(val) + .digest("base64") + .replace(/\=+$/, "") + ); + }; + + /** + * Unsign and decode the given `val` with `secret`, + * returning `false` if the signature is invalid. + * + * @param {String} val + * @param {String} secret + * @return {String|Boolean} + * @api private + */ + + exports.unsign = function (val, secret) { + if ("string" != typeof val) + throw new TypeError("Signed cookie string must be provided."); + if ("string" != typeof secret) + throw new TypeError("Secret string must be provided."); + var str = val.slice(0, val.lastIndexOf(".")), + mac = exports.sign(str, secret); + + return sha1(mac) == sha1(val) ? str : false; + }; + + /** + * Private + */ + + function sha1(str) { + return crypto.createHash("sha1").update(str).digest("hex"); + } + + /***/ + }, + + /***/ 7069: /***/ (__unused_webpack_module, exports) => { + /*! + * cookie + * Copyright(c) 2012-2014 Roman Shtylman + * Copyright(c) 2015 Douglas Christopher Wilson + * MIT Licensed + */ + + /** + * Module exports. + * @public + */ + + exports.parse = parse; + exports.serialize = serialize; + + /** + * Module variables. + * @private + */ + + var __toString = Object.prototype.toString; + + /** + * RegExp to match cookie-name in RFC 6265 sec 4.1.1 + * This refers out to the obsoleted definition of token in RFC 2616 sec 2.2 + * which has been replaced by the token definition in RFC 7230 appendix B. + * + * cookie-name = token + * token = 1*tchar + * tchar = "!" / "#" / "$" / "%" / "&" / "'" / + * "*" / "+" / "-" / "." / "^" / "_" / + * "`" / "|" / "~" / DIGIT / ALPHA + */ + + var cookieNameRegExp = /^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/; + + /** + * RegExp to match cookie-value in RFC 6265 sec 4.1.1 + * + * cookie-value = *cookie-octet / ( DQUOTE *cookie-octet DQUOTE ) + * cookie-octet = %x21 / %x23-2B / %x2D-3A / %x3C-5B / %x5D-7E + * ; US-ASCII characters excluding CTLs, + * ; whitespace DQUOTE, comma, semicolon, + * ; and backslash + */ + + var cookieValueRegExp = + /^("?)[\u0021\u0023-\u002B\u002D-\u003A\u003C-\u005B\u005D-\u007E]*\1$/; + + /** + * RegExp to match domain-value in RFC 6265 sec 4.1.1 + * + * domain-value = + * ; defined in [RFC1034], Section 3.5, as + * ; enhanced by [RFC1123], Section 2.1 + * =