get-it
Version:
Generic HTTP request library for node, browsers and workers
1 lines • 71.6 kB
Source Map (JSON)
{"version":3,"file":"middleware.browser.cjs","sources":["../src/middleware/agent/browser-agent.ts","../src/middleware/base.ts","../node_modules/debug/src/browser.js","../node_modules/debug/src/common.js","../node_modules/ms/index.js","../src/middleware/debug.ts","../src/middleware/httpErrors.ts","../src/util/isBuffer.ts","../src/util/isPlainObject.ts","../src/middleware/jsonRequest.ts","../src/util/global.ts","../src/middleware/promise.ts","../src/util/browser-shouldRetry.ts","../src/middleware/retry/shared-retry.ts","../src/middleware/retry/browser-retry.ts","../src/middleware/urlEncoded.ts","../src/request/node-request.ts","../src/middleware.browser.ts","../src/middleware/keepAlive.ts","../src/middleware/headers.ts","../src/middleware/injectResponse.ts","../src/middleware/jsonResponse.ts","../src/middleware/mtls.ts","../src/util/isBrowserOptions.ts","../src/middleware/observable.ts","../src/middleware/progress/browser-progress.ts","../src/middleware/proxy.ts"],"sourcesContent":["/**\n * This middleware only has an effect in Node.js.\n * @public\n */\nexport function agent(\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n _opts?: any,\n): any {\n return {}\n}\n","import type {Middleware} from 'get-it'\n\nconst leadingSlash = /^\\//\nconst trailingSlash = /\\/$/\n\n/** @public */\nexport function base(baseUrl: string) {\n const baseUri = baseUrl.replace(trailingSlash, '')\n return {\n processOptions: (options) => {\n if (/^https?:\\/\\//i.test(options.url)) {\n return options // Already prefixed\n }\n\n const url = [baseUri, options.url.replace(leadingSlash, '')].join('/')\n return Object.assign({}, options, {url})\n },\n } satisfies Middleware\n}\n","/* eslint-env browser */\n\n/**\n * This is the web browser implementation of `debug()`.\n */\n\nexports.formatArgs = formatArgs;\nexports.save = save;\nexports.load = load;\nexports.useColors = useColors;\nexports.storage = localstorage();\nexports.destroy = (() => {\n\tlet warned = false;\n\n\treturn () => {\n\t\tif (!warned) {\n\t\t\twarned = true;\n\t\t\tconsole.warn('Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.');\n\t\t}\n\t};\n})();\n\n/**\n * Colors.\n */\n\nexports.colors = [\n\t'#0000CC',\n\t'#0000FF',\n\t'#0033CC',\n\t'#0033FF',\n\t'#0066CC',\n\t'#0066FF',\n\t'#0099CC',\n\t'#0099FF',\n\t'#00CC00',\n\t'#00CC33',\n\t'#00CC66',\n\t'#00CC99',\n\t'#00CCCC',\n\t'#00CCFF',\n\t'#3300CC',\n\t'#3300FF',\n\t'#3333CC',\n\t'#3333FF',\n\t'#3366CC',\n\t'#3366FF',\n\t'#3399CC',\n\t'#3399FF',\n\t'#33CC00',\n\t'#33CC33',\n\t'#33CC66',\n\t'#33CC99',\n\t'#33CCCC',\n\t'#33CCFF',\n\t'#6600CC',\n\t'#6600FF',\n\t'#6633CC',\n\t'#6633FF',\n\t'#66CC00',\n\t'#66CC33',\n\t'#9900CC',\n\t'#9900FF',\n\t'#9933CC',\n\t'#9933FF',\n\t'#99CC00',\n\t'#99CC33',\n\t'#CC0000',\n\t'#CC0033',\n\t'#CC0066',\n\t'#CC0099',\n\t'#CC00CC',\n\t'#CC00FF',\n\t'#CC3300',\n\t'#CC3333',\n\t'#CC3366',\n\t'#CC3399',\n\t'#CC33CC',\n\t'#CC33FF',\n\t'#CC6600',\n\t'#CC6633',\n\t'#CC9900',\n\t'#CC9933',\n\t'#CCCC00',\n\t'#CCCC33',\n\t'#FF0000',\n\t'#FF0033',\n\t'#FF0066',\n\t'#FF0099',\n\t'#FF00CC',\n\t'#FF00FF',\n\t'#FF3300',\n\t'#FF3333',\n\t'#FF3366',\n\t'#FF3399',\n\t'#FF33CC',\n\t'#FF33FF',\n\t'#FF6600',\n\t'#FF6633',\n\t'#FF9900',\n\t'#FF9933',\n\t'#FFCC00',\n\t'#FFCC33'\n];\n\n/**\n * Currently only WebKit-based Web Inspectors, Firefox >= v31,\n * and the Firebug extension (any Firefox version) are known\n * to support \"%c\" CSS customizations.\n *\n * TODO: add a `localStorage` variable to explicitly enable/disable colors\n */\n\n// eslint-disable-next-line complexity\nfunction useColors() {\n\t// NB: In an Electron preload script, document will be defined but not fully\n\t// initialized. Since we know we're in Chrome, we'll just detect this case\n\t// explicitly\n\tif (typeof window !== 'undefined' && window.process && (window.process.type === 'renderer' || window.process.__nwjs)) {\n\t\treturn true;\n\t}\n\n\t// Internet Explorer and Edge do not support colors.\n\tif (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/(edge|trident)\\/(\\d+)/)) {\n\t\treturn false;\n\t}\n\n\tlet m;\n\n\t// Is webkit? http://stackoverflow.com/a/16459606/376773\n\t// document is undefined in react-native: https://github.com/facebook/react-native/pull/1632\n\t// eslint-disable-next-line no-return-assign\n\treturn (typeof document !== 'undefined' && document.documentElement && document.documentElement.style && document.documentElement.style.WebkitAppearance) ||\n\t\t// Is firebug? http://stackoverflow.com/a/398120/376773\n\t\t(typeof window !== 'undefined' && window.console && (window.console.firebug || (window.console.exception && window.console.table))) ||\n\t\t// Is firefox >= v31?\n\t\t// https://developer.mozilla.org/en-US/docs/Tools/Web_Console#Styling_messages\n\t\t(typeof navigator !== 'undefined' && navigator.userAgent && (m = navigator.userAgent.toLowerCase().match(/firefox\\/(\\d+)/)) && parseInt(m[1], 10) >= 31) ||\n\t\t// Double check webkit in userAgent just in case we are in a worker\n\t\t(typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/applewebkit\\/(\\d+)/));\n}\n\n/**\n * Colorize log arguments if enabled.\n *\n * @api public\n */\n\nfunction formatArgs(args) {\n\targs[0] = (this.useColors ? '%c' : '') +\n\t\tthis.namespace +\n\t\t(this.useColors ? ' %c' : ' ') +\n\t\targs[0] +\n\t\t(this.useColors ? '%c ' : ' ') +\n\t\t'+' + module.exports.humanize(this.diff);\n\n\tif (!this.useColors) {\n\t\treturn;\n\t}\n\n\tconst c = 'color: ' + this.color;\n\targs.splice(1, 0, c, 'color: inherit');\n\n\t// The final \"%c\" is somewhat tricky, because there could be other\n\t// arguments passed either before or after the %c, so we need to\n\t// figure out the correct index to insert the CSS into\n\tlet index = 0;\n\tlet lastC = 0;\n\targs[0].replace(/%[a-zA-Z%]/g, match => {\n\t\tif (match === '%%') {\n\t\t\treturn;\n\t\t}\n\t\tindex++;\n\t\tif (match === '%c') {\n\t\t\t// We only are interested in the *last* %c\n\t\t\t// (the user may have provided their own)\n\t\t\tlastC = index;\n\t\t}\n\t});\n\n\targs.splice(lastC, 0, c);\n}\n\n/**\n * Invokes `console.debug()` when available.\n * No-op when `console.debug` is not a \"function\".\n * If `console.debug` is not available, falls back\n * to `console.log`.\n *\n * @api public\n */\nexports.log = console.debug || console.log || (() => {});\n\n/**\n * Save `namespaces`.\n *\n * @param {String} namespaces\n * @api private\n */\nfunction save(namespaces) {\n\ttry {\n\t\tif (namespaces) {\n\t\t\texports.storage.setItem('debug', namespaces);\n\t\t} else {\n\t\t\texports.storage.removeItem('debug');\n\t\t}\n\t} catch (error) {\n\t\t// Swallow\n\t\t// XXX (@Qix-) should we be logging these?\n\t}\n}\n\n/**\n * Load `namespaces`.\n *\n * @return {String} returns the previously persisted debug modes\n * @api private\n */\nfunction load() {\n\tlet r;\n\ttry {\n\t\tr = exports.storage.getItem('debug') || exports.storage.getItem('DEBUG') ;\n\t} catch (error) {\n\t\t// Swallow\n\t\t// XXX (@Qix-) should we be logging these?\n\t}\n\n\t// If debug isn't set in LS, and we're in Electron, try to load $DEBUG\n\tif (!r && typeof process !== 'undefined' && 'env' in process) {\n\t\tr = process.env.DEBUG;\n\t}\n\n\treturn r;\n}\n\n/**\n * Localstorage attempts to return the localstorage.\n *\n * This is necessary because safari throws\n * when a user disables cookies/localstorage\n * and you attempt to access it.\n *\n * @return {LocalStorage}\n * @api private\n */\n\nfunction localstorage() {\n\ttry {\n\t\t// TVMLKit (Apple TV JS Runtime) does not have a window object, just localStorage in the global context\n\t\t// The Browser also has localStorage in the global context.\n\t\treturn localStorage;\n\t} catch (error) {\n\t\t// Swallow\n\t\t// XXX (@Qix-) should we be logging these?\n\t}\n}\n\nmodule.exports = require('./common')(exports);\n\nconst {formatters} = module.exports;\n\n/**\n * Map %j to `JSON.stringify()`, since no Web Inspectors do that by default.\n */\n\nformatters.j = function (v) {\n\ttry {\n\t\treturn JSON.stringify(v);\n\t} catch (error) {\n\t\treturn '[UnexpectedJSONParseError]: ' + error.message;\n\t}\n};\n","\n/**\n * This is the common logic for both the Node.js and web browser\n * implementations of `debug()`.\n */\n\nfunction setup(env) {\n\tcreateDebug.debug = createDebug;\n\tcreateDebug.default = createDebug;\n\tcreateDebug.coerce = coerce;\n\tcreateDebug.disable = disable;\n\tcreateDebug.enable = enable;\n\tcreateDebug.enabled = enabled;\n\tcreateDebug.humanize = require('ms');\n\tcreateDebug.destroy = destroy;\n\n\tObject.keys(env).forEach(key => {\n\t\tcreateDebug[key] = env[key];\n\t});\n\n\t/**\n\t* The currently active debug mode names, and names to skip.\n\t*/\n\n\tcreateDebug.names = [];\n\tcreateDebug.skips = [];\n\n\t/**\n\t* Map of special \"%n\" handling functions, for the debug \"format\" argument.\n\t*\n\t* Valid key names are a single, lower or upper-case letter, i.e. \"n\" and \"N\".\n\t*/\n\tcreateDebug.formatters = {};\n\n\t/**\n\t* Selects a color for a debug namespace\n\t* @param {String} namespace The namespace string for the debug instance to be colored\n\t* @return {Number|String} An ANSI color code for the given namespace\n\t* @api private\n\t*/\n\tfunction selectColor(namespace) {\n\t\tlet hash = 0;\n\n\t\tfor (let i = 0; i < namespace.length; i++) {\n\t\t\thash = ((hash << 5) - hash) + namespace.charCodeAt(i);\n\t\t\thash |= 0; // Convert to 32bit integer\n\t\t}\n\n\t\treturn createDebug.colors[Math.abs(hash) % createDebug.colors.length];\n\t}\n\tcreateDebug.selectColor = selectColor;\n\n\t/**\n\t* Create a debugger with the given `namespace`.\n\t*\n\t* @param {String} namespace\n\t* @return {Function}\n\t* @api public\n\t*/\n\tfunction createDebug(namespace) {\n\t\tlet prevTime;\n\t\tlet enableOverride = null;\n\t\tlet namespacesCache;\n\t\tlet enabledCache;\n\n\t\tfunction debug(...args) {\n\t\t\t// Disabled?\n\t\t\tif (!debug.enabled) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst self = debug;\n\n\t\t\t// Set `diff` timestamp\n\t\t\tconst curr = Number(new Date());\n\t\t\tconst ms = curr - (prevTime || curr);\n\t\t\tself.diff = ms;\n\t\t\tself.prev = prevTime;\n\t\t\tself.curr = curr;\n\t\t\tprevTime = curr;\n\n\t\t\targs[0] = createDebug.coerce(args[0]);\n\n\t\t\tif (typeof args[0] !== 'string') {\n\t\t\t\t// Anything else let's inspect with %O\n\t\t\t\targs.unshift('%O');\n\t\t\t}\n\n\t\t\t// Apply any `formatters` transformations\n\t\t\tlet index = 0;\n\t\t\targs[0] = args[0].replace(/%([a-zA-Z%])/g, (match, format) => {\n\t\t\t\t// If we encounter an escaped % then don't increase the array index\n\t\t\t\tif (match === '%%') {\n\t\t\t\t\treturn '%';\n\t\t\t\t}\n\t\t\t\tindex++;\n\t\t\t\tconst formatter = createDebug.formatters[format];\n\t\t\t\tif (typeof formatter === 'function') {\n\t\t\t\t\tconst val = args[index];\n\t\t\t\t\tmatch = formatter.call(self, val);\n\n\t\t\t\t\t// Now we need to remove `args[index]` since it's inlined in the `format`\n\t\t\t\t\targs.splice(index, 1);\n\t\t\t\t\tindex--;\n\t\t\t\t}\n\t\t\t\treturn match;\n\t\t\t});\n\n\t\t\t// Apply env-specific formatting (colors, etc.)\n\t\t\tcreateDebug.formatArgs.call(self, args);\n\n\t\t\tconst logFn = self.log || createDebug.log;\n\t\t\tlogFn.apply(self, args);\n\t\t}\n\n\t\tdebug.namespace = namespace;\n\t\tdebug.useColors = createDebug.useColors();\n\t\tdebug.color = createDebug.selectColor(namespace);\n\t\tdebug.extend = extend;\n\t\tdebug.destroy = createDebug.destroy; // XXX Temporary. Will be removed in the next major release.\n\n\t\tObject.defineProperty(debug, 'enabled', {\n\t\t\tenumerable: true,\n\t\t\tconfigurable: false,\n\t\t\tget: () => {\n\t\t\t\tif (enableOverride !== null) {\n\t\t\t\t\treturn enableOverride;\n\t\t\t\t}\n\t\t\t\tif (namespacesCache !== createDebug.namespaces) {\n\t\t\t\t\tnamespacesCache = createDebug.namespaces;\n\t\t\t\t\tenabledCache = createDebug.enabled(namespace);\n\t\t\t\t}\n\n\t\t\t\treturn enabledCache;\n\t\t\t},\n\t\t\tset: v => {\n\t\t\t\tenableOverride = v;\n\t\t\t}\n\t\t});\n\n\t\t// Env-specific initialization logic for debug instances\n\t\tif (typeof createDebug.init === 'function') {\n\t\t\tcreateDebug.init(debug);\n\t\t}\n\n\t\treturn debug;\n\t}\n\n\tfunction extend(namespace, delimiter) {\n\t\tconst newDebug = createDebug(this.namespace + (typeof delimiter === 'undefined' ? ':' : delimiter) + namespace);\n\t\tnewDebug.log = this.log;\n\t\treturn newDebug;\n\t}\n\n\t/**\n\t* Enables a debug mode by namespaces. This can include modes\n\t* separated by a colon and wildcards.\n\t*\n\t* @param {String} namespaces\n\t* @api public\n\t*/\n\tfunction enable(namespaces) {\n\t\tcreateDebug.save(namespaces);\n\t\tcreateDebug.namespaces = namespaces;\n\n\t\tcreateDebug.names = [];\n\t\tcreateDebug.skips = [];\n\n\t\tconst split = (typeof namespaces === 'string' ? namespaces : '')\n\t\t\t.trim()\n\t\t\t.replace(/\\s+/g, ',')\n\t\t\t.split(',')\n\t\t\t.filter(Boolean);\n\n\t\tfor (const ns of split) {\n\t\t\tif (ns[0] === '-') {\n\t\t\t\tcreateDebug.skips.push(ns.slice(1));\n\t\t\t} else {\n\t\t\t\tcreateDebug.names.push(ns);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Checks if the given string matches a namespace template, honoring\n\t * asterisks as wildcards.\n\t *\n\t * @param {String} search\n\t * @param {String} template\n\t * @return {Boolean}\n\t */\n\tfunction matchesTemplate(search, template) {\n\t\tlet searchIndex = 0;\n\t\tlet templateIndex = 0;\n\t\tlet starIndex = -1;\n\t\tlet matchIndex = 0;\n\n\t\twhile (searchIndex < search.length) {\n\t\t\tif (templateIndex < template.length && (template[templateIndex] === search[searchIndex] || template[templateIndex] === '*')) {\n\t\t\t\t// Match character or proceed with wildcard\n\t\t\t\tif (template[templateIndex] === '*') {\n\t\t\t\t\tstarIndex = templateIndex;\n\t\t\t\t\tmatchIndex = searchIndex;\n\t\t\t\t\ttemplateIndex++; // Skip the '*'\n\t\t\t\t} else {\n\t\t\t\t\tsearchIndex++;\n\t\t\t\t\ttemplateIndex++;\n\t\t\t\t}\n\t\t\t} else if (starIndex !== -1) { // eslint-disable-line no-negated-condition\n\t\t\t\t// Backtrack to the last '*' and try to match more characters\n\t\t\t\ttemplateIndex = starIndex + 1;\n\t\t\t\tmatchIndex++;\n\t\t\t\tsearchIndex = matchIndex;\n\t\t\t} else {\n\t\t\t\treturn false; // No match\n\t\t\t}\n\t\t}\n\n\t\t// Handle trailing '*' in template\n\t\twhile (templateIndex < template.length && template[templateIndex] === '*') {\n\t\t\ttemplateIndex++;\n\t\t}\n\n\t\treturn templateIndex === template.length;\n\t}\n\n\t/**\n\t* Disable debug output.\n\t*\n\t* @return {String} namespaces\n\t* @api public\n\t*/\n\tfunction disable() {\n\t\tconst namespaces = [\n\t\t\t...createDebug.names,\n\t\t\t...createDebug.skips.map(namespace => '-' + namespace)\n\t\t].join(',');\n\t\tcreateDebug.enable('');\n\t\treturn namespaces;\n\t}\n\n\t/**\n\t* Returns true if the given mode name is enabled, false otherwise.\n\t*\n\t* @param {String} name\n\t* @return {Boolean}\n\t* @api public\n\t*/\n\tfunction enabled(name) {\n\t\tfor (const skip of createDebug.skips) {\n\t\t\tif (matchesTemplate(name, skip)) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\tfor (const ns of createDebug.names) {\n\t\t\tif (matchesTemplate(name, ns)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t/**\n\t* Coerce `val`.\n\t*\n\t* @param {Mixed} val\n\t* @return {Mixed}\n\t* @api private\n\t*/\n\tfunction coerce(val) {\n\t\tif (val instanceof Error) {\n\t\t\treturn val.stack || val.message;\n\t\t}\n\t\treturn val;\n\t}\n\n\t/**\n\t* XXX DO NOT USE. This is a temporary stub function.\n\t* XXX It WILL be removed in the next major release.\n\t*/\n\tfunction destroy() {\n\t\tconsole.warn('Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.');\n\t}\n\n\tcreateDebug.enable(createDebug.load());\n\n\treturn createDebug;\n}\n\nmodule.exports = setup;\n","/**\n * Helpers.\n */\n\nvar s = 1000;\nvar m = s * 60;\nvar h = m * 60;\nvar d = h * 24;\nvar w = d * 7;\nvar y = d * 365.25;\n\n/**\n * Parse or format the given `val`.\n *\n * Options:\n *\n * - `long` verbose formatting [false]\n *\n * @param {String|Number} val\n * @param {Object} [options]\n * @throws {Error} throw an error if val is not a non-empty string or a number\n * @return {String|Number}\n * @api public\n */\n\nmodule.exports = function (val, options) {\n options = options || {};\n var type = typeof val;\n if (type === 'string' && val.length > 0) {\n return parse(val);\n } else if (type === 'number' && isFinite(val)) {\n return options.long ? fmtLong(val) : fmtShort(val);\n }\n throw new Error(\n 'val is not a non-empty string or a valid number. val=' +\n JSON.stringify(val)\n );\n};\n\n/**\n * Parse the given `str` and return milliseconds.\n *\n * @param {String} str\n * @return {Number}\n * @api private\n */\n\nfunction parse(str) {\n str = String(str);\n if (str.length > 100) {\n return;\n }\n var match = /^(-?(?:\\d+)?\\.?\\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(\n str\n );\n if (!match) {\n return;\n }\n var n = parseFloat(match[1]);\n var type = (match[2] || 'ms').toLowerCase();\n switch (type) {\n case 'years':\n case 'year':\n case 'yrs':\n case 'yr':\n case 'y':\n return n * y;\n case 'weeks':\n case 'week':\n case 'w':\n return n * w;\n case 'days':\n case 'day':\n case 'd':\n return n * d;\n case 'hours':\n case 'hour':\n case 'hrs':\n case 'hr':\n case 'h':\n return n * h;\n case 'minutes':\n case 'minute':\n case 'mins':\n case 'min':\n case 'm':\n return n * m;\n case 'seconds':\n case 'second':\n case 'secs':\n case 'sec':\n case 's':\n return n * s;\n case 'milliseconds':\n case 'millisecond':\n case 'msecs':\n case 'msec':\n case 'ms':\n return n;\n default:\n return undefined;\n }\n}\n\n/**\n * Short format for `ms`.\n *\n * @param {Number} ms\n * @return {String}\n * @api private\n */\n\nfunction fmtShort(ms) {\n var msAbs = Math.abs(ms);\n if (msAbs >= d) {\n return Math.round(ms / d) + 'd';\n }\n if (msAbs >= h) {\n return Math.round(ms / h) + 'h';\n }\n if (msAbs >= m) {\n return Math.round(ms / m) + 'm';\n }\n if (msAbs >= s) {\n return Math.round(ms / s) + 's';\n }\n return ms + 'ms';\n}\n\n/**\n * Long format for `ms`.\n *\n * @param {Number} ms\n * @return {String}\n * @api private\n */\n\nfunction fmtLong(ms) {\n var msAbs = Math.abs(ms);\n if (msAbs >= d) {\n return plural(ms, msAbs, d, 'day');\n }\n if (msAbs >= h) {\n return plural(ms, msAbs, h, 'hour');\n }\n if (msAbs >= m) {\n return plural(ms, msAbs, m, 'minute');\n }\n if (msAbs >= s) {\n return plural(ms, msAbs, s, 'second');\n }\n return ms + ' ms';\n}\n\n/**\n * Pluralization helper.\n */\n\nfunction plural(ms, msAbs, n, name) {\n var isPlural = msAbs >= n * 1.5;\n return Math.round(ms / n) + ' ' + name + (isPlural ? 's' : '');\n}\n","import debugIt from 'debug'\nimport type {Middleware} from 'get-it'\n\nconst SENSITIVE_HEADERS = ['cookie', 'authorization']\n\nconst hasOwn = Object.prototype.hasOwnProperty\nconst redactKeys = (source: any, redacted: any) => {\n const target: any = {}\n for (const key in source) {\n if (hasOwn.call(source, key)) {\n target[key] = redacted.indexOf(key.toLowerCase()) > -1 ? '<redacted>' : source[key]\n }\n }\n return target\n}\n\n/** @public */\nexport function debug(opts: any = {}) {\n const verbose = opts.verbose\n const namespace = opts.namespace || 'get-it'\n const defaultLogger = debugIt(namespace)\n const log = opts.log || defaultLogger\n const shortCircuit = log === defaultLogger && !debugIt.enabled(namespace)\n let requestId = 0\n\n return {\n processOptions: (options) => {\n options.debug = log\n options.requestId = options.requestId || ++requestId\n return options\n },\n\n onRequest: (event) => {\n // Short-circuit if not enabled, to save some CPU cycles with formatting stuff\n if (shortCircuit || !event) {\n return event\n }\n\n const options = event.options\n\n log('[%s] HTTP %s %s', options.requestId, options.method, options.url)\n\n if (verbose && options.body && typeof options.body === 'string') {\n log('[%s] Request body: %s', options.requestId, options.body)\n }\n\n if (verbose && options.headers) {\n const headers =\n opts.redactSensitiveHeaders === false\n ? options.headers\n : redactKeys(options.headers, SENSITIVE_HEADERS)\n\n log('[%s] Request headers: %s', options.requestId, JSON.stringify(headers, null, 2))\n }\n\n return event\n },\n\n onResponse: (res, context) => {\n // Short-circuit if not enabled, to save some CPU cycles with formatting stuff\n if (shortCircuit || !res) {\n return res\n }\n\n const reqId = context.options.requestId\n\n log('[%s] Response code: %s %s', reqId, res.statusCode, res.statusMessage)\n\n if (verbose && res.body) {\n log('[%s] Response body: %s', reqId, stringifyBody(res))\n }\n\n return res\n },\n\n onError: (err, context) => {\n const reqId = context.options.requestId\n if (!err) {\n log('[%s] Error encountered, but handled by an earlier middleware', reqId)\n return err\n }\n\n log('[%s] ERROR: %s', reqId, err.message)\n return err\n },\n } satisfies Middleware\n}\n\nfunction stringifyBody(res: any) {\n const contentType = (res.headers['content-type'] || '').toLowerCase()\n const isJson = contentType.indexOf('application/json') !== -1\n return isJson ? tryFormat(res.body) : res.body\n}\n\n// Attempt pretty-formatting JSON\nfunction tryFormat(body: any) {\n try {\n const parsed = typeof body === 'string' ? JSON.parse(body) : body\n return JSON.stringify(parsed, null, 2)\n } catch {\n return body\n }\n}\n","import type {Middleware} from 'get-it'\n\nclass HttpError extends Error {\n response: any\n request: any\n constructor(res: any, ctx: any) {\n super()\n const truncatedUrl = res.url.length > 400 ? `${res.url.slice(0, 399)}…` : res.url\n let msg = `${res.method}-request to ${truncatedUrl} resulted in `\n msg += `HTTP ${res.statusCode} ${res.statusMessage}`\n\n this.message = msg.trim()\n this.response = res\n this.request = ctx.options\n }\n}\n\n/** @public */\nexport function httpErrors() {\n return {\n onResponse: (res, ctx) => {\n const isHttpError = res.statusCode >= 400\n if (!isHttpError) {\n return res\n }\n\n throw new HttpError(res, ctx)\n },\n } satisfies Middleware\n}\n","export const isBuffer =\n typeof Buffer === 'undefined' ? () => false : (obj: unknown) => Buffer.isBuffer(obj)\n","/*!\n * is-plain-object <https://github.com/jonschlinkert/is-plain-object>\n *\n * Copyright (c) 2014-2017, Jon Schlinkert.\n * Released under the MIT License.\n */\n\nfunction isObject(o: unknown): o is Record<string, unknown> {\n return Object.prototype.toString.call(o) === '[object Object]'\n}\n\nexport function isPlainObject(o: unknown): boolean {\n if (isObject(o) === false) return false\n\n // If has modified constructor\n const ctor = o.constructor\n if (ctor === undefined) return true\n\n // If has modified prototype\n const prot = ctor.prototype\n if (isObject(prot) === false) return false\n\n // If constructor does not have an Object-specific method\n if (\n // eslint-disable-next-line no-prototype-builtins\n prot.hasOwnProperty('isPrototypeOf') === false\n ) {\n return false\n }\n\n // Most likely a plain Object\n return true\n}\n","import type {Middleware} from 'get-it'\n\nimport {isBuffer} from '../util/isBuffer'\nimport {isPlainObject} from '../util/isPlainObject'\n\nconst serializeTypes = ['boolean', 'string', 'number']\n\n/** @public */\nexport function jsonRequest() {\n return {\n processOptions: (options) => {\n const body = options.body\n if (!body) {\n return options\n }\n\n const isStream = typeof body.pipe === 'function'\n const shouldSerialize =\n !isStream &&\n !isBuffer(body) &&\n (serializeTypes.indexOf(typeof body) !== -1 || Array.isArray(body) || isPlainObject(body))\n\n if (!shouldSerialize) {\n return options\n }\n\n return Object.assign({}, options, {\n body: JSON.stringify(options.body),\n headers: Object.assign({}, options.headers, {\n 'Content-Type': 'application/json',\n }),\n })\n },\n } satisfies Middleware\n}\n","let actualGlobal = {} as typeof globalThis\n\nif (typeof globalThis !== 'undefined') {\n actualGlobal = globalThis\n} else if (typeof window !== 'undefined') {\n actualGlobal = window\n} else if (typeof global !== 'undefined') {\n actualGlobal = global\n} else if (typeof self !== 'undefined') {\n actualGlobal = self\n}\n\nexport default actualGlobal\n","import type {Middleware} from 'get-it'\n\n/** @public */\nexport const promise = (\n options: {onlyBody?: boolean; implementation?: PromiseConstructor} = {},\n) => {\n const PromiseImplementation = options.implementation || Promise\n if (!PromiseImplementation) {\n throw new Error('`Promise` is not available in global scope, and no implementation was passed')\n }\n\n return {\n onReturn: (channels, context) =>\n new PromiseImplementation((resolve, reject) => {\n const cancel = context.options.cancelToken\n if (cancel) {\n cancel.promise.then((reason: any) => {\n channels.abort.publish(reason)\n reject(reason)\n })\n }\n\n channels.error.subscribe(reject)\n channels.response.subscribe((response) => {\n resolve(options.onlyBody ? (response as any).body : response)\n })\n\n // Wait until next tick in case cancel has been performed\n setTimeout(() => {\n try {\n channels.request.publish(context)\n } catch (err) {\n reject(err)\n }\n }, 0)\n }),\n } satisfies Middleware\n}\n\n/**\n * The cancel token API is based on the [cancelable promises proposal](https://github.com/tc39/proposal-cancelable-promises), which is currently at Stage 1.\n *\n * Code shamelessly stolen/borrowed from MIT-licensed [axios](https://github.com/mzabriskie/axios). Thanks to [Nick Uraltsev](https://github.com/nickuraltsev), [Matt Zabriskie](https://github.com/mzabriskie) and the other contributors of that project!\n */\n/** @public */\nexport class Cancel {\n __CANCEL__ = true\n\n message: string | undefined\n\n constructor(message: string | undefined) {\n this.message = message\n }\n\n toString() {\n return `Cancel${this.message ? `: ${this.message}` : ''}`\n }\n}\n\n/** @public */\nexport class CancelToken {\n promise: Promise<any>\n reason?: Cancel\n\n constructor(executor: (cb: (message?: string) => void) => void) {\n if (typeof executor !== 'function') {\n throw new TypeError('executor must be a function.')\n }\n\n let resolvePromise: any = null\n\n this.promise = new Promise((resolve) => {\n resolvePromise = resolve\n })\n\n executor((message?: string) => {\n if (this.reason) {\n // Cancellation has already been requested\n return\n }\n\n this.reason = new Cancel(message)\n resolvePromise(this.reason)\n })\n }\n\n static source = () => {\n let cancel: (message?: string) => void\n const token = new CancelToken((can) => {\n cancel = can\n })\n\n return {\n token: token,\n cancel: cancel!,\n }\n }\n}\n\nconst isCancel = (value: any): value is Cancel => !!(value && value?.__CANCEL__)\n\npromise.Cancel = Cancel\npromise.CancelToken = CancelToken\npromise.isCancel = isCancel\n","export default (err: any, _attempt: any, options: any) => {\n if (options.method !== 'GET' && options.method !== 'HEAD') {\n return false\n }\n\n return err.isNetworkError || false\n}\n","import type {Middleware, RetryOptions} from 'get-it'\n\nconst isStream = (stream: any) =>\n stream !== null && typeof stream === 'object' && typeof stream.pipe === 'function'\n\n/** @public */\nexport default (opts: RetryOptions) => {\n const maxRetries = opts.maxRetries || 5\n const retryDelay = opts.retryDelay || getRetryDelay\n const allowRetry = opts.shouldRetry\n\n return {\n onError: (err, context) => {\n const options = context.options\n const max = options.maxRetries || maxRetries\n const delay = options.retryDelay || retryDelay\n const shouldRetry = options.shouldRetry || allowRetry\n const attemptNumber = options.attemptNumber || 0\n\n // We can't retry if body is a stream, since it'll be drained\n if (isStream(options.body)) {\n return err\n }\n\n // Give up?\n if (!shouldRetry(err, attemptNumber, options) || attemptNumber >= max) {\n return err\n }\n\n // Create a new context with an increased attempt number, so we can exit if we reach a limit\n const newContext = Object.assign({}, context, {\n options: Object.assign({}, options, {attemptNumber: attemptNumber + 1}),\n })\n\n // Wait a given amount of time before doing the request again\n setTimeout(() => context.channels.request.publish(newContext), delay(attemptNumber))\n\n // Signal that we've handled the error and that it should not propagate further\n return null\n },\n } satisfies Middleware\n}\n\nfunction getRetryDelay(attemptNum: number) {\n return 100 * Math.pow(2, attemptNum) + Math.random() * 100\n}\n","import type {RetryOptions} from 'get-it'\n\nimport defaultShouldRetry from '../../util/browser-shouldRetry'\nimport sharedRetry from './shared-retry'\n\n/** @public */\nexport const retry = (opts: Partial<RetryOptions> = {}) =>\n sharedRetry({shouldRetry: defaultShouldRetry, ...opts})\n\nretry.shouldRetry = defaultShouldRetry\n","import type {Middleware} from 'get-it'\n\nimport {isBuffer} from '../util/isBuffer'\nimport {isPlainObject} from '../util/isPlainObject'\n\nfunction encode(data: Record<string, string | Set<number | string>>): string {\n const query = new URLSearchParams()\n\n const nest = (name: string, _value: unknown) => {\n const value = _value instanceof Set ? Array.from(_value) : _value\n if (Array.isArray(value)) {\n if (value.length) {\n for (const index in value) {\n nest(`${name}[${index}]`, value[index])\n }\n } else {\n query.append(`${name}[]`, '')\n }\n } else if (typeof value === 'object' && value !== null) {\n for (const [key, obj] of Object.entries(value)) {\n nest(`${name}[${key}]`, obj)\n }\n } else {\n query.append(name, value as string)\n }\n }\n\n for (const [key, value] of Object.entries(data)) {\n nest(key, value)\n }\n\n return query.toString()\n}\n\n/** @public */\nexport function urlEncoded() {\n return {\n processOptions: (options) => {\n const body = options.body\n if (!body) {\n return options\n }\n\n const isStream = typeof body.pipe === 'function'\n const shouldSerialize = !isStream && !isBuffer(body) && isPlainObject(body)\n\n if (!shouldSerialize) {\n return options\n }\n\n return {\n ...options,\n body: encode(options.body),\n headers: {\n ...options.headers,\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n }\n },\n } satisfies Middleware\n}\n","import decompressResponse from 'decompress-response'\nimport follow, {type FollowResponse, type RedirectableRequest} from 'follow-redirects'\nimport type {FinalizeNodeOptionsPayload, HttpRequest, MiddlewareResponse} from 'get-it'\nimport http from 'http'\nimport https from 'https'\nimport qs from 'querystring'\nimport {Readable, type Stream} from 'stream'\nimport url from 'url'\n\nimport {lowerCaseHeaders} from '../util/lowerCaseHeaders'\nimport {progressStream} from '../util/progress-stream'\nimport {getProxyOptions, rewriteUriForProxy} from './node/proxy'\nimport {concat} from './node/simpleConcat'\nimport {timedOut} from './node/timedOut'\nimport * as tunneling from './node/tunnel'\nimport type {RequestAdapter} from '../types'\n\n/**\n * Taken from:\n * https://github.com/sindresorhus/is-stream/blob/fb8caed475b4107cee3c22be3252a904020eb2d4/index.js#L3-L6\n */\nconst isStream = (stream: any): stream is Stream =>\n stream !== null && typeof stream === 'object' && typeof stream.pipe === 'function'\n\n/** @public */\nexport const adapter: RequestAdapter = 'node'\n\nexport class NodeRequestError extends Error {\n request: http.ClientRequest\n code?: string | undefined\n\n constructor(err: NodeJS.ErrnoException, req: any) {\n super(err.message)\n this.request = req\n this.code = err.code\n }\n}\n\n// Reduce a fully fledged node-style response object to\n// something that works in both browser and node environment\nconst reduceResponse = (\n res: any,\n reqUrl: string,\n method: string,\n body: any,\n): MiddlewareResponse => ({\n body,\n url: reqUrl,\n method: method,\n headers: res.headers,\n statusCode: res.statusCode,\n statusMessage: res.statusMessage,\n})\n\nexport const httpRequester: HttpRequest = (context, cb) => {\n const {options} = context\n const uri = Object.assign({}, url.parse(options.url))\n\n if (typeof fetch === 'function' && options.fetch) {\n const controller = new AbortController()\n const reqOpts = context.applyMiddleware('finalizeOptions', {\n ...uri,\n method: options.method,\n headers: {\n ...(typeof options.fetch === 'object' && options.fetch.headers\n ? lowerCaseHeaders(options.fetch.headers)\n : {}),\n ...lowerCaseHeaders(options.headers),\n },\n maxRedirects: options.maxRedirects,\n }) as FinalizeNodeOptionsPayload\n const fetchOpts = {\n credentials: options.withCredentials ? 'include' : 'omit',\n ...(typeof options.fetch === 'object' ? options.fetch : {}),\n method: reqOpts.method,\n headers: reqOpts.headers,\n body: options.body,\n signal: controller.signal,\n } satisfies RequestInit\n\n // Allow middleware to inject a response, for instance in the case of caching or mocking\n const injectedResponse = context.applyMiddleware('interceptRequest', undefined, {\n adapter,\n context,\n })\n\n // If middleware injected a response, treat it as we normally would and return it\n // Do note that the injected response has to be reduced to a cross-environment friendly response\n if (injectedResponse) {\n const cbTimer = setTimeout(cb, 0, null, injectedResponse)\n const cancel = () => clearTimeout(cbTimer)\n return {abort: cancel}\n }\n\n const request = fetch(options.url, fetchOpts)\n\n // Let middleware know we're about to do a request\n context.applyMiddleware('onRequest', {options, adapter, request, context})\n\n request\n .then(async (res) => {\n const body = options.rawBody ? res.body : await res.text()\n\n const headers = {} as Record<string, string>\n res.headers.forEach((value, key) => {\n headers[key] = value\n })\n\n cb(null, {\n body,\n url: res.url,\n method: options.method!,\n headers,\n statusCode: res.status,\n statusMessage: res.statusText,\n })\n })\n .catch((err) => {\n if (err.name == 'AbortError') return\n cb(err)\n })\n\n return {abort: () => controller.abort()}\n }\n\n const bodyType = isStream(options.body) ? 'stream' : typeof options.body\n if (\n bodyType !== 'undefined' &&\n bodyType !== 'stream' &&\n bodyType !== 'string' &&\n !Buffer.isBuffer(options.body)\n ) {\n throw new Error(`Request body must be a string, buffer or stream, got ${bodyType}`)\n }\n\n const lengthHeader: any = {}\n if (options.bodySize) {\n lengthHeader['content-length'] = options.bodySize\n } else if (options.body && bodyType !== 'stream') {\n lengthHeader['content-length'] = Buffer.byteLength(options.body)\n }\n\n // Make sure callback is not called in the event of a cancellation\n let aborted = false\n const callback = (err: Error | null, res?: MiddlewareResponse) => !aborted && cb(err, res)\n context.channels.abort.subscribe(() => {\n aborted = true\n })\n\n // Create a reduced subset of options meant for the http.request() method\n let reqOpts: any = Object.assign({}, uri, {\n method: options.method,\n headers: Object.assign({}, lowerCaseHeaders(options.headers), lengthHeader),\n maxRedirects: options.maxRedirects,\n })\n\n // Figure out proxying/tunnel options\n const proxy = getProxyOptions(options)\n const tunnel = proxy && tunneling.shouldEnable(options)\n\n // Allow middleware to inject a response, for instance in the case of caching or mocking\n const injectedResponse = context.applyMiddleware('interceptRequest', undefined, {\n adapter,\n context,\n })\n\n // If middleware injected a response, treat it as we normally would and return it\n // Do note that the injected response has to be reduced to a cross-environment friendly response\n if (injectedResponse) {\n const cbTimer = setImmediate(callback, null, injectedResponse)\n const abort = () => clearImmediate(cbTimer)\n return {abort}\n }\n\n // We're using the follow-redirects module to transparently follow redirects\n if (options.maxRedirects !== 0) {\n reqOpts.maxRedirects = options.maxRedirects || 5\n }\n\n // Apply currect options for proxy tunneling, if enabled\n if (proxy && tunnel) {\n reqOpts = tunneling.applyAgent(reqOpts, proxy)\n } else if (proxy && !tunnel) {\n reqOpts = rewriteUriForProxy(reqOpts, uri, proxy)\n }\n\n // Handle proxy authorization if present\n if (!tunnel && proxy && proxy.auth && !reqOpts.headers['proxy-authorization']) {\n const [username, password] =\n typeof proxy.auth === 'string'\n ? proxy.auth.split(':').map((item) => qs.unescape(item))\n : [proxy.auth.username, proxy.auth.password]\n\n const auth = Buffer.from(`${username}:${password}`, 'utf8')\n const authBase64 = auth.toString('base64')\n reqOpts.headers['proxy-authorization'] = `Basic ${authBase64}`\n }\n\n // Figure out transport (http/https, forwarding/non-forwarding agent)\n const transport = getRequestTransport(reqOpts, proxy, tunnel)\n if (typeof options.debug === 'function' && proxy) {\n options.debug(\n 'Proxying using %s',\n reqOpts.agent ? 'tunnel agent' : `${reqOpts.host}:${reqOpts.port}`,\n )\n }\n\n // See if we should try to request a compressed response (and decompress on return)\n const tryCompressed = reqOpts.method !== 'HEAD'\n if (tryCompressed && !reqOpts.headers['accept-encoding'] && options.compress !== false) {\n reqOpts.headers['accept-encoding'] =\n // Workaround Bun not supporting brotli: https://github.com/oven-sh/bun/issues/267\n typeof Bun !== 'undefined' ? 'gzip, deflate' : 'br, gzip, deflate'\n }\n\n let _res: http.IncomingMessage | undefined\n const finalOptions = context.applyMiddleware(\n 'finalizeOptions',\n reqOpts,\n ) as FinalizeNodeOptionsPayload\n const request = transport.request(finalOptions, (response) => {\n const res = tryCompressed ? decompressResponse(response) : response\n _res = res\n const resStream = context.applyMiddleware('onHeaders', res, {\n headers: response.headers,\n adapter,\n context,\n })\n\n // On redirects, `responseUrl` is set\n const reqUrl = 'responseUrl' in response ? response.responseUrl : options.url\n\n if (options.stream) {\n callback(null, reduceResponse(res, reqUrl, reqOpts.method, resStream))\n return\n }\n\n // Concatenate the response body, then parse the response with middlewares\n concat(resStream, (err: any, data: any) => {\n if (err) {\n return callback(err)\n }\n\n const body = options.rawBody ? data : data.toString()\n const reduced = reduceResponse(res, reqUrl, reqOpts.method, body)\n return callback(null, reduced)\n })\n })\n\n function onError(err: NodeJS.ErrnoException) {\n // HACK: If we have a socket error, and response has already been assigned this means\n // that a response has already been sent. According to node.js docs, this is\n // will result in the response erroring with an error code of 'ECONNRESET'.\n // We first destroy the response, then the request, with the same error. This way the\n // error is forwarded to both the response and the request.\n // See the event order outlined here https://nodejs.org/api/http.html#httprequesturl-options-callback for how node.js handles the different scenarios.\n if (_res) _res.destroy(err)\n request.destroy(err)\n }\n\n request.once('socket', (socket: NodeJS.Socket) => {\n socket.once('error', onError)\n request.once('response', (response) => {\n response.once('end', () => {\n socket.removeListener('error', onError)\n })\n })\n })\n\n request.once('error', (err: NodeJS.ErrnoException) => {\n if (_res) return\n // The callback has already been invoked. Any error should be sent to the response.\n callback(new NodeRequestError(err, request))\n })\n\n if (options.timeout) {\n timedOut(request, options.timeout)\n }\n\n // Cheating a bit here; since we're not concerned about the \"bundle size\" in node,\n // and modifying the body stream would be sorta tricky, we're just always going\n // to put a progress stream in the middle here.\n const {bodyStream, progress} = getProgressStream(options)\n\n // Let middleware know we're about to do a request\n context.applyMiddleware('onRequest', {options, adapter, request, context, progress})\n\n if (bodyStream) {\n bodyStream.pipe(request)\n } else {\n request.end(options.body)\n }\n\n return {abort: () => request.abort()}\n}\n\nfunction getProgressStream(options: any) {\n if (!options.body) {\n return {}\n }\n\n const bodyIsStream = isStream(options.body)\n const length = options.bodySize || (bodyIsStream ? null : Buffer.byteLength(options.body))\n if (!length) {\n return bodyIsStream ? {bodyStream: options.body} : {}\n }\n\n const progress = progressStream({time: 32, length})\n const bodyStream = bodyIsStream ? options.body : Readable.from(options.body)\n return {bodyStream: bodyStream.pipe(progress), progress}\n}\n\nfunction getRequestTransport(\n reqOpts: any,\n proxy: any,\n tunnel: any,\n): {\n request: (\n options: any,\n callback: (response: http.IncomingMessage | (http.IncomingMessage & FollowResponse)) => void,\n ) => http.ClientRequest | RedirectableRequest<http.ClientRequest, http.IncomingMessage>\n} {\n const isHttpsRequest = reqOpts.protocol === 'https:'\n const transports =\n reqOpts.maxRedirects === 0\n ? {http: http, https: https}\n : {http: follow.http, https: follow.https}\n\n if (!proxy || tunnel) {\n return isHttpsRequest ? transports.https : transports.http\n }\n\n // Assume the proxy is an HTTPS proxy if port is 443, or if there is a\n // `protocol` option set that starts with https\n let isHttpsProxy = proxy.port === 443\n if (proxy.protocol) {\n isHttpsProxy = /^https:?/.test(proxy.protocol)\n }\n\n return isHttpsProxy ? transports.https : transports.http\n}\n","export * from './middleware/agent/browser-agent'\nexport * from './middleware/base'\nexport * from './middleware/debug'\nexport * from './middleware/defaultOptionsProcessor'\nexport * from './middleware/defaultOptionsValidator'\nexport * from './middleware/headers'\nexport * from './middleware/httpErrors'\nexport * from './middleware/injectResponse'\nexport * from './middleware/jsonRequest'\nexport * from './middleware/jsonResponse'\nexport * from './middleware/mtls'\nexport * from './middleware/observable'\nexport * from './middleware/progress/browser-progress'\nexport * from './middleware/promise'\nexport * from './middleware/proxy'\nexport * from './middleware/retry/browser-retry'\nexport * from './middleware/urlEncoded'\n\nimport {agent} from './middleware/agent/browser-agent'\nimport {buildKeepAlive} from './middleware/keepAlive'\n/** @public */\nexport const keepAlive = buildKeepAlive(agent)\n","import type {AgentOptions} from 'http'\nimport type {Middleware} from 'get-it'\n\nimport {NodeRequestError} from '../request/node-request'\n\ntype KeepAliveOptions = {\n ms?: number\n maxFree?: number\n\n /**\n How many times to retry in case of ECONNRESET error. Default: 3\n */\n maxRetries?: number\n}\n\nexport function buildKeepAlive(agent: (opts: AgentOptions) => Pick<Middleware, 'finalizeOptions'>) {\n return function keepAlive(config: KeepAliveOptions = {}): any {\n const {maxRetries = 3, ms = 1000, maxFree = 256} = config\n\n const {finalizeOptions} = agent({\n keepAlive: true,\n keepAliveMsecs: ms,\n maxFreeSockets: maxFree,\n })\n\n return {\n finalizeOptions,\n onError: (err, context) => {\n // When sending request through a keep-alive enabled agent, the underlying socket might be reused. But if server closes connection at unfortunate time, client may run into a 'ECONNRESET' error.\n // We retry three times in case of ECONNRESET error.\n // https://nodejs.org/docs/latest-v20.x/api/http.html#requestreusedsocket\n if (\n (context.options.method === 'GET' || context.options.method === 'POST') &&\n err instanceof NodeRequestError &&\n err.code === 'ECONNRESET' &&\n err.request.reusedSocket\n ) {\n const attemptNumber = context.options.attemptNumber || 0\n if (attemptNumber < maxRetries) {\n // Create a new context with an increased attempt number, so we can exit if we reach a limit\n const newContext = Object.assign({}, context, {\n options: Object.assign({}, context.options, {attemptNumber: attemptNumber + 1}),\n })\n // If this is a reused socket we retry immediately\n setImmediate(() => context.channels.request.publish(newContext))\n\n return null\n }\n }\n\n return err\n },\n } satisfies Middleware\n }\n}\n","import type {Middleware} from 'get-it'\n\n/** @public */\nexport function headers(_headers: any, opts: any = {}) {\n return {\n processOptions: (options) => {\n const existing = options.headers || {}\n options.headers = opts.override\n ? Object.assign({}, existing, _headers)\n : Object.assign({}, _headers, existing)\n\n return options\n },\n } satisfies Middleware\n}\n","import type {Middleware, MiddlewareHooks, MiddlewareResponse} from 'get-it'\n\n/** @public */\nexport function injectResponse(\n opts: {\n inject: (\n event: Parameters<MiddlewareHooks['interceptRequest']>[1],\n prevValue: Parameters<MiddlewareHooks['interceptRequest']>[0],\n ) => Partial<MiddlewareResponse | undefined | void>\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n } = {} as any,\n) {\n if (typeof opts.inject !== 'function') {\n throw new Error('`injectResponse` middleware requires a `inject` function')\n }\n\n const inject = function inject(prevValue, event) {\n const response = opts.inject(event, prevValue)\n if (!response) {\n return prevValue\n }\n\n // Merge defaults so we don't have to provide the most basic of details unless we want to\n const options = event.context.options\n return {\n body: '',\n url: options.url,\n method: options.method!,\n headers: {},\n statusCode: 200,\n statusMessage: 'OK',\n ...response,\n } satisfies MiddlewareResponse\n } satisfies Middleware['interceptRequest']\n\n return {interceptRequest: inject} satisfies Middleware\n}\n","import type {Middleware} from 'get-it'\n\n/** @public */\nexport function jsonResponse(opts?: any) {\n return {\n onResponse: (response) => {\n const contentType = response.headers['content-type'] || ''\n const shouldDecode = (opts && opts.force) || contentType.indexOf('application/json') !== -1\n if (!response.body || !contentType || !shouldDecode) {\n return response\n }\n\n return Object.assign({}, response, {body: tryParse(response.body)})\n },\n\n processOptions: (options) =>\n Object.assign({}, options, {\n headers: Object.assign({Accept: 'application/json'}, options.headers),\n }),\n } satisfies Middleware\n\n function tryParse(body: any) {\n try {\n return JSON.parse(body)\n } catch (err: any) {\n err.message = `Failed to parsed response body as JSON: ${err.message}`\n throw err\n }\n }\n}\n","import type {Middleware} from 'get-it'\n\nimport {isBrowserOptions} from '../util/isBrowserOptions'\n\n/** @public */\nexport function mtls(config: any = {}) {\n if (!config.ca) {\n throw new Error('Required mtls option \"ca\" is missing')\n }\n if (!config.cert) {\n throw new Error('Required mtls option \"cert\" is missing')\n }\n if (!config.key) {\n throw new Error('Required mtls option \"key\" is missing')\n }\n\n return {\n finalizeOptions: (options) => {\n if (isBrowserOptions(options)) {\n return options\n }\n\n const mtlsOpts = {\n cert: config.cert,\n key: config.key,